byKeyValue

@safe @trusted
byKeyValue
(
Table
)
(
auto ref return Table c
)
if (
isInstanceOf!(OpenHashMapOrSet, Table) &&
Table.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 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);

Meta