]> www.ginac.de Git - cln.git/blob - src/base/hash/cl_hash2.h
Fix compilation with clang.
[cln.git] / src / base / hash / cl_hash2.h
1 // Hash tables with 2 keys and a value
2
3 #ifndef _CL_HASH2_H
4 #define _CL_HASH2_H
5
6 #include "base/hash/cl_hash.h"
7 #include "base/cl_iterator.h"
8
9 namespace cln {
10
11 // Requirements:
12 // - function  bool equal (key1_type,key1_type);
13 // - function  bool equal (key2_type,key2_type);
14 // - function  unsigned long hashcode (key1_type,key2_type);
15
16 template <class key1_type, class key2_type, class value_type>
17 struct cl_htentry2 {
18     ALLOCATE_ANYWHERE(cl_htentry2)
19     key1_type key1;
20     key2_type key2;
21     value_type val;
22     const value_type& htvalue () { return val; }
23     cl_htentry2 (const key1_type& k1, const key2_type& k2, const value_type& v)
24         : key1 (k1), key2 (k2), val (v) {}
25 #if (defined(__rs6000__) && !defined(__GNUC__))
26     cl_htentry2 () {}
27 #endif
28 };
29
30 template <class key1_type, class key2_type, class value_type>
31 struct cl_heap_hashtable_2 : public cl_heap_hashtable <cl_htentry2 <key1_type,key2_type,value_type> > {
32 protected:
33     // Abbreviations.
34     typedef cl_heap_hashtable <cl_htentry2 <key1_type,key2_type,value_type> > inherited;
35     typedef typename inherited::htxentry htxentry;
36 public:
37     // Allocation.
38     void* operator new (size_t size) { return malloc_hook(size); }
39     // Deallocation.
40     void operator delete (void* ptr) { free_hook(ptr); }
41 public:
42     // Lookup (htref alias gethash).
43     // Returns a pointer which you should immediately dereference
44     // if it is not NULL.
45     value_type* get (const key1_type& key1, const key2_type& key2)
46     {
47         var long index = this->_slots[hashcode(key1,key2) % this->_modulus] - 1;
48         while (index >= 0) {
49             if (!(index < this->_size))
50                 throw runtime_exception();
51             if (equal(key1,this->_entries[index].entry.key1)
52                 && equal(key2,this->_entries[index].entry.key2))
53                 return &this->_entries[index].entry.val;
54             index = this->_entries[index].next - 1;
55         }
56         return NULL;
57     }
58     // Store (htset alias puthash).
59     void put (const key1_type& key1, const key2_type& key2, const value_type& val)
60     {
61         var unsigned long hcode = hashcode(key1,key2);
62         // Search whether it is already there.
63         {
64             var long index = this->_slots[hcode % this->_modulus] - 1;
65             while (index >= 0) {
66                 if (!(index < this->_size))
67                     throw runtime_exception();
68                 if (equal(key1,this->_entries[index].entry.key1)
69                     && equal(key2,this->_entries[index].entry.key2)) {
70                     this->_entries[index].entry.val = val;
71                     return;
72                 }
73                 index = this->_entries[index].next - 1;
74             }
75         }
76         // Put it into the table.
77         prepare_store();
78         var long hindex = hcode % this->_modulus; // _modulus may have changed!
79         var long index = this->get_free_index();
80         new (&this->_entries[index].entry) cl_htentry2<key1_type,key2_type,value_type> (key1,key2,val);
81         this->_entries[index].next = this->_slots[hindex];
82         this->_slots[hindex] = 1+index;
83         this->_count++;
84     }
85     // Remove (htrem alias remhash).
86     void remove (const key1_type& key1, const key2_type& key2)
87     {
88         var long* _index = &this->_slots[hashcode(key1,key2) % this->_modulus];
89         while (*_index > 0) {
90             var long index = *_index - 1;
91             if (!(index < this->_size))
92                 throw runtime_exception();
93             if (equal(key1,this->_entries[index].entry.key1)
94                 && equal(key2,this->_entries[index].entry.key2)) {
95                 // Remove _entries[index].entry
96                 *_index = this->_entries[index].next;
97                 this->_entries[index].~htxentry();
98                 // The entry is now free.
99                 this->put_free_index(index);
100                 // That's it.
101                 this->_count--;
102                 return;
103             }
104             _index = &this->_entries[index].next;
105         }
106     }
107     // Iterate through the table.
108     // No stuff should be inserted into the table during the iteration,
109     // or you may find yourself iterating over an entry vector which has
110     // already been freed!
111     // ??
112 private:
113     // Prepare a store operation: make sure that the free list is non-empty.
114     // This may change the table's size!
115     void prepare_store ()
116     {
117       #if !(defined(__sparc__) && !defined(__GNUC__))
118         if (this->_freelist < -1)
119             return;
120         // Can we make room?
121         if (this->_garcol_fun(this))
122             if (this->_freelist < -1)
123                 return;
124         // No! Have to grow the hash table.
125         grow();
126       #else
127         // workaround Sun C++ 4.1 inline function compiler bug
128         if (this->_freelist >= -1) {
129             if (!this->_garcol_fun(this) || (this->_freelist >= -1))
130                 grow();
131         }
132       #endif
133     }
134     void grow ()
135     {
136         var long new_size = this->_size + (this->_size >> 1) + 1; // _size*1.5
137         var long new_modulus = inherited::compute_modulus(new_size);
138         var void* new_total_vector = malloc_hook(new_modulus*sizeof(long) + new_size*sizeof(htxentry));
139         var long* new_slots = (long*) ((char*)new_total_vector + 0);
140         var htxentry* new_entries = (htxentry *) ((char*)new_total_vector + new_modulus*sizeof(long));
141         for (var long hi = new_modulus-1; hi >= 0; hi--)
142             new_slots[hi] = 0;
143         var long free_list_head = -1;
144         for (var long i = new_size-1; i >= 0; i--) {
145             new_entries[i].next = free_list_head;
146             free_list_head = -2-i;
147         }
148         var htxentry* old_entries = this->_entries;
149         for (var long old_index = 0; old_index < this->_size; old_index++)
150             if (old_entries[old_index].next >= 0) {
151                 var key1_type& key1 = old_entries[old_index].entry.key1;
152                 var key2_type& key2 = old_entries[old_index].entry.key2;
153                 var value_type& val = old_entries[old_index].entry.val;
154                 var long hindex = hashcode(key1,key2) % new_modulus;
155                 var long index = -2-free_list_head;
156                 free_list_head = new_entries[index].next;
157                 new (&new_entries[index].entry) cl_htentry2<key1_type,key2_type,value_type> (key1,key2,val);
158                 new_entries[index].next = new_slots[hindex];
159                 new_slots[hindex] = 1+index;
160                 old_entries[old_index].~htxentry();
161             }
162         free_hook(this->_total_vector);
163         this->_modulus = new_modulus;
164         this->_size = new_size;
165         this->_freelist = free_list_head;
166         this->_slots = new_slots;
167         this->_entries = new_entries;
168         this->_total_vector = new_total_vector;
169     }
170 };
171
172 }  // namespace cln
173
174 #endif /* _CL_HASH2_H */