d: Merge dmd, druntime d8e3976a58, phobos 7a6e95688
[official-gcc.git] / gcc / d / dmd / root / aav.d
blob8929679e37ef4fc77a5b6675e8de99150c5c4041
1 /**
2 * Associative array implementation.
4 * Copyright: Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
5 * Authors: Walter Bright, https://www.digitalmars.com
6 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/aav.d, root/_aav.d)
8 * Documentation: https://dlang.org/phobos/dmd_root_aav.html
9 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/aav.d
12 module dmd.root.aav;
14 import core.stdc.string;
15 import dmd.root.rmem;
17 nothrow:
19 private size_t hash(size_t a) pure nothrow @nogc @safe
21 a ^= (a >> 20) ^ (a >> 12);
22 return a ^ (a >> 7) ^ (a >> 4);
25 private struct KeyValueTemplate(K,V)
27 K key;
28 V value;
31 alias Key = void*;
32 alias Value = void*;
34 alias KeyValue = KeyValueTemplate!(Key, Value);
36 private struct aaA
38 private:
39 aaA* next;
40 KeyValue keyValue;
41 alias keyValue this;
44 private struct AA
46 private:
47 aaA** b;
48 size_t b_length;
49 size_t nodes; // total number of aaA nodes
50 aaA*[4] binit; // initial value of b[]
51 aaA aafirst; // a lot of these AA's have only one entry
54 /****************************************************
55 * Determine number of entries in associative array.
57 private size_t dmd_aaLen(const AA* aa) pure nothrow @nogc @safe
59 return aa ? aa.nodes : 0;
62 /*************************************************
63 * Get pointer to value in associative array indexed by key.
64 * Add entry for key if it is not already there, returning a pointer to a null Value.
65 * Create the associative array if it does not already exist.
67 private Value* dmd_aaGet(AA** paa, Key key) pure nothrow
69 //printf("paa = %p\n", paa);
70 if (!*paa)
72 AA* a = cast(AA*)mem.xmalloc(AA.sizeof);
73 a.b = cast(aaA**)a.binit;
74 a.b_length = 4;
75 a.nodes = 0;
76 a.binit[0] = null;
77 a.binit[1] = null;
78 a.binit[2] = null;
79 a.binit[3] = null;
80 *paa = a;
81 assert((*paa).b_length == 4);
83 //printf("paa = %p, *paa = %p\n", paa, *paa);
84 assert((*paa).b_length);
85 size_t i = hash(cast(size_t)key) & ((*paa).b_length - 1);
86 aaA** pe = &(*paa).b[i];
87 aaA* e;
88 while ((e = *pe) !is null)
90 if (key == e.key)
91 return &e.value;
92 pe = &e.next;
94 // Not found, create new elem
95 //printf("create new one\n");
96 size_t nodes = ++(*paa).nodes;
97 e = (nodes != 1) ? cast(aaA*)mem.xmalloc(aaA.sizeof) : &(*paa).aafirst;
98 //e = new aaA();
99 e.next = null;
100 e.key = key;
101 e.value = null;
102 *pe = e;
103 //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes);
104 if (nodes > (*paa).b_length * 2)
106 //printf("rehash\n");
107 dmd_aaRehash(paa);
109 return &e.value;
112 /*************************************************
113 * Get value in associative array indexed by key.
114 * Returns NULL if it is not already there.
116 private Value dmd_aaGetRvalue(AA* aa, Key key) pure nothrow @nogc
118 //printf("_aaGetRvalue(key = %p)\n", key);
119 if (aa)
121 size_t i;
122 size_t len = aa.b_length;
123 i = hash(cast(size_t)key) & (len - 1);
124 aaA* e = aa.b[i];
125 while (e)
127 if (key == e.key)
128 return e.value;
129 e = e.next;
132 return null; // not found
136 Gets a range of key/values for `aa`.
138 Returns: a range of key/values for `aa`.
140 @property auto asRange(AA* aa) pure nothrow @nogc
142 return AARange!(Key, Value)(aa);
145 private struct AARange(K,V)
147 AA* aa;
148 // current index into bucket array `aa.b`
149 size_t bIndex;
150 aaA* current;
152 this(AA* aa) pure nothrow @nogc scope
154 if (aa)
156 this.aa = aa;
157 toNext();
161 @property bool empty() const pure nothrow @nogc @safe
163 return current is null;
166 @property auto front() const pure nothrow @nogc
168 return cast(KeyValueTemplate!(K,V))current.keyValue;
171 void popFront() pure nothrow @nogc
173 if (current.next)
174 current = current.next;
175 else
177 bIndex++;
178 toNext();
182 private void toNext() pure nothrow @nogc
184 for (; bIndex < aa.b_length; bIndex++)
186 if (auto next = aa.b[bIndex])
188 current = next;
189 return;
192 current = null;
196 unittest
198 AA* aa = null;
199 foreach(keyValue; aa.asRange)
200 assert(0);
202 enum totalKeyLength = 50;
203 foreach (i; 1 .. totalKeyLength + 1)
205 auto key = cast(void*)i;
207 auto valuePtr = dmd_aaGet(&aa, key);
208 assert(valuePtr);
209 *valuePtr = key;
211 bool[totalKeyLength] found;
212 size_t rangeCount = 0;
213 foreach (keyValue; aa.asRange)
215 assert(keyValue.key <= key);
216 assert(keyValue.key == keyValue.value);
217 rangeCount++;
218 assert(!found[cast(size_t)keyValue.key - 1]);
219 found[cast(size_t)keyValue.key - 1] = true;
221 assert(rangeCount == i);
225 /********************************************
226 * Rehash an array.
228 private void dmd_aaRehash(AA** paa) pure nothrow
230 //printf("Rehash\n");
231 if (*paa)
233 AA* aa = *paa;
234 if (aa)
236 size_t len = aa.b_length;
237 if (len == 4)
238 len = 32;
239 else
240 len *= 4;
241 aaA** newb = cast(aaA**)mem.xmalloc(aaA.sizeof * len);
242 memset(newb, 0, len * (aaA*).sizeof);
243 for (size_t k = 0; k < aa.b_length; k++)
245 aaA* e = aa.b[k];
246 while (e)
248 aaA* enext = e.next;
249 size_t j = hash(cast(size_t)e.key) & (len - 1);
250 e.next = newb[j];
251 newb[j] = e;
252 e = enext;
255 if (aa.b != cast(aaA**)aa.binit)
256 mem.xfree(aa.b);
257 aa.b = newb;
258 aa.b_length = len;
263 unittest
265 AA* aa = null;
266 Value v = dmd_aaGetRvalue(aa, null);
267 assert(!v);
268 Value* pv = dmd_aaGet(&aa, null);
269 assert(pv);
270 *pv = cast(void*)3;
271 v = dmd_aaGetRvalue(aa, null);
272 assert(v == cast(void*)3);
275 struct AssocArray(K,V)
277 private AA* aa;
280 Returns: The number of key/value pairs.
282 @property size_t length() const pure nothrow @nogc @safe
284 return dmd_aaLen(aa);
288 Lookup value associated with `key` and return the address to it. If the `key`
289 has not been added, it adds it and returns the address to the new value.
291 Params:
292 key = key to lookup the value for
294 Returns: the address to the value associated with `key`. If `key` does not exist, it
295 is added and the address to the new value is returned.
297 V* getLvalue(const(K) key) pure nothrow
299 return cast(V*)dmd_aaGet(&aa, cast(void*)key);
303 Lookup and return the value associated with `key`, if the `key` has not been
304 added, it returns null.
306 Params:
307 key = key to lookup the value for
309 Returns: the value associated with `key` if present, otherwise, null.
311 V opIndex(const(K) key) pure nothrow @nogc
313 return cast(V)dmd_aaGetRvalue(aa, cast(void*)key);
317 Gets a range of key/values for `aa`.
319 Returns: a range of key/values for `aa`.
321 @property auto asRange() pure nothrow @nogc
323 return AARange!(K,V)(aa);
328 unittest
330 auto foo = new Object();
331 auto bar = new Object();
333 AssocArray!(Object, Object) aa;
335 assert(aa[foo] is null);
336 assert(aa.length == 0);
338 auto fooValuePtr = aa.getLvalue(foo);
339 *fooValuePtr = bar;
341 assert(aa[foo] is bar);
342 assert(aa.length == 1);