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