aboutsummaryrefslogtreecommitdiff
path: root/include/base/macro/map.h
blob: d7b9e897e5d205f5f8f2edcf76a7592b63ab7c33 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
#pragma once

/*
 * Based on khash.h
 * Modified to make control more granular and similar to QSORT
 */

static const double HASHFILL = 0.77;

#define ROUNDUP32(x)                                                            \
  (--(x), (x) |= (x) >> 1, (x) |= (x) >> 2, (x) |= (x) >> 4, (x) |= (x) >> 8,   \
   (x) |= (x) >> 16, ++(x))

#define map·isempty(flag, i)  ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 2)
#define map·isdelete(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 1)
#define map·iseither(flag, i) ((flag[i >> 4] >> ((i & 0xfU) << 1)) & 3)
#define map·setnodelete(flag, i)                                                \
  (flag[i >> 4] &= ~(1ul << ((i & 0xfU) << 1)))
#define map·setnoteither(flag, i)                                               \
  (flag[i >> 4] &= ~(2ul << ((i & 0xfU) << 1)))
#define map·setnotboth(flag, i)                                                 \
  (flag[i >> 4] &= ~(3ul << ((i & 0xfU) << 1)))
#define map·setdelete(flag, i) (flag[i >> 4] |= 1ul << ((i & 0xfU) << 1))

#define map·flagsize(m) ((m) < 16 ? 1 : (m) >> 4)
#define map·fill(m, x) (!map·iseither((m)->flag, (x)))

/* map types */
#define MAP_STRUCT_BODY(key_t, val_t)                                          \
  int32 cap, len, occ, fill;                                                   \
  int32  *flag;                                                                \
  key_t *key;                                                                  \
  val_t *val

#define MAP_MAKE(type, h, alloc)                                               \
  type *map = alloc((h), 1, sizeof(*map));                                     \
  return map

#define MAP_FREE(map, mem, heap)                                               \
  (mem).free((heap), (map)->key);                                              \
  (mem).free((heap), (map)->flag);                                             \
  (mem).free((heap), (map)->val);                                              \
  (mem).free((heap), (map));

#define MAP_RESET(map)                                                         \
  if((map) && (map)->flag){                                                    \
    memset((map)->flag, 0xAA, map·flagsize((map)->cap)*sizeof(int32));         \
    (map)->len = (map)->occ = 0;                                               \
  }

#define MAP_GET(i, map, key, hashfunc, equalfunc)                              \
  int32 k, last, mask, step;                                                   \
  if((map)->cap){                                                              \
    k    = 0;                                                                  \
    i    = 0;                                                                  \
    last = 0;                                                                  \
    mask = 0;                                                                  \
    step = 0;                                                                  \
    mask = (map)->cap - 1;                                                     \
    k    = hashfunc((key));                                                    \
    i    = k & mask;                                                           \
    last = i;                                                                  \
    while(!map·isempty((map)->flag, i) &&                                      \
          (map·isdelete((map)->flag, i) || !equalfunc((map)->key[i], (key)))){ \
      i = (i + (++step)) & mask;                                               \
      if(i == last){                                                           \
        i = (map)->cap;                                                        \
        break;                                                                 \
      }                                                                        \
    }                                                                          \
    if(i < (map)->cap && map·iseither((map)->flag, i))                         \
        i = (map)->cap;                                                        \
  }else                                                                        \
    i = 0;

