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