blob: db94f02395a2117878960146db6af3e9d84934d5 [file] [log] [blame]
// Copyright (c) 2012, 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.
library util;
/**
* An abstract map implementation. This class can be used as a superclass for
* implementing maps, requiring only the further implementation of the
* [:operator []:], [:forEach:] and [:length:] methods to provide a fully
* implemented immutable map.
*/
abstract class AbstractMap<K, V> implements Map<K, V> {
AbstractMap();
AbstractMap.from(Map<K, V> other) {
other.forEach((k,v) => this[k] = v);
}
void operator []=(K key, value) {
throw new UnsupportedError('[]= is not supported');
}
void clear() {
throw new UnsupportedError('clear() is not supported');
}
void addAll(Map<K, V> other) {
throw new UnsupportedError('addAll() is not supported');
}
bool containsKey(K key) {
var found = false;
forEach((k,_) {
if (k == key) {
found = true;
}
});
return found;
}
bool containsValue(V value) {
var found = false;
forEach((_,v) {
if (v == value) {
found = true;
}
});
return found;
}
Iterable<K> get keys {
var keys = <K>[];
forEach((k,_) => keys.add(k));
return keys;
}
Iterable<V> get values {
var values = <V>[];
forEach((_,v) => values.add(v));
return values;
}
bool get isEmpty => length == 0;
bool get isNotEmpty => !isEmpty;
V putIfAbsent(K key, V ifAbsent()) {
if (!containsKey(key)) {
V value = this[key];
this[key] = ifAbsent();
return value;
}
return null;
}
V remove(K key) {
throw new UnsupportedError('V remove(K key) is not supported');
}
}
/**
* [ImmutableMapWrapper] wraps a (mutable) map as an immutable map where all
* mutating operations throw [UnsupportedError] upon invocation.
*/
class ImmutableMapWrapper<K, V> extends AbstractMap<K, V> {
final Map<K, V> _map;
ImmutableMapWrapper(this._map);
int get length => _map.length;
V operator [](K key) {
if (key is K) {
return _map[key];
}
return null;
}
void forEach(void f(K key, V value)) {
_map.forEach(f);
}
}
/**
* A [Filter] function returns [:true:] iff [value] should be included.
*/
typedef bool Filter<V>(V value);
/**
* An immutable map wrapper capable of filtering the input map.
*/
class FilteredImmutableMap<K, V> extends ImmutableMapWrapper<K, V> {
final Filter<V> _filter;
FilteredImmutableMap(Map<K, V> map, this._filter) : super(map);
int get length {
var count = 0;
forEach((k,v) {
count++;
});
return count;
}
void forEach(void f(K key, V value)) {
_map.forEach((K k, V v) {
if (_filter(v)) {
f(k, v);
}
});
}
}
/**
* An [AsFilter] takes a [value] of type [V1] and returns [value] iff it is of
* type [V2] or [:null:] otherwise. An [AsFilter] therefore behaves like the
* [:as:] expression.
*/
typedef V2 AsFilter<V1, V2>(V1 value);
/**
* An immutable map wrapper capable of filtering the input map based on types.
* It takes an [AsFilter] function which converts the original values of type
* [Vin] into values of type [Vout], or returns [:null:] if the value should
* not be included in the filtered map.
*/
class AsFilteredImmutableMap<K, Vin, Vout> extends AbstractMap<K, Vout> {
final Map<K, Vin> _map;
final AsFilter<Vin, Vout> _filter;
AsFilteredImmutableMap(this._map, this._filter);
int get length {
var count = 0;
forEach((k,v) {
count++;
});
return count;
}
Vout operator [](K key) {
if (key is K) {
Vin value = _map[key];
if (value != null) {
return _filter(value);
}
}
return null;
}
void forEach(void f(K key, Vout value)) {
_map.forEach((K k, Vin v) {
var value = _filter(v);
if (value != null) {
f(k, value);
}
});
}
}