byKeyValue

@safe @trusted
byKeyValue
(
SomeMap
)
(
auto ref return SomeMap c
)
if (
isInstanceOf!(OpenHashMap, SomeMap) &&
SomeMap.hasValue
)

Return Value

Type: auto

range that iterates through the key-value-pairs of c in undefined order.

Examples

make range from l-value and r-value. element access is always const

1 version(showEntries) dbg();
2 
3 import core.exception : AssertError;
4 import std.typecons : Nullable;
5 import nxt.digestx.fnv : FNV;
6 import nxt.array_help : s;
7 debug import std.exception : assertThrown;
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     assert(eDup == x);
54 }
55 
56 // const
57 const y = X.withElements(ks);
58 assert(!x.contains(k44));
59 assert(!x.containsUsingLinearSearch(k44));
60 foreach (e; y.byElement)    // from l-value
61 {
62     auto _ = y.byElement;   // ok to read-borrow again
63     assert(y.contains(e));
64     assert(y.containsUsingLinearSearch(e));
65     debug static assert(is(typeof(e) == const(K)));
66 }
67 
68 foreach (e; X.withElements([K(11)].s).byElement) // from r-value
69 {
70     assert(e == K(11));
71     debug static assert(is(typeof(e) == const(K))); // always const access
72 }

range checking

version(showEntries) dbg();
import core.exception : RangeError;
import std.typecons : Nullable;
import nxt.digestx.fnv : FNV;
debug import std.exception : assertThrown, assertNotThrown;
immutable n = 11;

alias K = Nullable!(uint, uint.max);
alias V = uint;

alias X = OpenHashMap!(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

1 version(showEntries) dbg();
2 import core.exception : RangeError;
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

version(showEntries) dbg();
import std.typecons : Nullable;
import nxt.digestx.fnv : FNV;

alias K = Nullable!(uint, uint.max);
class V
{
    this(uint data) { this.data = data; }
    uint data;
}

alias X = OpenHashMap!(K, V, FNV!(64, true));
const x = X();

foreach (const e; x.byKey)
{
    debug static assert(is(typeof(e) == const(X.KeyType)));
}

foreach (const e; x.byValue)
{
    debug static assert(is(typeof(e) == const(X.ValueType)));
}

foreach (const e; X.init.byValue)
{
    debug static assert(is(typeof(e) == const(X.ValueType)));
}

foreach (const 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();
import std.typecons : Nullable;
import nxt.digestx.fnv : FNV;

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 = OpenHashMap!(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 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);

Meta