1 /**
2  * Compiler implementation of the D programming language
3  * http://dlang.org
4  *
5  * Copyright: Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:   Walter Bright, http://www.digitalmars.com
7  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:    $(DMDSRC root/_aav.d)
9  */
10 
11 module ddmd.root.aav;
12 
13 import core.stdc..string;
14 import ddmd.root.rmem;
15 
16 extern (C++) size_t hash(size_t a)
17 {
18     a ^= (a >> 20) ^ (a >> 12);
19     return a ^ (a >> 7) ^ (a >> 4);
20 }
21 
22 alias Key = void*;
23 alias Value = void*;
24 
25 struct aaA
26 {
27     aaA* next;
28     Key key;
29     Value value;
30 }
31 
32 struct AA
33 {
34     aaA** b;
35     size_t b_length;
36     size_t nodes; // total number of aaA nodes
37     aaA*[4] binit; // initial value of b[]
38     aaA aafirst; // a lot of these AA's have only one entry
39 }
40 
41 /****************************************************
42  * Determine number of entries in associative array.
43  */
44 extern (C++) size_t dmd_aaLen(const AA* aa) pure
45 {
46     return aa ? aa.nodes : 0;
47 }
48 
49 /*************************************************
50  * Get pointer to value in associative array indexed by key.
51  * Add entry for key if it is not already there, returning a pointer to a null Value.
52  * Create the associative array if it does not already exist.
53  */
54 extern (C++) Value* dmd_aaGet(AA** paa, Key key)
55 {
56     //printf("paa = %p\n", paa);
57     if (!*paa)
58     {
59         AA* a = cast(AA*)mem.xmalloc(AA.sizeof);
60         a.b = cast(aaA**)a.binit;
61         a.b_length = 4;
62         a.nodes = 0;
63         a.binit[0] = null;
64         a.binit[1] = null;
65         a.binit[2] = null;
66         a.binit[3] = null;
67         *paa = a;
68         assert((*paa).b_length == 4);
69     }
70     //printf("paa = %p, *paa = %p\n", paa, *paa);
71     assert((*paa).b_length);
72     size_t i = hash(cast(size_t)key) & ((*paa).b_length - 1);
73     aaA** pe = &(*paa).b[i];
74     aaA* e;
75     while ((e = *pe) !is null)
76     {
77         if (key == e.key)
78             return &e.value;
79         pe = &e.next;
80     }
81     // Not found, create new elem
82     //printf("create new one\n");
83     size_t nodes = ++(*paa).nodes;
84     e = (nodes != 1) ? cast(aaA*)mem.xmalloc(aaA.sizeof) : &(*paa).aafirst;
85     //e = new aaA();
86     e.next = null;
87     e.key = key;
88     e.value = null;
89     *pe = e;
90     //printf("length = %d, nodes = %d\n", (*paa)->b_length, nodes);
91     if (nodes > (*paa).b_length * 2)
92     {
93         //printf("rehash\n");
94         dmd_aaRehash(paa);
95     }
96     return &e.value;
97 }
98 
99 /*************************************************
100  * Get value in associative array indexed by key.
101  * Returns NULL if it is not already there.
102  */
103 extern (C++) Value dmd_aaGetRvalue(AA* aa, Key key)
104 {
105     //printf("_aaGetRvalue(key = %p)\n", key);
106     if (aa)
107     {
108         size_t i;
109         size_t len = aa.b_length;
110         i = hash(cast(size_t)key) & (len - 1);
111         aaA* e = aa.b[i];
112         while (e)
113         {
114             if (key == e.key)
115                 return e.value;
116             e = e.next;
117         }
118     }
119     return null; // not found
120 }
121 
122 /********************************************
123  * Rehash an array.
124  */
125 extern (C++) void dmd_aaRehash(AA** paa)
126 {
127     //printf("Rehash\n");
128     if (*paa)
129     {
130         AA* aa = *paa;
131         if (aa)
132         {
133             size_t len = aa.b_length;
134             if (len == 4)
135                 len = 32;
136             else
137                 len *= 4;
138             aaA** newb = cast(aaA**)mem.xmalloc(aaA.sizeof * len);
139             memset(newb, 0, len * (aaA*).sizeof);
140             for (size_t k = 0; k < aa.b_length; k++)
141             {
142                 aaA* e = aa.b[k];
143                 while (e)
144                 {
145                     aaA* enext = e.next;
146                     size_t j = hash(cast(size_t)e.key) & (len - 1);
147                     e.next = newb[j];
148                     newb[j] = e;
149                     e = enext;
150                 }
151             }
152             if (aa.b != cast(aaA**)aa.binit)
153                 mem.xfree(aa.b);
154             aa.b = newb;
155             aa.b_length = len;
156         }
157     }
158 }
159 
160 unittest
161 {
162     AA* aa = null;
163     Value v = dmd_aaGetRvalue(aa, null);
164     assert(!v);
165     Value* pv = dmd_aaGet(&aa, null);
166     assert(pv);
167     *pv = cast(void*)3;
168     v = dmd_aaGetRvalue(aa, null);
169     assert(v == cast(void*)3);
170 }