typedef import(K, V); from collections.genericpair(K=K, V=V) access Pair_K_V; from collections.iter(T=K) access Iter_T as Iter_K, Iterable_T as Iterable_K; from collections.iter(T=Pair_K_V) access Iter_T as Iter_K_V, Iterable_T as Iterable_K_V; struct Map_K_V { restricted V nullValue; restricted bool isNullValue(V) = null; void operator init() {} void operator init(V nullValue, bool isNullValue(V) = new bool(V v) { return v == nullValue; } ) { this.nullValue = nullValue; this.isNullValue = isNullValue; assert(isNullValue(nullValue), 'nullValue must satisfy isNullValue'); } // Remaining methods are not implemented here. int size(); bool empty() { return size() == 0; } bool contains(K key); // If the key was not present already, returns nullValue, or throws error // if nullValue was never set. V operator [] (K key); // Adds the key-value pair, replacing both the key and value if the key was // already present. void operator [=] (K key, V value); // Removes the entry with the given key, if it exists. Throws error if the // key was not present. void delete(K key); Iter_K operator iter(); Iterable_K_V pairs() { Iter_K_V iter() { Iter_K iterK = this.operator iter(); Iter_K_V result; result.valid = iterK.valid; result.get = new Pair_K_V() { K k = iterK.get(); return Pair_K_V(k, this[k]); }; result.advance = iterK.advance; return result; } return Iterable(iter); } // Returns a random, uniformly distributed key from the map. The default // implementation is O(n) in the number of keys. Intended primarily for // testing purposes. K randomKey() { int size = this.size(); if (size == 0) { assert(false, 'Cannot get a random key from an empty map'); } int index = rand(0, size - 1); for (K key : this) { if (index == 0) { return key; } --index; } assert(false, 'Unreachable code'); K unused; return unused; } autounravel Iterable_K operator cast(Map_K_V map) { return Iterable_K(map.operator iter); } K[] keys() { K[] result; for (K key : this) { result.push(key); } return result; } void add(Iterable_K_V other) { for (Pair_K_V kv : other) { this[kv.k] = kv.v; } } } // Reference implementation for testing purposes. struct NaiveMap_K_V { private K[] keys; private V[] values; private int size; private int numChanges = 0; restricted Map_K_V map; void operator init() { keys = new K[0]; values = new V[0]; size = 0; using F = void(); ((F)map.operator init)(); } void operator init(V keyword nullValue, bool keyword isNullValue(V) = null) { keys = new K[0]; values = new V[0]; size = 0; if (isNullValue == null) { // Let operator init supply its own default. map.operator init(nullValue); } else { map.operator init(nullValue, isNullValue); } } map.size = new int() { return size; }; map.contains = new bool(K key) { for (int i = 0; i < size; ++i) { if (keys[i] == key) { return true; } } return false; }; map.operator[] = new V(K key) { for (int i = 0; i < size; ++i) { if (keys[i] == key) { return values[i]; } } assert(map.isNullValue != null, 'Key not found in map'); return map.nullValue; }; map.operator[=] = new void(K key, V value) { bool delete = false; if (map.isNullValue != null && map.isNullValue(value)) { delete = true; } for (int i = 0; i < size; ++i) { if (keys[i] == key) { if (delete) { keys.delete(i); values.delete(i); ++numChanges; --size; } else { keys[i] = key; values[i] = value; } return; } } if (!delete) { keys.push(key); values.push(value); ++numChanges; ++size; } }; map.delete = new void(K key) { ++numChanges; for (int i = 0; i < size; ++i) { if (keys[i] == key) { keys.delete(i); values.delete(i); --size; return; } } assert(false, 'Nonexistent key cannot be deleted'); }; map.operator iter = new Iter_K() { int numChangesAtStart = numChanges; int i = 0; Iter_K result; result.valid = new bool() { assert(numChanges == numChangesAtStart, 'Map keys changed during iteration'); return i < size; }; result.advance = new void() { assert(numChanges == numChangesAtStart, 'Map keys changed during iteration'); ++i; }; result.get = new K() { assert(numChanges == numChangesAtStart, 'Map keys changed during iteration'); return keys[i]; }; return result; }; autounravel Iterable_K operator cast(NaiveMap_K_V map) { return Iterable_K(map.map.operator iter); } autounravel Map_K_V operator cast(NaiveMap_K_V map) { return map.map; } from map unravel *; }