blob: a6e015877ed4410d1b8c58d2aef3d465b407ed3a [file] [log] [blame]
// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import 'package:collection/collection.dart';
extension IterableExtension<E> on Iterable<E> {
/// Note, elements must be unique.
Map<E, int> get asElementToIndexMap {
return {
for (var (index, element) in indexed) element: index,
};
}
/// Returns the fixed-length [List] with elements of `this`.
List<E> toFixedList() {
if (isEmpty) {
return const <Never>[];
}
return toList(growable: false);
}
Iterable<E> whereNotType<U>() {
return whereNot((element) => element is U);
}
}
extension IterableIterableExtension<T> on Iterable<Iterable<T>> {
/// Elements of each iterable in this iterable.
///
/// At the moment of writing, this method is `2.75` times faster than
/// `expand((e) => e)`, and `3.5` faster than `flattened` from
/// `package:collection`.
List<T> get flattenedToList2 {
return [
for (var elements in this) ...elements,
];
}
/// Elements of each iterable in this iterable.
Set<T> get flattenedToSet2 {
return {
for (var elements in this) ...elements,
};
}
}
extension IterableMapEntryExtension<K, V> on Iterable<MapEntry<K, V>> {
Map<K, V> get mapFromEntries => Map.fromEntries(this);
}
extension ListExtension<E> on List<E> {
Iterable<E> get withoutLast {
var length = this.length;
return length > 0 ? take(length - 1) : Iterable.empty();
}
void addIfNotNull(E? element) {
if (element != null) {
add(element);
}
}
/// Returns the element at [index].
///
/// Returns `null`, if [index] is negative or greater than the length.
E? elementAtOrNull2(int index) {
if (0 <= index && index < length) {
return this[index];
} else {
return null;
}
}
bool endsWith(List<E> expected) {
var thisIndex = length - expected.length;
if (thisIndex < 0) {
return false;
}
var expectedIndex = 0;
for (; expectedIndex < expected.length;) {
if (this[thisIndex++] != expected[expectedIndex++]) {
return false;
}
}
return true;
}
E? nextOrNull(E element) {
var index = indexOf(element);
if (index >= 0 && index < length - 1) {
return this[index + 1];
} else {
return null;
}
}
E? removeLastOrNull() {
if (isNotEmpty) {
return removeLast();
}
return null;
}
/// Returns a new list with all elements of the target, arranged such that
/// all elements for which the [predicate] specified returns `true` come
/// before those for which the [predicate] returns `false`. The partitioning
/// is stable, i.e. the relative ordering of the elements is preserved.
List<E> stablePartition(bool Function(E element) predicate) {
return [
...where(predicate),
...whereNot(predicate),
];
}
}
extension ListQueueExtension<T> on ListQueue<T> {
T? removeFirstOrNull() {
return isNotEmpty ? removeFirst() : null;
}
}
extension MapExtension<K, V> on Map<K, V> {
K? get firstKey {
return keys.firstOrNull;
}
}
extension MapOfListExtension<K, V> on Map<K, List<V>> {
void add(K key, V value) {
(this[key] ??= []).add(value);
}
/// Ensure that [key] is present in the target, maybe with the empty list.
void addKey(K key) {
this[key] ??= [];
}
}
extension SetExtension<E> on Set<E> {
void addIfNotNull(E? element) {
if (element != null) {
add(element);
}
}
}