range

Undocumented in source.
alias range = byElement

Examples

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

alias K = uint;
alias X = SSOHashMapOrSet!(K, void, null, FNV!(64, true));

immutable a = [11, 22].s;

// mutable
auto x = X.withElements(a);
foreach (e; x.byElement)    // from l-value
{
    static assert(is(typeof(e) == const(K))); // always const access
}

// const
const y = X.withElements(a);
foreach (e; y.byElement)    // from l-value
{
    static assert(is(typeof(e) == const(K)));
}

foreach (e; X.withElements([11].s).byElement) // from r-value
{
    static assert(is(typeof(e) == const(K))); // always const access
}

test various things

1 immutable n = 600;
2 
3 alias K = uint;
4 
5 import std.meta : AliasSeq;
6 foreach (V; AliasSeq!(void, string))
7 {
8     alias X = SSOHashMapOrSet!(K, V, null, FNV!(64, true));
9 
10     static if (!X.hasValue)
11     {
12         auto x = X.withElements([11, 12, 13].s);
13 
14         import std.algorithm : count;
15         auto xr = x.byElement;
16 
17         alias R = typeof(xr);
18         import std.range.primitives : isInputRange;
19         import std.traits : ReturnType;
20         static assert(is(typeof(R.init) == R));
21         static assert(is(ReturnType!((R xr) => xr.empty) == bool));
22         auto f = xr.front;
23         static assert(is(typeof((R xr) => xr.front)));
24         static assert(!is(ReturnType!((R xr) => xr.front) == void));
25         static assert(is(typeof((R xr) => xr.popFront)));
26 
27         static assert(isInputRange!(typeof(xr)));
28 
29         assert(x.byElement.count == 3);
30 
31         X y;
32         foreach (const ref e; x.byElement)
33         {
34             y.insert(e);
35         }
36 
37         assert(y.byElement.count == 3);
38         assert(x == y);
39 
40         const z = X();
41         assert(z.byElement.count == 0);
42 
43         immutable w = X();
44         assert(w.byElement.count == 0);
45 
46         {
47             auto xc = X.withElements([11, 12, 13].s);
48             assert(xc.length == 3);
49             assert(xc.contains(11));
50 
51             // TODO http://forum.dlang.org/post/kvwrktmameivubnaifdx@forum.dlang.org
52             xc.removeAllMatching!(_ => _ == 11);
53 
54             assert(xc.length == 2);
55             assert(!xc.contains(11));
56 
57             xc.removeAllMatching!(_ => _ == 12);
58             assert(!xc.contains(12));
59             assert(xc.length == 1);
60 
61             xc.removeAllMatching!(_ => _ == 13);
62             assert(!xc.contains(13));
63             assert(xc.length == 0);
64 
65             // this is ok
66             foreach (e; xc.byElement) {}
67 
68         }
69 
70         {
71             auto k = X.withElements([11, 12].s).filtered!(_ => _ != 11).byElement;
72             static assert(isInputRange!(typeof(k)));
73             assert(k.front == 12);
74             k.popFront();
75             assert(k.empty);
76         }
77 
78         {
79             X q;
80             auto qv = [11U, 12U, 13U, 14U].s;
81             q.insertN(qv);
82             foreach (e; qv[])
83             {
84                 assert(q.contains(e));
85             }
86             q.clear();
87             assert(q.empty);
88         }
89     }
90 
91     import nxt.container_traits : mustAddGCRange;
92     static if (X.hasValue &&
93                is(V == string))
94     {
95         static assert(mustAddGCRange!V);
96         static assert(mustAddGCRange!(V[1]));
97         static assert(mustAddGCRange!(X.T));
98         static assert(mustAddGCRange!(X.SmallBin));
99         static assert(!mustAddGCRange!(X.LargeBin));
100     }
101     else
102     {
103         static assert(!mustAddGCRange!(X.T));
104         static assert(!mustAddGCRange!(X.SmallBin), "Fails for X being " ~ X.SmallBin.stringof);
105     }
106 
107     auto x1 = X();            // start empty
108 
109     // all bins start small
110     assert(x1.binCounts.largeCount == 0);
111 
112     // fill x1
113 
114     foreach (immutable key; 0 .. n)
115     {
116         static if (X.hasValue)
117         {
118             const value = V.init;
119             const element = X.ElementType(key, value);
120         }
121         else
122         {
123             const element = key;
124         }
125 
126         assert(key !in x1);
127 
128         assert(x1.length == key);
129         assert(x1.insert(element) == X.InsertionStatus.added);
130 
131         static if (X.hasValue)
132         {
133             const e2 = X.ElementType(key, "a");
134             assert(x1.insert(e2) == X.InsertionStatus.modified);
135             assert(x1.contains(key));
136             assert(x1.get(key, null) == "a");
137             x1.remove(key);
138             x1[key] = value;
139         }
140 
141         assert(x1.length == key + 1);
142 
143         assert(key in x1);
144         static if (X.hasValue)
145         {
146             auto elementFound = key in x1;
147             assert(elementFound);
148             assert(*elementFound != "_");
149         }
150 
151         assert(x1.insert(element) == X.InsertionStatus.unmodified);
152         static if (X.hasValue)
153         {
154             assert(x1.insert(key, value) == X.InsertionStatus.unmodified);
155         }
156         assert(x1.length == key + 1);
157 
158         assert(key in x1);
159     }
160 
161     static if (X.hasValue)
162     {
163         import nxt.dynamic_array : Array = DynamicArray;
164         Array!(X.ElementType) a1;
165 
166         foreach (const ref key; x1.byKey)
167         {
168             auto keyPtr = key in x1;
169             assert(keyPtr);
170             a1 ~= X.ElementType(key, (*keyPtr));
171         }
172 
173         assert(x1.length == a1.length);
174 
175         foreach (aElement; a1[])
176         {
177             auto keyPtr = aElement.key in x1;
178             assert(keyPtr);
179             assert((*keyPtr) is aElement.value);
180         }
181     }
182 
183     assert(x1.length == n);
184 
185     // duplicate x1
186 
187     auto x2 = x1.dup;
188 
189     // non-symmetric algorithm so both are needed
190     assert(x2 == x1);
191     assert(x1 == x2);
192 
193     static if (X.hasValue)
194     {
195         assert(equal(x1.byKey, x2.byKey));
196         assert(equal(x1.byValue, x2.byValue));
197         assert(equal(x1.byKeyValue, x2.byKeyValue));
198         assert(equal(x1[], x2[]));
199     }
200 
201     assert(x1.binCounts.largeCount ==
202            x2.binCounts.largeCount);
203 
204     static assert(!__traits(compiles, { const _ = x1 < x2; })); // no ordering
205 
206     assert(x2.length == n);
207 
208     // empty x1
209 
210     foreach (immutable key; 0 .. n)
211     {
212         static if (X.hasValue)
213         {
214             const element = X.ElementType(key, V.init);
215         }
216         else
217         {
218             const element = key;
219         }
220 
221         assert(x1.length == n - key);
222 
223         auto elementFound = key in x1;
224         assert(elementFound);
225         static if (X.hasValue)
226         {
227             assert(*elementFound is element.value);
228         }
229 
230         assert(x1.remove(key));
231         assert(x1.length == n - key - 1);
232 
233         static if (!X.hasValue)
234         {
235             assert(!x1.contains(key));
236         }
237         assert(key !in x1);
238         assert(!x1.remove(key));
239         assert(x1.length == n - key - 1);
240     }
241 
242     assert(x1.binCounts.largeCount == 0);
243 
244     assert(x1.length == 0);
245 
246     x1.clear();
247     assert(x1.length == 0);
248 
249     // empty x2
250 
251     assert(x2.length == n); // should be not affected by emptying of x1
252 
253     foreach (immutable key; 0 .. n)
254     {
255         static if (X.hasValue)
256         {
257             const element = X.ElementType(key, V.init);
258         }
259         else
260         {
261             const element = key;
262         }
263 
264         assert(x2.length == n - key);
265 
266         assert(key in x2);
267 
268         assert(x2.remove(key));
269         assert(x2.length == n - key - 1);
270 
271         assert(key !in x2);
272         assert(!x2.remove(key));
273         assert(x2.length == n - key - 1);
274     }
275 
276     assert(x2.binCounts.largeCount == 0);
277 
278     assert(x2.length == 0);
279 
280     x2.clear();
281     assert(x2.length == 0);
282 }