#define MAP_GROW(map, key_t, val_t, newcap, hashfunc, mem, heap)               \
  int32 *new_flags = nil;                                                      \
  int32 j = 1;                                                                 \
  {                                                                            \
    ROUNDUP32(newcap);                                                         \
    if(newcap < 4)                                                             \
      newcap = 4;                                                              \
    if((map)->len >= (int32)(newcap * HASHFILL + 0.5))                         \
      j = 0;                                                                   \
    else{                                                                      \
      new_flags = (mem).alloc((heap), map·flagsize(newcap), sizeof(int32));    \
      if(!new_flags) return -1;                                                \
      memset(new_flags, 0xaa, map·flagsize(newcap) * sizeof(int32));           \
      if((map)->cap < newcap){ /* expand */                                    \
        key_t *new_keys = (mem).alloc((heap), newcap, sizeof(key_t));          \
        if(!new_keys){                                                         \
          (mem).free((heap), new_flags);                                       \
          return -1;                                                           \
        }                                                                      \
        memcpy(new_keys, (map)->key, sizeof(key_t) * (map)->cap);              \
        (mem).free((heap), (map)->key);                                        \
        (map)->key = new_keys;                                                 \
        val_t *new_vals = (mem).alloc((heap), newcap, sizeof(val_t));          \
        if(!new_vals){                                                         \
          (mem).free((heap), new_flags);                                       \
          return -1;                                                           \
        }                                                                      \
        memcpy(new_vals, (map)->val, sizeof(val_t) * (map)->cap);              \
        (mem).free((heap), (map)->val);                                        \
        (map)->val = new_vals;                                                 \
      }                                                                        \
    }                                                                          \
  }                                                                            \
  if(j){ /* rehashing is needed */                                             \
    for(j = 0; j != (map)->cap; ++j){                                          \
      if(map·iseither((map)->flag, j) == 0){                                   \
        key_t key = (map)->key[j];                                             \
        val_t val;                                                             \
        int32 new_mask;                                                        \
        new_mask = newcap - 1;                                                 \
        val = (map)->val[j];                                                   \
        map·setdelete((map)->flag, j);                                         \
        while(1){                                                              \
          int32 k, i, step = 0;                                                \
          k = hashfunc(key);                                                   \
          i = k & new_mask;                                                    \
          while (!map·isempty(new_flags, i))                                   \
            i = (i + (++step)) & new_mask;                                     \
          map·setnoteither(new_flags, i);                                      \
          if(i < (map)->cap && map·iseither((map)->flag, i) == 0) {            \
            {                                                                  \
              key_t tmp = (map)->key[i];                                       \
              (map)->key[i] = key;                                             \
              key = tmp;                                                       \
            }                                                                  \
            {                                                                  \
              val_t tmp = (map)->val[i];                                       \
              (map)->val[i] = val;                                             \
              val = tmp;                                                       \
            }                                                                  \
            map·setdelete((map)->flag, i);                                     \
          }else{                                                               \
            (map)->key[i] = key;                                               \
            (map)->val[i] = val;                                               \
            break;                                                             \
          }                                                                    \
        }                                                                      \
      }                                                                        \
    }                                                                          \
    if((map)->cap > newcap){ /* shrink the hash table */                       \
      key_t *new_keys = (mem).alloc((heap), newcap, sizeof(key_t));            \
      memcpy(new_keys, (map)->key, sizeof(key_t) * (map)->cap);                \
      (mem).free((heap), (map)->key);                                          \
      (map)->key = new_keys;                                                   \
                                                                               \
      val_t *new_vals = (mem).alloc((heap), newcap, sizeof(val_t));            \
      memcpy(new_vals, (map)->val, sizeof(val_t) * (map)->cap);                \
      (mem).free((heap), (map)->val);                                          \
      (map)->val = new_vals;                                                   \
    }                                                                          \
    (mem).free((heap), (map)->flag); /* free the working space */              \
    (map)->flag      = new_flags;                                              \
    (map)->cap  = newcap;                                                      \
    (map)->occ = (map)->len;                                                   \
    (map)->fill = (int32)((map)->cap * HASHFILL + 0.5);                        \
  }                                                                            \
  return 0;

#define MAP_PUT(map, key, hashfunc, equalfunc, resizefunc, err)                \
    int32 x = 0;                                                               \
    if(map->occ >= map->fill){                                                 \
      if(map->cap > (map->len << 1)){                                          \
        if(resizefunc(map, map->cap - 1) < 0){                                 \
          *err = -1;                                                           \
          return map->cap;                                                     \
        }                                                                      \
      }else if(resizefunc(map, map->cap + 1) < 0){                             \
        *err = -1;                                                             \
        return map->cap;                                                       \
      }                                                                        \
    }                                                                          \
                                                                               \
    {                                                                          \
      int32 k, i, site, last, mask = map->cap - 1, step = 0;                   \
      x = site = map->cap;                                                     \
      k = hashfunc((key));                                                     \
      i = k & mask;                                                            \
      if(map·isempty(map->flag, i))                                            \
        x = i; /* for speed up */                                              \
      else{                                                                    \
        last = i;                                                              \
        while(!map·isempty(map->flag, i) &&                                    \
              (map·isdelete(map->flag, i) || !equalfunc(map->key[i], (key)))){ \
          if(map·isdelete(map->flag, i))                                       \
            site = i;                                                          \
          i = (i + (++step)) & mask;                                           \
          if(i == last){                                                       \
            x = site;                                                          \
            break;                                                             \
          }                                                                    \
        }                                                                      \
        if(x == map->cap){                                                     \
          if(map·isempty(map->flag, i) && site != map->cap)                    \
            x = site;                                                          \
          else                                                                 \
            x = i;                                                             \
        }                                                                      \
      }                                                                        \
    }                                                                          \
    if(map·isempty(map->flag, x)){ /* not present at all */                    \
      map->key[x] = (key);                                                     \
      map·setnotboth(map->flag, x);                                            \
      ++map->len;                                                              \
      ++map->occ;                                                              \
      *err = 1;                                                                \
    }else if(map·isdelete(map->flag, x)){ /* deleted */                        \
      map->key[x] = (key);                                                     \
      map·setnotboth(map->flag, x);                                            \
      ++map->len;                                                              \
    }else                                                                      \
      *err = 0;                                                                \
    return x;

