source: git/ppcc/adlib/map.h @ 54b24c

spielwiese
Last change on this file since 54b24c was 54b24c, checked in by Reimer Behrends <behrends@…>, 5 years ago
Finalizing thread support.
  • Property mode set to 100644
File size: 11.2 KB
Line 
1#pragma once
2
3#include "lib.h"
4
5// Note: this is not an enum. A low bit of 0 indicates a value of either
6// SLOT_EMPTY or SLOT_OCCUPIED. A low bit of 1 (== SLOT_OCCUPIED)
7// indicates that the top bits contain an abbreviated hash value.
8
9#define SLOT_EMPTY 0
10#define SLOT_OCCUPIED 1
11#define SLOT_DELETED 2
12
13template <typename K, typename V>
14struct Assoc : public GC {
15  K key;
16  V value;
17};
18
19template <typename K, typename V>
20class Map : public GC {
21  template <typename K2, typename V2>
22  friend class Map;
23private:
24  static const Int _minsize = 8;
25  Int _count;
26  Int _size;
27  Int _deleted;
28  CmpFunc(K, _cmp);
29  HashFunc(K, _hash);
30  K *_keys;
31  V *_values;
32  // The _state array contains either SLOT_EMPTY, SLOT_DELETED or
33  // an abbreviated hash value with the lowest bit (SLOT_OCCUPIED)
34  // set. Rather than storing the entire hash value, we only store
35  // 7 bits of it, expecting this to still eliminate 99% of calls
36  // to the compare function.
37  Byte *_state;
38  void resize(Int newsize) {
39    _keys = (K *) GC_MALLOC(newsize * sizeof(K));
40    _values = (V *) GC_MALLOC(newsize * sizeof(V));
41    _state = (Byte *) GC_MALLOC_ATOMIC(newsize);
42    memset(_state, SLOT_EMPTY, newsize);
43    _size = newsize;
44  }
45  void uncheckedAdd(K key, V value, bool replace = false);
46  void rebuild();
47  Word next(Word pos, Word hash) {
48    return (pos - hash) * 5 + 1 + hash;
49  }
50
51public:
52  class Each {
53  private:
54    Map *_map;
55    Int _i;
56    void skip() {
57      while (_i < _map->_size && (_map->_state[_i] & SLOT_OCCUPIED) == 0)
58        _i++;
59    }
60
61  public:
62    Each(Map *map) {
63      _map = map;
64      _i = 0;
65      skip();
66    }
67    operator bool() {
68      return _i < _map->_size;
69    }
70    void operator++() {
71      _i++;
72      skip();
73    }
74    void operator++(int dummy) {
75      _i++;
76      skip();
77    }
78    K &key() {
79      return _map->_keys[_i];
80    }
81    V &value() {
82      return _map->_values[_i];
83    }
84    Assoc<K, V> pair() {
85      Assoc<K, V> assoc;
86      assoc.key = _map->_keys[_i];
87      assoc.value = _map->_values[_i];
88      return assoc;
89    }
90  };
91  Map(CmpFunc(K, cmp), HashFunc(K, hash));
92  Map();
93  Map(Map<K, V> *map, bool copy = true);
94  Map(Arr<K> *keys, Arr<V> *values);
95  Map(Arr<K> *keys, Arr<V> *values, CmpFunc(K, cmp), HashFunc(K, hash));
96  Map<K, V> *clone() {
97    return new Map(this);
98  }
99  Int count() {
100    return _count;
101  }
102  Map<K, V> *add(K key, V value, bool replace = false);
103  Map<K, V> *add(Assoc<K, V> assoc, bool replace = false) {
104    add(assoc.key, assoc.value, replace);
105    return this;
106  }
107  Map<K, V> *add(Arr<Assoc<K, V> > *arr, bool replace = false);
108  Map<K, V> *add(Arr<K> *keys, Arr<V> *values, bool replace = false);
109  bool remove(K key);
110  bool contains(K key);
111  bool find(K key, V &value);
112  V get(K key, V if_absent);
113  V get(K key);
114  V at(K key);
115  Arr<K> *keys();
116  Arr<V> *values();
117  Arr<Assoc<K, V> > *pairs();
118  bool eq(Map<K, V> *that);
119  Map<K, V> *union_with(Map<K, V> *that, bool replace = false);
120  Map<K, V> *union_in_place(Map<K, V> *that, bool replace = false);
121  Map<K, V> *intersect_with(Map<K, V> *that);
122  Map<K, V> *intersect_in_place(Map<K, V> *that);
123  Map<K, V> *diff_with(Map<K, V> *that);
124  Map<K, V> *diff_in_place(Map<K, V> *that);
125  template <typename A, typename F>
126  A fold(A init, F foldfunc);
127  template <typename V2, typename F>
128  Map<K, V2> *map_values(Map<K, V2> *into, F mapfunc);
129  template <typename K2, typename V2, typename F, typename G>
130  Map<K2, V2> *map_pairs(Map<K2, V2> *into, F mapfunc, G mapfunc2);
131  template <typename F>
132  Map<K, V> *filter(F filterfunc);
133  template <typename F>
134  void iter(F iterfunc);
135};
136
137template <typename K, typename V>
138void Map<K, V>::rebuild() {
139  Int size = _size;
140  Int newsize = nextPow2(_count * 2);
141  if (newsize < _minsize)
142    newsize = _minsize;
143  K *keys = _keys;
144  V *values = _values;
145  Byte *state = _state;
146  _count = 0;
147  _deleted = 0;
148  resize(newsize);
149  for (Int i = 0; i < size; i++) {
150    if (state[i] & SLOT_OCCUPIED)
151      uncheckedAdd(keys[i], values[i]);
152  }
153}
154
155template <typename K, typename V>
156Map<K, V>::Map(CmpFunc(K, cmp), HashFunc(K, hash)) {
157  resize(_minsize);
158  _count = 0;
159  _deleted = 0;
160  _cmp = cmp;
161  _hash = hash;
162}
163
164template <typename K, typename V>
165Map<K, V>::Map() {
166  resize(_minsize);
167  _count = 0;
168  _deleted = 0;
169  _cmp = Cmp;
170  _hash = Hash;
171}
172
173template <typename K, typename V>
174Map<K, V>::Map(Arr<K> *keys, Arr<V> *values) {
175  resize(_minsize);
176  _count = 0;
177  _deleted = 0;
178  _cmp = Cmp;
179  _hash = Hash;
180  add(keys, values);
181}
182
183template <typename K, typename V>
184Map<K, V>::Map(
185    Arr<K> *keys, Arr<V> *values, CmpFunc(K, cmp), HashFunc(K, hash)) {
186  resize(_minsize);
187  _count = 0;
188  _deleted = 0;
189  _cmp = cmp;
190  _hash = hash;
191  add(keys, values);
192}
193
194template <typename K, typename V>
195Map<K, V>::Map(Map<K, V> *map, bool copy) {
196  _cmp = map->_cmp;
197  _hash = map->_hash;
198  if (copy) {
199    resize(map->_size);
200    memcpy(_keys, map->_keys, sizeof(K) * _size);
201    memcpy(_values, map->_values, sizeof(V) * _size);
202    memcpy(_state, map->_state, _size);
203    _count = map->_count;
204    _deleted = map->_deleted;
205  } else {
206    resize(_minsize);
207    _count = 0;
208    _deleted = 0;
209  }
210}
211
212#define INIT_HASH_LOOP(key) \
213  Word mask = _size - 1; \
214  Word hash = _hash(key); \
215  Word pos = hash & mask; \
216  Byte occ = FibHash(hash, 8) | SLOT_OCCUPIED
217
218template <typename K, typename V>
219void Map<K, V>::uncheckedAdd(K key, V value, bool replace) {
220  INIT_HASH_LOOP(key);
221  Int freepos = -1;
222  while (_state[pos] != SLOT_EMPTY) {
223    if (_state[pos] == occ && _cmp(_keys[pos], key) == 0) {
224      if (replace) {
225        _keys[pos] = key;
226        _values[pos] = value;
227      }
228      return;
229    }
230    if (_state[pos] == SLOT_DELETED && freepos < 0)
231      freepos = pos;
232    pos = next(pos, hash) & mask;
233  }
234  if (freepos >= 0) {
235    _deleted--;
236    pos = freepos;
237  }
238  _keys[pos] = key;
239  _values[pos] = value;
240  _state[pos] = occ;
241  _count++;
242}
243
244template <typename K, typename V>
245Map<K, V> *Map<K, V>::add(K key, V value, bool replace) {
246  if ((_count + _deleted) * 3 / 2 >= _size)
247    rebuild();
248  uncheckedAdd(key, value, replace);
249  return this;
250}
251
252template <typename K, typename V>
253Map<K, V> *Map<K, V>::add(Arr<Assoc<K, V> > *arr, bool replace) {
254  for (Int i = 0; i < arr->len(); i++)
255    add(arr->at(i));
256  return this;
257}
258
259template <typename K, typename V>
260Map<K, V> *Map<K, V>::add(Arr<K> *keys, Arr<V> *values, bool replace) {
261  require(keys->len() == values->len(), "mismatched array sizes");
262  for (Int i = 0; i < keys->len(); i++) {
263    add(keys->at(i), values->at(i));
264  }
265  return this;
266}
267
268template <typename K, typename V>
269bool Map<K, V>::remove(K key) {
270  INIT_HASH_LOOP(key);
271  while (_state[pos] != SLOT_EMPTY) {
272    if (_state[pos] == occ && _cmp(_keys[pos], key) == 0) {
273      memset(_keys + pos, 0, sizeof(K));
274      memset(_values + pos, 0, sizeof(V));
275      _state[pos] = SLOT_DELETED;
276      _count--;
277      _deleted++;
278      if ((_count + _deleted) * 3 / 2 > _size || _deleted >= _count)
279        rebuild();
280      return 1;
281    }
282    pos = next(pos, hash) & mask;
283  }
284  return 0;
285}
286
287template <typename K, typename V>
288bool Map<K, V>::find(K key, V &value) {
289  INIT_HASH_LOOP(key);
290  while (_state[pos] != SLOT_EMPTY) {
291    if (_state[pos] == occ && _cmp(_keys[pos], key) == 0) {
292      value = _values[pos];
293      return true;
294    }
295    pos = next(pos, hash) & mask;
296  }
297  return false;
298}
299
300template <typename K, typename V>
301V Map<K, V>::get(K key, V if_absent) {
302  V result;
303  if (find(key, result))
304    return result;
305  else
306    return if_absent;
307}
308
309template <typename K, typename V>
310V Map<K, V>::get(K key) {
311  V result;
312  if (find(key, result))
313    return result;
314  memset(result, 0, sizeof(V));
315  return result;
316}
317
318template <typename K, typename V>
319V Map<K, V>::at(K key) {
320  V result;
321  require(find(key, result), "key not found");
322  return result;
323}
324
325template <typename K, typename V>
326bool Map<K, V>::contains(K key) {
327  V value;
328  return find(key, value);
329}
330
331template <typename K, typename V>
332Arr<K> *Map<K, V>::keys() {
333  Arr<K> *result = new Arr<K>(_count);
334  for (Int i = 0; i < _size; i++) {
335    if (_state[i] == SLOT_OCCUPIED)
336      result->add(_keys[i]);
337  }
338  return result;
339}
340
341template <typename K, typename V>
342Arr<V> *Map<K, V>::values() {
343  Arr<V> *result = new Arr<V>(_count);
344  for (Int i = 0; i < _size; i++) {
345    if (_state[i] == SLOT_OCCUPIED)
346      result->add(_values[i]);
347  }
348  return result;
349}
350
351template <typename K, typename V>
352Arr<Assoc<K, V> > *Map<K, V>::pairs() {
353  Arr<Assoc<K, V> > *result = new Arr<Assoc<K, V> >(_count);
354  for (Int i = 0; i < _size; i++) {
355    if (_state[i] == SLOT_OCCUPIED) {
356      Assoc<K, V> m;
357      m.key = _keys[i];
358      m.value = _values[i];
359      result->add(m);
360    }
361  }
362  return result;
363}
364
365template <typename K, typename V>
366Map<K, V> *Map<K, V>::union_in_place(Map<K, V> *that, bool replace) {
367  for (Each it(that); it; it++) {
368    add(it.key(), it.value(), replace);
369  }
370  return this;
371}
372
373template <typename K, typename V>
374Map<K, V> *Map<K, V>::union_with(Map<K, V> *that, bool replace) {
375  return clone()->union_in_place(that, replace);
376}
377
378template <typename K, typename V>
379Map<K, V> *Map<K, V>::diff_in_place(Map<K, V> *that) {
380  for (Each it(that); it; it++) {
381    remove(it.key());
382  }
383  return this;
384}
385
386template <typename K, typename V>
387Map<K, V> *Map<K, V>::diff_with(Map<K, V> *that) {
388  return clone()->diff_in_place(that);
389}
390
391template <typename K, typename V>
392Map<K, V> *Map<K, V>::intersect_with(Map<K, V> *that) {
393  Map<K, V> *result = new Map<K, V>(_cmp, _hash);
394  for (Each it(this); it; it++) {
395    if (that->contains(it.key()))
396      result->add(it.key(), it.value());
397  }
398  return result;
399}
400
401template <typename K, typename V>
402Map<K, V> *Map<K, V>::intersect_in_place(Map<K, V> *that) {
403  Map<K, V> *tmp = intersect_with(that);
404  *this = *tmp;
405  return this;
406}
407
408template <typename K, typename V>
409bool Map<K, V>::eq(Map<K, V> *that) {
410  // FIXME: compare values
411  if (_count != that->_count)
412    return false;
413  for (Each it(this); it; it++) {
414    if (!that->contains(it.key()))
415      return false;
416  }
417  return true;
418}
419
420template <typename K, typename V>
421template <typename A, typename F>
422A Map<K, V>::fold(A init, F foldfunc) {
423  A result = init;
424  for (Each it(this); it; it++) {
425    result = foldfunc(result, it.key(), it.value());
426  }
427  return result;
428}
429
430template <typename K, typename V>
431template <typename V2, typename F>
432Map<K, V2> *Map<K, V>::map_values(Map<K, V2> *into, F mapfunc) {
433  for (Each it(this); it; it++) {
434    into->add(it.key(), mapfunc(it.value()));
435  }
436  return into;
437}
438
439template <typename K, typename V>
440template <typename K2, typename V2, typename F, typename G>
441Map<K2, V2> *Map<K, V>::map_pairs(Map<K2, V2> *into, F mapfunc, G mapfunc2) {
442  for (Each it(this); it; it++) {
443    into->add(mapfunc(it.key()), mapfunc2(it.value()));
444  }
445  return into;
446}
447
448template <typename K, typename V>
449template <typename F>
450Map<K, V> *Map<K, V>::filter(F filterfunc) {
451  Map<K, V> *result = new Map<K, V>(_cmp, _hash);
452  for (Each it(this); it; it++) {
453    if (filterfunc(it.key(), it.value()))
454      result->add(it.key(), it.value());
455  }
456  return result;
457}
458
459template <typename K, typename V>
460template <typename F>
461void Map<K, V>::iter(F iterfunc) {
462  for (Each it(this); it; it++) {
463    iterfunc(*it);
464  }
465}
466
467typedef Map<Str *, Str *> Dict;
468
469#undef SLOT_EMPTY
470#undef SLOT_OCCUPIED
471#undef SLOT_DELETED
472
473#undef INIT_HASH_LOOP
Note: See TracBrowser for help on using the repository browser.