range checking

import std.exception : assertThrown, assertNotThrown;
import core.exception : RangeError;
import nxt.uncopyable_sample : V = SomeUncopyable;

immutable n = 11;

alias K = uint;

alias X = SSOHashMapOrSet!(K, V, null, FNV!(64, true));

auto s = X.withCapacity(n);

void dummy(ref V value) {}

assertThrown!RangeError(dummy(s[K.init]));

foreach (immutable uint i; 0 .. n)
{
    s[i] = V(i);
    assertNotThrown!RangeError(dummy(s[i]));
}

foreach (immutable uint i; 0 .. n)
{
    s.remove(i);
    assertThrown!RangeError(dummy(s[i]));
}

s[K.init] = V.init;
auto vp = K.init in s;
static assert(is(typeof(vp) == V*));
assert((*vp) == V.init);

s.remove(K.init);
assert(K.init !in s);

X t;
t.reserveExtra(4096);
assert(t.binCount == 8192);

t.clear();

class as value

import std.exception : assertThrown, assertNotThrown;
import core.exception : RangeError;

immutable n = 11;

alias K = uint;
class V
{
    this(uint data) { this.data = data; }
    uint data;
}

alias X = SSOHashMapOrSet!(K, V, null, FNV!(64, true));

auto s = X.withCapacity(n);

