range that iterates through the key-value-pairs of c in undefined order.
make range from l-value and r-value. element access is always const
1 version(showEntries) dbg(); 2 alias K = Nullable!(uint, uint.max); 3 alias X = OpenHashSet!(K, 4 FNV!(64, true), 5 defaultKeyEqualPredOf!K, 6 Mallocator.instance, 7 true); 8 9 auto k11 = K(11); 10 auto k22 = K(22); 11 auto k33 = K(33); 12 auto ks = [k11, k22, k33].s; 13 auto k44 = K(44); 14 15 // mutable 16 auto x = X.withElements(ks); 17 assert(!x.contains(k44)); 18 assert(!x.containsUsingLinearSearch(k44)); 19 assert(x.length == 3); 20 21 assert(x.byElement.count == x.length); 22 foreach (e; x.byElement) // from l-value 23 { 24 debug static assert(is(typeof(e) == const(K))); // always const access 25 26 // range invalidation forbidden: 27 debug 28 { 29 assertThrown!AssertError(x.reserveExtra(1)); // range invalidation 30 assertThrown!AssertError(x.clear()); // range invalidation 31 assertThrown!AssertError(x.insert(k11)); // range invalidation 32 assertThrown!AssertError(x.insertN([k11].s)); // range invalidation 33 assertThrown!AssertError(x.remove(k11)); // range invalidation 34 } 35 36 // allowed 37 assert(x.contains(e)); 38 assert(x.containsUsingLinearSearch(e)); 39 40 const eHit = e in x; 41 assert(eHit); // found 42 assert(*eHit is e); // and the value equals what we searched for 43 44 const eDup = x.dup; // duplication is `const` and allowed 45 } 46 47 // const 48 const y = X.withElements(ks); 49 assert(!x.contains(k44)); 50 assert(!x.containsUsingLinearSearch(k44)); 51 foreach (e; y.byElement) // from l-value 52 { 53 auto z = y.byElement; // ok to read-borrow again 54 assert(y.contains(e)); 55 assert(y.containsUsingLinearSearch(e)); 56 debug static assert(is(typeof(e) == const(K))); 57 } 58 59 foreach (e; X.withElements([K(11)].s).byElement) // from r-value 60 { 61 assert(e == K(11)); 62 debug static assert(is(typeof(e) == const(K))); // always const access 63 }
range checking
version(showEntries) dbg(); immutable n = 11; alias K = Nullable!(uint, uint.max); alias V = uint; alias X = OpenHashMapOrSet!(K, V, FNV!(64, true)); auto s = X.withCapacity(n); void dummy(ref V value) {} debug assertThrown!RangeError(dummy(s[K(0)])); foreach (immutable i; 0 .. n) { const k = K(i); s[k] = V(i); debug assertNotThrown!RangeError(dummy(s[k])); } foreach (immutable i; 0 .. n) { const k = K(i); assert(s.remove(k)); debug assertThrown!RangeError(dummy(s[k])); } s[K(0)] = V.init; auto vp = K(0) in s; debug static assert(is(typeof(vp) == V*)); assert((*vp) == V.init); assert(s.remove(K(0))); assert(K(0) !in s); X t; t.reserveExtra(4096); t.clear();
class as value
version(showEntries) dbg(); immutable n = 11; alias K = Nullable!(uint, uint.max); class V { this(uint data) { this.data = data; } uint data; } alias X = OpenHashMapOrSet!(K, V, FNV!(64, true)); auto s = X.withCapacity(n); void dummy(ref V value) {} debug assertThrown!RangeError(dummy(s[K(0)])); foreach (immutable i; 0 .. n) { const k = K(i); s[k] = new V(i); debug assertNotThrown!RangeError(dummy(s[k])); } // test range { auto sr = s.byKeyValue; // scoped range assert(sr.length == n); foreach (immutable i; 0 .. n) { sr.popFront(); assert(sr.length == n - i - 1); } } foreach (immutable i; 0 .. n) { const k = K(i); assert(s.remove(k)); debug assertThrown!RangeError(dummy(s[k])); } s[K(0)] = V.init; auto vp = K(0) in s; debug static assert(is(typeof(vp) == V*)); assert(s.remove(K(0))); assert(K(0) !in s); X t; t.reserveExtra(4096);
constness inference of ranges
version(showEntries) dbg(); alias K = Nullable!(uint, uint.max); class V { this(uint data) { this.data = data; } uint data; } alias X = OpenHashMapOrSet!(K, V, FNV!(64, true)); const x = X(); foreach (ref e; x.byKey) { debug static assert(is(typeof(e) == const(X.KeyType))); } foreach (ref e; x.byValue) { debug static assert(is(typeof(e) == const(X.ValueType))); } foreach (e; x.byKeyValue) { debug static assert(is(typeof(e.key) == const(X.KeyType))); debug static assert(is(typeof(e.value) == const(X.ValueType))); debug static assert(is(typeof(e) == const(X.ElementType))); }
range key constness and value mutability with class value
version(showEntries) dbg(); struct S { uint value; } alias K = Nullable!(S, S(uint.min)); // use uint.min to trigger use of faster `Allocator.allocateZeroed` class V { this(uint data) { this.data = data; } uint data; } alias X = OpenHashMapOrSet!(K, V, FNV!(64, true)); auto x = X(); x[K(S(42))] = new V(43); assert(x.length == 1); foreach (e; x.byValue) // `e` is auto ref { debug static assert(is(typeof(e) == X.ValueType)); // mutable access to value assert(e.data == 43); // value mutation side effects e.data += 1; assert(e.data == 44); e.data -= 1; assert(e.data == 43); } foreach (ref e; x.byKeyValue) // `e` is auto ref { debug static assert(is(typeof(e.key) == const(X.KeyType))); // const access to key debug static assert(is(typeof(e.value) == X.ValueType)); // mutable access to value assert(e.key.value == 42); assert(e.value.data == 43); // key cannot be mutated debug static assert(!__traits(compiles, { e.key.value += 1; })); // value mutation side effects e.value.data += 1; assert(e.value.data == 44); e.value.data -= 1; assert(e.value.data == 43); }
range key constness and value mutability with class key and class value
1 version(showEntries) dbg(); 2 class K 3 { 4 this(uint value) 5 { 6 this.value = value; 7 } 8 9 @property bool opEquals(const scope typeof(this) rhs) const 10 { 11 return value == rhs.value; 12 } 13 14 uint value; 15 } 16 17 class V 18 { 19 this(uint data) { this.data = data; } 20 uint data; 21 } 22 23 alias X = OpenHashMapOrSet!(K, V, FNV!(64, true)); 24 auto x = X(); 25 26 x[new K(42)] = new V(43); 27 28 assert(x.length == 1); 29 30 foreach (e; x.byValue) // `e` is auto ref 31 { 32 debug static assert(is(typeof(e) == X.ValueType)); // mutable access to value 33 assert(e.data == 43); 34 35 // value mutation side effects 36 e.data += 1; 37 assert(e.data == 44); 38 e.data -= 1; 39 assert(e.data == 43); 40 } 41 42 foreach (ref e; x.byKeyValue) // `e` is auto ref 43 { 44 debug static assert(is(typeof(e.key) == X.KeyType)); // mutable access to class key 45 debug static assert(is(typeof(e.value) == X.ValueType)); // mutable access to value 46 47 assert(e.key.value == 42); 48 assert(e.value.data == 43); 49 50 // class key itself should not be mutable 51 debug static assert(!__traits(compiles, { e.key = null; })); 52 53 // members of key can be mutated 54 debug static assert(__traits(compiles, { e.key.value += 1; })); 55 56 // value mutation side effects 57 e.value.data += 1; 58 assert(e.value.data == 44); 59 e.value.data -= 1; 60 assert(e.value.data == 43); 61 }
range key constness and value mutability with class key and class value
1 version(showEntries) dbg(); 2 class K 3 { 4 this(uint value) 5 { 6 this.value = value; 7 } 8 uint value; 9 } 10 11 struct V 12 { 13 this(uint data) { this.data = data; } 14 @disable this(this); 15 uint data; 16 } 17 18 alias X = OpenHashMapOrSet!(K, V, FNV!(64, true)); 19 auto x = X(); 20 21 auto key42 = new K(42); 22 x[key42] = V(43); 23 24 assert(x.length == 1); 25 26 foreach (ref e; x.byValue) // `e` is auto ref 27 { 28 debug static assert(is(typeof(e) == X.ValueType)); // mutable access to value 29 assert(e.data == 43); 30 31 // value mutation side effects 32 e.data += 1; 33 assert(e.data == 44); 34 e.data -= 1; 35 assert(e.data == 43); 36 } 37 38 foreach (ref e; x.byKeyValue) // `e` is auto ref 39 { 40 debug static assert(is(typeof(e.key) == X.KeyType)); // mutable access to class key 41 debug static assert(is(typeof(e.value) == X.ValueType)); // mutable access to value 42 43 assert(e.key.value == 42); 44 assert(e.value.data == 43); 45 46 // value mutation side effects 47 e.value.data += 1; 48 assert(e.value.data == 44); 49 e.value.data -= 1; 50 assert(e.value.data == 43); 51 } 52 53 assert(x.length == 1); 54 55 assert(x.remove(key42)); 56 assert(x.length == 0); 57 58 x[key42] = V(43); 59 assert(x.length == 1);