2 * HashTab container for internal usage.
4 * Copyright: Copyright Martin Nowak 2013.
5 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
6 * Authors: Martin Nowak
8 module core.internal.container.hashtab;
10 import core.internal.container.array;
11 static import common = core.internal.container.common;
13 struct HashTab(Key, Value)
45 @property size_t length() const
50 @property bool empty() const
55 void remove(in Key key)
56 in { assert(key in this); }
61 immutable hash = hashOf(key) & mask;
62 auto pp = &_buckets[hash];
71 if (--_length < _buckets.length && _length >= 4)
83 ref inout(Value) opIndex(Key key) inout
85 return *opBinaryRight!("in")(key);
88 void opIndexAssign(Value value, Key key)
93 inout(Value)* opBinaryRight(string op)(const scope Key key) inout
98 immutable hash = hashOf(key) & mask;
99 for (inout(Node)* p = _buckets[hash]; p !is null; p = p._next)
108 int opApply(scope int delegate(ref Key, ref Value) dg)
110 immutable save = _inOpApply;
112 scope (exit) _inOpApply = save;
113 foreach (p; _buckets)
117 if (auto res = dg(p._key, p._value))
129 if (auto p = opBinaryRight!("in")(key))
132 ensureNotInOpApply();
134 if (!_buckets.length)
137 immutable hash = hashOf(key) & mask;
138 auto p = cast(Node*)common.xmalloc(Node.sizeof);
139 common.initialize(*p);
141 p._next = _buckets[hash];
143 if (++_length >= 2 * _buckets.length)
148 static hash_t hashOf(const scope ref Key key) @trusted
150 static if (is(Key U : U[]))
151 return .hashOf(key, 0);
153 return .hashOf((&key)[0 .. 1], 0);
156 @property hash_t mask() const
158 return _buckets.length - 1;
164 assert(_buckets.length);
168 immutable ocnt = _buckets.length;
169 immutable nmask = 2 * ocnt - 1;
170 _buckets.length = 2 * ocnt;
171 for (size_t i = 0; i < ocnt; ++i)
173 auto pp = &_buckets[i];
178 immutable nidx = hashOf(p._key) & nmask;
182 p._next = _buckets[nidx];
196 assert(_buckets.length >= 2);
200 immutable ocnt = _buckets.length;
201 immutable ncnt = ocnt >> 1;
202 immutable nmask = ncnt - 1;
204 for (size_t i = ncnt; i < ocnt; ++i)
206 if (auto tail = _buckets[i])
208 immutable nidx = i & nmask;
209 auto pp = &_buckets[nidx];
216 _buckets.length = ncnt;
219 void ensureNotInOpApply()
222 assert(0, "Invalid HashTab manipulation during opApply iteration.");
225 Array!(Node*) _buckets;
232 HashTab!(int, int) tab;
234 foreach (i; 0 .. 100)
237 foreach (i; 0 .. 100)
238 assert(tab[i] == 100 - i);
241 assert(v == 100 - k);
246 assert(tab.length == 50);
249 assert(tab[2 * i + 1] == 100 - 2 * i - 1);
251 assert(tab.length == 50);
261 static assert(!__traits(compiles, { HashTab!(int, int) tab2 = tab; }));
262 HashTab!(int, int) tab2;
263 static assert(!__traits(compiles, tab = tab2));
264 static void foo(HashTab!(int, int) copy) {}
265 static assert(!__traits(compiles, foo(tab)));
270 HashTab!(string, size_t) tab;
273 assert(tab["foo"] == 0);
275 assert(tab["foo"] == 1);
277 assert(tab["foo"] == 2);
282 assert(tab.length == 1);
286 assert(tab[s] == 12);
294 alias RC = common.RC!();
295 HashTab!(size_t, RC) tab;
311 import core.exception;
313 HashTab!(uint, uint) tab;
321 if (k == 3) tab.remove(k);
323 catch (AssertError e)