xref: /netbsd-src/external/gpl3/gcc.old/dist/gcc/d/dmd/root/stringtable.c (revision 627f7eb200a4419d89b531d55fccd2ee3ffdcde0)
1*627f7eb2Smrg 
2*627f7eb2Smrg /* Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
3*627f7eb2Smrg  * http://www.digitalmars.com
4*627f7eb2Smrg  * Distributed under the Boost Software License, Version 1.0.
5*627f7eb2Smrg  * (See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt)
6*627f7eb2Smrg  * https://github.com/D-Programming-Language/dmd/blob/master/src/root/stringtable.c
7*627f7eb2Smrg  */
8*627f7eb2Smrg 
9*627f7eb2Smrg #include "dsystem.h"                    // uint{8|16|32}_t, memcpy()
10*627f7eb2Smrg #include "root.h"
11*627f7eb2Smrg #include "rmem.h"                       // mem
12*627f7eb2Smrg #include "stringtable.h"
13*627f7eb2Smrg #include "hash.h"
14*627f7eb2Smrg 
15*627f7eb2Smrg #define POOL_BITS 12
16*627f7eb2Smrg #define POOL_SIZE (1U << POOL_BITS)
17*627f7eb2Smrg 
18*627f7eb2Smrg struct StringEntry
19*627f7eb2Smrg {
20*627f7eb2Smrg     uint32_t hash;
21*627f7eb2Smrg     uint32_t vptr;
22*627f7eb2Smrg };
23*627f7eb2Smrg 
allocValue(const char * s,size_t length,void * ptrvalue)24*627f7eb2Smrg uint32_t StringTable::allocValue(const char *s, size_t length, void *ptrvalue)
25*627f7eb2Smrg {
26*627f7eb2Smrg     const size_t nbytes = sizeof(StringValue) + length + 1;
27*627f7eb2Smrg 
28*627f7eb2Smrg     if (!npools || nfill + nbytes > POOL_SIZE)
29*627f7eb2Smrg     {
30*627f7eb2Smrg         pools = (uint8_t **)mem.xrealloc(pools, ++npools * sizeof(pools[0]));
31*627f7eb2Smrg         pools[npools - 1] = (uint8_t *)mem.xmalloc(nbytes > POOL_SIZE ? nbytes : POOL_SIZE);
32*627f7eb2Smrg         nfill = 0;
33*627f7eb2Smrg     }
34*627f7eb2Smrg 
35*627f7eb2Smrg     StringValue *sv = (StringValue *)&pools[npools - 1][nfill];
36*627f7eb2Smrg     sv->ptrvalue = ptrvalue;
37*627f7eb2Smrg     sv->length = length;
38*627f7eb2Smrg     ::memcpy(sv->lstring(), s, length);
39*627f7eb2Smrg     sv->lstring()[length] = 0;
40*627f7eb2Smrg 
41*627f7eb2Smrg     const uint32_t vptr = (uint32_t)(npools << POOL_BITS | nfill);
42*627f7eb2Smrg     nfill += nbytes + (-nbytes & 7); // align to 8 bytes
43*627f7eb2Smrg     return vptr;
44*627f7eb2Smrg }
45*627f7eb2Smrg 
getValue(uint32_t vptr)46*627f7eb2Smrg StringValue *StringTable::getValue(uint32_t vptr)
47*627f7eb2Smrg {
48*627f7eb2Smrg     if (!vptr) return NULL;
49*627f7eb2Smrg 
50*627f7eb2Smrg     const size_t idx = (vptr >> POOL_BITS) - 1;
51*627f7eb2Smrg     const size_t off = vptr & (POOL_SIZE - 1);
52*627f7eb2Smrg     return (StringValue *)&pools[idx][off];
53*627f7eb2Smrg }
54*627f7eb2Smrg 
nextpow2(size_t val)55*627f7eb2Smrg static size_t nextpow2(size_t val)
56*627f7eb2Smrg {
57*627f7eb2Smrg     size_t res = 1;
58*627f7eb2Smrg     while (res < val)
59*627f7eb2Smrg         res <<= 1;
60*627f7eb2Smrg     return res;
61*627f7eb2Smrg }
62*627f7eb2Smrg 
63*627f7eb2Smrg static const double loadFactor = 0.8;
64*627f7eb2Smrg 
_init(size_t size)65*627f7eb2Smrg void StringTable::_init(size_t size)
66*627f7eb2Smrg {
67*627f7eb2Smrg     size = nextpow2((size_t)(size / loadFactor));
68*627f7eb2Smrg     if (size < 32) size = 32;
69*627f7eb2Smrg     table = (StringEntry *)mem.xcalloc(size, sizeof(table[0]));
70*627f7eb2Smrg     tabledim = size;
71*627f7eb2Smrg     pools = NULL;
72*627f7eb2Smrg     npools = nfill = 0;
73*627f7eb2Smrg     count = 0;
74*627f7eb2Smrg }
75*627f7eb2Smrg 
reset(size_t size)76*627f7eb2Smrg void StringTable::reset(size_t size)
77*627f7eb2Smrg {
78*627f7eb2Smrg     for (size_t i = 0; i < npools; ++i)
79*627f7eb2Smrg         mem.xfree(pools[i]);
80*627f7eb2Smrg 
81*627f7eb2Smrg     mem.xfree(table);
82*627f7eb2Smrg     mem.xfree(pools);
83*627f7eb2Smrg     table = NULL;
84*627f7eb2Smrg     pools = NULL;
85*627f7eb2Smrg     _init(size);
86*627f7eb2Smrg }
87*627f7eb2Smrg 
~StringTable()88*627f7eb2Smrg StringTable::~StringTable()
89*627f7eb2Smrg {
90*627f7eb2Smrg     for (size_t i = 0; i < npools; ++i)
91*627f7eb2Smrg         mem.xfree(pools[i]);
92*627f7eb2Smrg 
93*627f7eb2Smrg     mem.xfree(table);
94*627f7eb2Smrg     mem.xfree(pools);
95*627f7eb2Smrg     table = NULL;
96*627f7eb2Smrg     pools = NULL;
97*627f7eb2Smrg }
98*627f7eb2Smrg 
findSlot(hash_t hash,const char * s,size_t length)99*627f7eb2Smrg size_t StringTable::findSlot(hash_t hash, const char *s, size_t length)
100*627f7eb2Smrg {
101*627f7eb2Smrg     // quadratic probing using triangular numbers
102*627f7eb2Smrg     // http://stackoverflow.com/questions/2348187/moving-from-linear-probing-to-quadratic-probing-hash-collisons/2349774#2349774
103*627f7eb2Smrg     for (size_t i = hash & (tabledim - 1), j = 1; ;++j)
104*627f7eb2Smrg     {
105*627f7eb2Smrg         StringValue *sv;
106*627f7eb2Smrg         if (!table[i].vptr ||
107*627f7eb2Smrg             (table[i].hash == hash &&
108*627f7eb2Smrg              (sv = getValue(table[i].vptr))->length == length &&
109*627f7eb2Smrg              ::memcmp(s, sv->lstring(), length) == 0))
110*627f7eb2Smrg             return i;
111*627f7eb2Smrg         i = (i + j) & (tabledim - 1);
112*627f7eb2Smrg     }
113*627f7eb2Smrg }
114*627f7eb2Smrg 
lookup(const char * s,size_t length)115*627f7eb2Smrg StringValue *StringTable::lookup(const char *s, size_t length)
116*627f7eb2Smrg {
117*627f7eb2Smrg     const hash_t hash = calcHash(s, length);
118*627f7eb2Smrg     const size_t i = findSlot(hash, s, length);
119*627f7eb2Smrg     // printf("lookup %.*s %p\n", (int)length, s, table[i].value ?: NULL);
120*627f7eb2Smrg     return getValue(table[i].vptr);
121*627f7eb2Smrg }
122*627f7eb2Smrg 
update(const char * s,size_t length)123*627f7eb2Smrg StringValue *StringTable::update(const char *s, size_t length)
124*627f7eb2Smrg {
125*627f7eb2Smrg     const hash_t hash = calcHash(s, length);
126*627f7eb2Smrg     size_t i = findSlot(hash, s, length);
127*627f7eb2Smrg     if (!table[i].vptr)
128*627f7eb2Smrg     {
129*627f7eb2Smrg         if (++count > tabledim * loadFactor)
130*627f7eb2Smrg         {
131*627f7eb2Smrg             grow();
132*627f7eb2Smrg             i = findSlot(hash, s, length);
133*627f7eb2Smrg         }
134*627f7eb2Smrg         table[i].hash = hash;
135*627f7eb2Smrg         table[i].vptr = allocValue(s, length, NULL);
136*627f7eb2Smrg     }
137*627f7eb2Smrg     // printf("update %.*s %p\n", (int)length, s, table[i].value ?: NULL);
138*627f7eb2Smrg     return getValue(table[i].vptr);
139*627f7eb2Smrg }
140*627f7eb2Smrg 
insert(const char * s,size_t length,void * ptrvalue)141*627f7eb2Smrg StringValue *StringTable::insert(const char *s, size_t length, void *ptrvalue)
142*627f7eb2Smrg {
143*627f7eb2Smrg     const hash_t hash = calcHash(s, length);
144*627f7eb2Smrg     size_t i = findSlot(hash, s, length);
145*627f7eb2Smrg     if (table[i].vptr)
146*627f7eb2Smrg         return NULL; // already in table
147*627f7eb2Smrg     if (++count > tabledim * loadFactor)
148*627f7eb2Smrg     {
149*627f7eb2Smrg         grow();
150*627f7eb2Smrg         i = findSlot(hash, s, length);
151*627f7eb2Smrg     }
152*627f7eb2Smrg     table[i].hash = hash;
153*627f7eb2Smrg     table[i].vptr = allocValue(s, length, ptrvalue);
154*627f7eb2Smrg     // printf("insert %.*s %p\n", (int)length, s, table[i].value ?: NULL);
155*627f7eb2Smrg     return getValue(table[i].vptr);
156*627f7eb2Smrg }
157*627f7eb2Smrg 
grow()158*627f7eb2Smrg void StringTable::grow()
159*627f7eb2Smrg {
160*627f7eb2Smrg     const size_t odim = tabledim;
161*627f7eb2Smrg     StringEntry *otab = table;
162*627f7eb2Smrg     tabledim *= 2;
163*627f7eb2Smrg     table = (StringEntry *)mem.xcalloc(tabledim, sizeof(table[0]));
164*627f7eb2Smrg 
165*627f7eb2Smrg     for (size_t i = 0; i < odim; ++i)
166*627f7eb2Smrg     {
167*627f7eb2Smrg         StringEntry *se = &otab[i];
168*627f7eb2Smrg         if (!se->vptr) continue;
169*627f7eb2Smrg         StringValue *sv = getValue(se->vptr);
170*627f7eb2Smrg         table[findSlot(se->hash, sv->lstring(), sv->length)] = *se;
171*627f7eb2Smrg     }
172*627f7eb2Smrg     mem.xfree(otab);
173*627f7eb2Smrg }
174*627f7eb2Smrg 
175*627f7eb2Smrg /********************************
176*627f7eb2Smrg  * Walk the contents of the string table,
177*627f7eb2Smrg  * calling fp for each entry.
178*627f7eb2Smrg  * Params:
179*627f7eb2Smrg  *      fp = function to call. Returns !=0 to stop
180*627f7eb2Smrg  * Returns:
181*627f7eb2Smrg  *      last return value of fp call
182*627f7eb2Smrg  */
apply(int (* fp)(StringValue *))183*627f7eb2Smrg int StringTable::apply(int (*fp)(StringValue *))
184*627f7eb2Smrg {
185*627f7eb2Smrg     for (size_t i = 0; i < tabledim; ++i)
186*627f7eb2Smrg     {
187*627f7eb2Smrg         StringEntry *se = &table[i];
188*627f7eb2Smrg         if (!se->vptr) continue;
189*627f7eb2Smrg         StringValue *sv = getValue(se->vptr);
190*627f7eb2Smrg         int result = (*fp)(sv);
191*627f7eb2Smrg         if (result)
192*627f7eb2Smrg             return result;
193*627f7eb2Smrg     }
194*627f7eb2Smrg     return 0;
195*627f7eb2Smrg }
196*627f7eb2Smrg 
197