#define MAP_DEL(map, x)                                                        \
    if(x != map->cap && !map·iseither(map->flag, x)){                          \
      map·setdelete(map->flag, x);                                             \
      --map->len;                                                              \
    }

/* set macro */

#define SET_STRUCT_BODY(key_t)                                                 \
  int32 cap, len, occ, fill;                                                   \
  int32 *flag;                                                                 \
  key_t *key                                                                   \

#define SET_MAKE(type, h, alloc)                                               \
  type *set = alloc((h), 1, sizeof(*set));                                     \
  return set

#define SET_FREE(set, mem, heap)                                               \
  (mem).free((heap), (set)->key);                                              \
  (mem).free((heap), (set)->flag);                                             \
  (mem).free((heap), (set))

#define SET_RESET(set)                                                         \
  if ((set) && (set)->flag) {                                                  \
    memset((set)->flag, 0xAA, map·flagsize((set)->cap) * sizeof(int32));       \
    (set)->len = (set)->occ = 0;                                               \
  }

#define SET_GET(i, set, key, hashfunc, equalfunc )                             \
  int32 k, last, mask, step;                                                   \
  if((set)->cap){                                                              \
    k    = 0;                                                                  \
    i    = 0;                                                                  \
    last = 0;                                                                  \
    mask = 0;                                                                  \
    step = 0;                                                                  \
    mask = (set)->cap - 1;                                                     \
    k    = hashfunc((key));                                                    \
    i    = k & mask;                                                           \
    last = i;                                                                  \
    while(!map·isempty((set)->flag, i) &&                                      \
          (map·isdelete((set)->flag, i) || !equalfunc((set)->key[i], (key)))){ \
      i = (i + (++step)) & mask;                                               \
      if(i == last){                                                           \
        i = (set)->cap;                                                        \
        break;                                                                 \
      }                                                                        \
    }                                                                          \
    if(i < (set)->cap && map·iseither((set)->flag, i))                         \
        i = (set)->cap;                                                        \
  }else                                                                        \
    i = 0;