void dummy(ref V value) {}

assertThrown!RangeError(dummy(s[K.init]));

foreach (immutable uint i; 0 .. n)
{
    s[i] = new V(i);
    assertNotThrown!RangeError(dummy(s[i]));
}

// test range
auto sr = s.byKeyValue;
assert(sr.length == n);
foreach (immutable uint i; 0 .. n)
{
    sr.popFront();
    assert(sr.length == n - i - 1);
}

foreach (immutable uint i; 0 .. n)
{
    s.remove(i);
    assertThrown!RangeError(dummy(s[i]));
}

s[K.init] = V.init;
auto vp = K.init in s;
static assert(is(typeof(vp) == V*));

s.remove(K.init);
assert(K.init !in s);

X t;
t.reserveExtra(4096);
assert(t.binCount == 8192);

constness inference of ranges

alias K = uint;
class V
{
    this(uint data) { this.data = data; }
    uint data;
}

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

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

foreach (e; x.byValue)
{
    static assert(is(typeof(e) == X.ValueType)); // TODO should be const(X.ValueType)
}

foreach (e; x.byKeyValue)
{
    static assert(is(typeof(e.key) == const(X.KeyType)));
    static assert(is(typeof(e.value) == const(X.ValueType)));
    static assert(is(typeof(e) == const(X.ElementType)));
}

range key constness and value mutability with class value

struct K
{
    @disable this(this);
    uint value;
}

class V
{
    this(uint data) { this.data = data; }
    uint data;
}

alias X = SSOHashMapOrSet!(K, V, null, FNV!(64, true));
auto x = X();

x[K(42)] = new V(43);

assert(x.length == 1);

foreach (e; x.byValue)      // `e` is auto ref
{
    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
{
    static assert(is(typeof(e.key) == const(X.KeyType))); // const access to key

    static assert(is(typeof(e.value) == X.ValueType)); // mutable access to value

    assert(e.value.data == 43);

    // value mutation side effects
    e.value.data += 1;
    assert(e.value.data == 44);
    e.value.data -= 1;
    assert(e.value.data == 43);
}

Meta