#define SET_GROW(set, key_t, newcap, hashfunc, mem, heap)                      \
  int32 *new_flags = nil;                                                      \
  int32 j = 1;                                                                 \
  {                                                                            \
    ROUNDUP32(newcap);                                                         \
    if(newcap < 4)                                                             \
      newcap = 4;                                                              \
    if((set)->len >= (int32)(newcap * HASHFILL + 0.5))                         \
      j = 0;                                                                   \
    else{                                                                      \
      new_flags = mem.alloc((heap), map·flagsize(newcap), sizeof(int32));      \
      if(!new_flags) return -1;                                                \
      memset(new_flags, 0xaa, map·flagsize(newcap) * sizeof(int32));           \
      if((set)->cap < newcap) { /* expand */                                   \
        key_t *new_keys = mem.alloc((heap), newcap, sizeof(key_t));            \
        if(!new_keys){                                                         \
          mem.free((heap), new_flags);                                         \
          return -1;                                                           \
        }                                                                      \
        memcpy(new_keys, (set)->key, sizeof(key_t) * (set)->cap);              \
        mem.free((heap), (set)->key);                                          \
        (set)->key = new_keys;                                                 \
      }                                                                        \
    }                                                                          \
  }                                                                            \
  if(j){ /* rehashing is needed */                                             \
    for(j = 0; j != (set)->cap; ++j) {                                         \
      if(map·iseither((set)->flag, j) == 0) {                                  \
        key_t key = (set)->key[j];                                             \
        int32 new_mask;                                                        \
        new_mask = newcap - 1;                                                 \
        map·setdelete((set)->flag, j);                                         \
        while(1){                                                              \
          int32 k, i, step = 0;                                                \
          k = hashfunc(key);                                                   \
          i = k & new_mask;                                                    \
          while(!map·isempty(new_flags, i))                                    \
            i = (i + (++step)) & new_mask;                                     \
          map·setnoteither(new_flags, i);                                      \
          if(i < (set)->cap && map·iseither((set)->flag, i) == 0) {            \
            {                                                                  \
              key_t tmp = (set)->key[i];                                       \
              (set)->key[i] = key;                                             \
              key = tmp;                                                       \
            }                                                                  \
            map·setdelete((set)->flag, i);                                     \
          }else{                                                               \
            (set)->key[i] = key;                                               \
            break;                                                             \
          }                                                                    \
        }                                                                      \
      }                                                                        \
    }                                                                          \
    if((set)->cap > newcap) { /* shrink the hash table */                      \
      key_t *new_keys = mem.alloc((heap), newcap, sizeof(key_t));              \
      memcpy(new_keys, (set)->key, sizeof(key_t) * (set)->cap);                \
      mem.free((heap), (set)->key);                                            \
      (set)->key = new_keys;                                                   \
    }                                                                          \
    mem.free((heap), (set)->flag); /* free the working space */                \
    (set)->flag      = new_flags;                                              \
    (set)->cap  = newcap;                                                      \
    (set)->occ = (set)->len;                                                   \
    (set)->fill = (int32)((set)->cap * HASHFILL + 0.5);                        \
  }                                                                            \
  return 0;

#define SET_PUT(set, key, hashfunc, equalfunc, resizefunc, err)                \
    int32 x = 0;                                                               \
    if((set)->occ >= (set)->fill){                                             \
      if((set)->cap > ((set)->len << 1)){                                      \
        if(resizefunc((set), (set)->cap - 1) < 0){                             \
          *err = -1;                                                           \
          return (set)->cap;                                                   \
        }                                                                      \
      }else if(resizefunc((set), (set)->cap + 1) < 0){                         \
        *err = -1;                                                             \
        return (set)->cap;                                                     \
      }                                                                        \
    }                                                                          \
                                                                               \
    {                                                                          \
      int32 k, i, site, last, mask = (set)->cap - 1, step = 0;                 \
      x = site = (set)->cap;                                                   \
      k = hashfunc((key));                                                     \
      i = k & mask;                                                            \
      if(map·isempty((set)->flag, i))                                          \
        x = i; /* for speed up */                                              \
      else{                                                                    \
        last = i;                                                              \
        while(!map·isempty((set)->flag, i) &&                                  \
           (map·isdelete((set)->flag, i) || !equalfunc((set)->key[i], (key)))){\
          if(map·isdelete((set)->flag, i))                                     \
            site = i;                                                          \
          i = (i + (++step)) & mask;                                           \
          if(i == last) {                                                      \
            x = site;                                                          \
            break;                                                             \
          }                                                                    \
        }                                                                      \
        if(x == (set)->cap){                                                   \
          if(map·isempty((set)->flag, i) && site != (set)->cap)                \
            x = site;                                                          \
          else                                                                 \
            x = i;                                                             \
        }                                                                      \
      }                                                                        \
    }                                                                          \
    if(map·isempty((set)->flag, x)) { /* not present at all */                 \
      (set)->key[x] = (key);                                                   \
      map·setnotboth((set)->flag, x);                                          \
      ++(set)->len;                                                            \
      ++(set)->occ;                                                            \
      *err = 1;                                                                \
    }else if(map·isdelete((set)->flag, x)){ /* deleted */                      \
      (set)->key[x] = (key);                                                   \
      map·setnotboth((set)->flag, x);                                          \
      ++(set)->len;                                                            \
    }else                                                                      \
      *err = 0;                                                                \
    return x

#define SET_DEL(set, x)                                                        \
    if(x != (set)->cap && !map·iseither((set)->flag, x)) {                     \
      map·setdelete((set)->flag, x);                                           \
      --(set)->len;                                                            \
    }