annotate libvtv/vtv_map.h @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1 /* Copyright (C) 2012-2020 Free Software Foundation, Inc.
111
kono
parents:
diff changeset
2
kono
parents:
diff changeset
3 This file is part of GCC.
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 GCC is free software; you can redistribute it and/or modify
kono
parents:
diff changeset
6 it under the terms of the GNU General Public License as published by
kono
parents:
diff changeset
7 the Free Software Foundation; either version 3, or (at your option)
kono
parents:
diff changeset
8 any later version.
kono
parents:
diff changeset
9
kono
parents:
diff changeset
10 GCC is distributed in the hope that it will be useful,
kono
parents:
diff changeset
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
kono
parents:
diff changeset
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
kono
parents:
diff changeset
13 GNU General Public License for more details.
kono
parents:
diff changeset
14
kono
parents:
diff changeset
15 Under Section 7 of GPL version 3, you are granted additional
kono
parents:
diff changeset
16 permissions described in the GCC Runtime Library Exception, version
kono
parents:
diff changeset
17 3.1, as published by the Free Software Foundation.
kono
parents:
diff changeset
18
kono
parents:
diff changeset
19 You should have received a copy of the GNU General Public License and
kono
parents:
diff changeset
20 a copy of the GCC Runtime Library Exception along with this program;
kono
parents:
diff changeset
21 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
kono
parents:
diff changeset
22 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
23
kono
parents:
diff changeset
24 #ifndef _VTV_MAP_H
kono
parents:
diff changeset
25 #define _VTV_MAP_H 1
kono
parents:
diff changeset
26
kono
parents:
diff changeset
27 #include <string.h>
kono
parents:
diff changeset
28
kono
parents:
diff changeset
29 #ifdef __MINGW32__
kono
parents:
diff changeset
30 #include <stdint.h>
kono
parents:
diff changeset
31 #include "vtv_utils.h"
kono
parents:
diff changeset
32 #else
kono
parents:
diff changeset
33 #include <vtv_utils.h>
kono
parents:
diff changeset
34 #endif
kono
parents:
diff changeset
35
kono
parents:
diff changeset
36 inline uint64_t
kono
parents:
diff changeset
37 load8bytes (const void *p)
kono
parents:
diff changeset
38 {
kono
parents:
diff changeset
39 uint64_t result;
kono
parents:
diff changeset
40 memcpy (&result, p, 8);
kono
parents:
diff changeset
41 return result;
kono
parents:
diff changeset
42 }
kono
parents:
diff changeset
43
kono
parents:
diff changeset
44 /* Insert_only_hash_map maps keys to values. The implementation is a
kono
parents:
diff changeset
45 basic hash table with open addressing. The keys are not "owned" by
kono
parents:
diff changeset
46 the table; it only stores pointers to keys. The key type is
kono
parents:
diff changeset
47 specified below (see insert_only_hash_map::key_type) and is,
kono
parents:
diff changeset
48 roughly speaking, a string of any length with the string length and
kono
parents:
diff changeset
49 a hash code stored at the front. The code here does not compute
kono
parents:
diff changeset
50 any hash codes, but rather uses what's given. */
kono
parents:
diff changeset
51
kono
parents:
diff changeset
52 template<typename T, typename Alloc>
kono
parents:
diff changeset
53 class insert_only_hash_map
kono
parents:
diff changeset
54 {
kono
parents:
diff changeset
55 public:
kono
parents:
diff changeset
56 typedef size_t size_type;
kono
parents:
diff changeset
57 typedef T value_type;
kono
parents:
diff changeset
58 typedef Alloc alloc_type;
kono
parents:
diff changeset
59 enum { min_capacity = 4 };
kono
parents:
diff changeset
60 #if HASHMAP_STATS
kono
parents:
diff changeset
61 enum { stats = true };
kono
parents:
diff changeset
62 #else
kono
parents:
diff changeset
63 enum { stats = false };
kono
parents:
diff changeset
64 #endif
kono
parents:
diff changeset
65
kono
parents:
diff changeset
66 /* Keys are a byte string (up to 2^32 - 1 long) plus a uint32_t
kono
parents:
diff changeset
67 that's used as a hash code. The latter can encode arbitrary
kono
parents:
diff changeset
68 information at the client's discretion, so, e.g., multiple keys
kono
parents:
diff changeset
69 that are the same string still "differ" if the hash codes differ.
kono
parents:
diff changeset
70 Keys are equal if the first 8 bytes are equal and the next n
kono
parents:
diff changeset
71 bytes are equal. */
kono
parents:
diff changeset
72 struct key_type
kono
parents:
diff changeset
73 {
kono
parents:
diff changeset
74 uint32_t n;
kono
parents:
diff changeset
75 uint32_t hash;
kono
parents:
diff changeset
76 char bytes[0];
kono
parents:
diff changeset
77
kono
parents:
diff changeset
78 bool
kono
parents:
diff changeset
79 equals (const key_type *k) const;
kono
parents:
diff changeset
80 };
kono
parents:
diff changeset
81
kono
parents:
diff changeset
82 /* Create an empty map with a reasonable number of buckets for the
kono
parents:
diff changeset
83 expected size. Returns NULL if the allocator fails. */
kono
parents:
diff changeset
84
kono
parents:
diff changeset
85 static insert_only_hash_map *
kono
parents:
diff changeset
86 create (size_type expected_size);
kono
parents:
diff changeset
87
kono
parents:
diff changeset
88 /* The opposite of create(). Free the memory for the given map. */
kono
parents:
diff changeset
89
kono
parents:
diff changeset
90 static void
kono
parents:
diff changeset
91 destroy (insert_only_hash_map *m)
kono
parents:
diff changeset
92 { Alloc().dealloc (m, m->size_in_bytes_); }
kono
parents:
diff changeset
93
kono
parents:
diff changeset
94 /* Return a map identical to this except that *k is mapped to v.
kono
parents:
diff changeset
95 Typcially it's done by modifying this in place, but if a resize
kono
parents:
diff changeset
96 is necessary then this is deallocated and a new map is returned.
kono
parents:
diff changeset
97 Requires k to be non-NULL. Does nothing and returns NULL if the
kono
parents:
diff changeset
98 allocator fails. */
kono
parents:
diff changeset
99
kono
parents:
diff changeset
100 insert_only_hash_map*
kono
parents:
diff changeset
101 put (const key_type *k, const value_type &v)
kono
parents:
diff changeset
102 { return this->put_internal (k, v, false); }
kono
parents:
diff changeset
103
kono
parents:
diff changeset
104 /* If *k is a key in this then set *v to point to the corresponding
kono
parents:
diff changeset
105 value. Otherwise, do the equivalent of insert(k, value_type())
kono
parents:
diff changeset
106 and, if that succeeds, set *v to point to the inserted value.
kono
parents:
diff changeset
107 Requires k to be non-NULL. Does nothing and returns NULL if the
kono
parents:
diff changeset
108 allocator fails. Typically returns this, but will return a new
kono
parents:
diff changeset
109 insert_only_hash_map if a resize occurs. If the return value is
kono
parents:
diff changeset
110 non-NULL, *v is set and it's valid until a resize of the map that
kono
parents:
diff changeset
111 is the return value. */
kono
parents:
diff changeset
112
kono
parents:
diff changeset
113 insert_only_hash_map *
kono
parents:
diff changeset
114 find_or_add_key (const key_type *k, value_type **v);
kono
parents:
diff changeset
115
kono
parents:
diff changeset
116 /* Get the value corresponding to *k. Returns NULL if there is
kono
parents:
diff changeset
117 none. Requires k to be non-NULL. The return value is valid
kono
parents:
diff changeset
118 until any resize. */
kono
parents:
diff changeset
119 const value_type *get (const key_type *k) const;
kono
parents:
diff changeset
120
kono
parents:
diff changeset
121 size_type
kono
parents:
diff changeset
122 size () const
kono
parents:
diff changeset
123 { return num_entries_; }
kono
parents:
diff changeset
124
kono
parents:
diff changeset
125 bool
kono
parents:
diff changeset
126 empty () const
kono
parents:
diff changeset
127 { return this->size () == 0; }
kono
parents:
diff changeset
128
kono
parents:
diff changeset
129 size_type
kono
parents:
diff changeset
130 bucket_count () const
kono
parents:
diff changeset
131 { return num_buckets_; }
kono
parents:
diff changeset
132
kono
parents:
diff changeset
133 private:
kono
parents:
diff changeset
134 typedef std::pair <const key_type *, value_type> bucket_type;
kono
parents:
diff changeset
135
kono
parents:
diff changeset
136 insert_only_hash_map *put_internal (const key_type *, const value_type &,
kono
parents:
diff changeset
137 bool);
kono
parents:
diff changeset
138
kono
parents:
diff changeset
139 /* This function determines when to resize the table. */
kono
parents:
diff changeset
140 bool
kono
parents:
diff changeset
141 is_too_full (size_type entries) const
kono
parents:
diff changeset
142 { return entries > (this->bucket_count () * 0.7); }
kono
parents:
diff changeset
143
kono
parents:
diff changeset
144 /* Return a copy with double the number of buckets. Returns NULL if
kono
parents:
diff changeset
145 the allocator fails. Otherwise, calls destroy (this). */
kono
parents:
diff changeset
146 insert_only_hash_map *destructive_copy ();
kono
parents:
diff changeset
147
kono
parents:
diff changeset
148 /* Must be a power of 2 not less than min_capacity. */
kono
parents:
diff changeset
149 size_type num_buckets_;
kono
parents:
diff changeset
150 size_type num_entries_;
kono
parents:
diff changeset
151 size_type size_in_bytes_;
kono
parents:
diff changeset
152 bucket_type buckets[0]; /* Actual array size is num_buckets. */
kono
parents:
diff changeset
153 };
kono
parents:
diff changeset
154
kono
parents:
diff changeset
155 template <typename T, typename Alloc>
kono
parents:
diff changeset
156 insert_only_hash_map <T, Alloc> *
kono
parents:
diff changeset
157 insert_only_hash_map <T, Alloc>::create (size_type expected_size)
kono
parents:
diff changeset
158 {
kono
parents:
diff changeset
159 size_t cap = min_capacity;
kono
parents:
diff changeset
160 while (expected_size >= cap)
kono
parents:
diff changeset
161 {
kono
parents:
diff changeset
162 cap *= 2;
kono
parents:
diff changeset
163 }
kono
parents:
diff changeset
164 size_t size_in_bytes = sizeof (insert_only_hash_map <T, Alloc>)
kono
parents:
diff changeset
165 + cap * sizeof (bucket_type);
kono
parents:
diff changeset
166 insert_only_hash_map <T, Alloc>* result =
kono
parents:
diff changeset
167 static_cast <insert_only_hash_map <T, Alloc>*> (Alloc ()
kono
parents:
diff changeset
168 .alloc (size_in_bytes));
kono
parents:
diff changeset
169 if (result != NULL)
kono
parents:
diff changeset
170 {
kono
parents:
diff changeset
171 result->size_in_bytes_ = size_in_bytes;
kono
parents:
diff changeset
172 result->num_buckets_ = cap;
kono
parents:
diff changeset
173 result->num_entries_ = 0;
kono
parents:
diff changeset
174 memset (result->buckets, 0, cap * sizeof (bucket_type));
kono
parents:
diff changeset
175 }
kono
parents:
diff changeset
176 return result;
kono
parents:
diff changeset
177 }
kono
parents:
diff changeset
178
kono
parents:
diff changeset
179 template <typename T, typename Alloc>
kono
parents:
diff changeset
180 insert_only_hash_map <T, Alloc>*
kono
parents:
diff changeset
181 insert_only_hash_map <T, Alloc>::destructive_copy ()
kono
parents:
diff changeset
182 {
kono
parents:
diff changeset
183 insert_only_hash_map* copy = create (this->bucket_count ());
kono
parents:
diff changeset
184 if (copy == NULL)
kono
parents:
diff changeset
185 return NULL;
kono
parents:
diff changeset
186 VTV_DEBUG_ASSERT (copy->bucket_count () == 2 * this->bucket_count ());
kono
parents:
diff changeset
187 for (size_type i = 0; i < this->bucket_count (); i++)
kono
parents:
diff changeset
188 if (this->buckets[i].first != NULL)
kono
parents:
diff changeset
189 copy->put_internal (this->buckets[i].first, this->buckets[i].second,
kono
parents:
diff changeset
190 true);
kono
parents:
diff changeset
191 VTV_DEBUG_ASSERT (copy->size () == this->size ());
kono
parents:
diff changeset
192 destroy (this);
kono
parents:
diff changeset
193 return copy;
kono
parents:
diff changeset
194 }
kono
parents:
diff changeset
195
kono
parents:
diff changeset
196 template <typename T, typename Alloc>
kono
parents:
diff changeset
197 insert_only_hash_map <T, Alloc>*
kono
parents:
diff changeset
198 insert_only_hash_map <T, Alloc>::find_or_add_key (const key_type *k,
kono
parents:
diff changeset
199 value_type **v)
kono
parents:
diff changeset
200 {
kono
parents:
diff changeset
201 /* Table size is always a power of 2. */
kono
parents:
diff changeset
202 const size_type mask = this->bucket_count () - 1;
kono
parents:
diff changeset
203 size_type bucket_index = k->hash & mask;
kono
parents:
diff changeset
204 size_type step = 1;
kono
parents:
diff changeset
205 for (;;)
kono
parents:
diff changeset
206 {
kono
parents:
diff changeset
207 bucket_type &bucket = this->buckets[bucket_index];
kono
parents:
diff changeset
208 if (bucket.first == NULL)
kono
parents:
diff changeset
209 {
kono
parents:
diff changeset
210 /* Key was not present. */
kono
parents:
diff changeset
211 if (this->is_too_full (this->size () + 1))
kono
parents:
diff changeset
212 {
kono
parents:
diff changeset
213 insert_only_hash_map <T, Alloc>* result =
kono
parents:
diff changeset
214 this->destructive_copy ();
kono
parents:
diff changeset
215 return result == NULL
kono
parents:
diff changeset
216 ? NULL
kono
parents:
diff changeset
217 : result->find_or_add_key (k, v);
kono
parents:
diff changeset
218 }
kono
parents:
diff changeset
219 else
kono
parents:
diff changeset
220 {
kono
parents:
diff changeset
221 bucket.first = k;
kono
parents:
diff changeset
222 bucket.second = T ();
kono
parents:
diff changeset
223 this->num_entries_++;
kono
parents:
diff changeset
224 *v = &bucket.second;
kono
parents:
diff changeset
225 return this;
kono
parents:
diff changeset
226 }
kono
parents:
diff changeset
227 }
kono
parents:
diff changeset
228 else if (bucket.first->equals (k))
kono
parents:
diff changeset
229 {
kono
parents:
diff changeset
230 /* Key was present. */
kono
parents:
diff changeset
231 *v = &bucket.second;
kono
parents:
diff changeset
232 return this;
kono
parents:
diff changeset
233 }
kono
parents:
diff changeset
234 else
kono
parents:
diff changeset
235 bucket_index = (bucket_index + step++) & mask;
kono
parents:
diff changeset
236 }
kono
parents:
diff changeset
237 }
kono
parents:
diff changeset
238
kono
parents:
diff changeset
239 template <typename T, typename Alloc>
kono
parents:
diff changeset
240 insert_only_hash_map <T, Alloc>*
kono
parents:
diff changeset
241 insert_only_hash_map <T, Alloc>::put_internal (
kono
parents:
diff changeset
242 const insert_only_hash_map::key_type *k,
kono
parents:
diff changeset
243 const insert_only_hash_map::value_type &v,
kono
parents:
diff changeset
244 bool unique_key_and_resize_not_needed)
kono
parents:
diff changeset
245 {
kono
parents:
diff changeset
246 /* Table size is always a power of 2. */
kono
parents:
diff changeset
247 const size_type mask = this->bucket_count () - 1;
kono
parents:
diff changeset
248 size_type bucket_index = k->hash & mask;
kono
parents:
diff changeset
249 size_type step = 1;
kono
parents:
diff changeset
250 for (;;)
kono
parents:
diff changeset
251 {
kono
parents:
diff changeset
252 bucket_type &bucket = this->buckets[bucket_index];
kono
parents:
diff changeset
253 if (bucket.first == NULL)
kono
parents:
diff changeset
254 {
kono
parents:
diff changeset
255 /* Key was not present. */
kono
parents:
diff changeset
256 if (!unique_key_and_resize_not_needed
kono
parents:
diff changeset
257 && this->is_too_full (this->size () + 1))
kono
parents:
diff changeset
258 {
kono
parents:
diff changeset
259 insert_only_hash_map <T, Alloc>* result =
kono
parents:
diff changeset
260 this->destructive_copy ();
kono
parents:
diff changeset
261 return result == NULL
kono
parents:
diff changeset
262 ? NULL
kono
parents:
diff changeset
263 : result->put_internal (k, v, true);
kono
parents:
diff changeset
264 }
kono
parents:
diff changeset
265 else
kono
parents:
diff changeset
266 {
kono
parents:
diff changeset
267 bucket.first = k;
kono
parents:
diff changeset
268 bucket.second = v;
kono
parents:
diff changeset
269 this->num_entries_++;
kono
parents:
diff changeset
270 return this;
kono
parents:
diff changeset
271 }
kono
parents:
diff changeset
272 }
kono
parents:
diff changeset
273 else if (!unique_key_and_resize_not_needed && bucket.first->equals (k))
kono
parents:
diff changeset
274 {
kono
parents:
diff changeset
275 /* Key was present. Just change the value. */
kono
parents:
diff changeset
276 bucket.second = v;
kono
parents:
diff changeset
277 return this;
kono
parents:
diff changeset
278 }
kono
parents:
diff changeset
279 else
kono
parents:
diff changeset
280 bucket_index = (bucket_index + step++) & mask;
kono
parents:
diff changeset
281 }
kono
parents:
diff changeset
282 }
kono
parents:
diff changeset
283
kono
parents:
diff changeset
284 template <typename T, typename Alloc>
kono
parents:
diff changeset
285 inline const typename insert_only_hash_map <T, Alloc>::value_type*
kono
parents:
diff changeset
286 insert_only_hash_map <T, Alloc>::get (const insert_only_hash_map::key_type *k)
kono
parents:
diff changeset
287 const
kono
parents:
diff changeset
288 {
kono
parents:
diff changeset
289 /* Table size is always a power of 2. */
kono
parents:
diff changeset
290 const size_type mask = this->bucket_count () - 1;
kono
parents:
diff changeset
291 size_type bucket_index = k->hash & mask;
kono
parents:
diff changeset
292 size_type step = 1;
kono
parents:
diff changeset
293 for (;;)
kono
parents:
diff changeset
294 {
kono
parents:
diff changeset
295 const bucket_type &bucket = this->buckets[bucket_index];
kono
parents:
diff changeset
296 if (bucket.first == NULL)
kono
parents:
diff changeset
297 return NULL;
kono
parents:
diff changeset
298 else if (bucket.first->equals (k))
kono
parents:
diff changeset
299 return &bucket.second;
kono
parents:
diff changeset
300 else
kono
parents:
diff changeset
301 bucket_index = (bucket_index + step++) & mask;
kono
parents:
diff changeset
302 }
kono
parents:
diff changeset
303 }
kono
parents:
diff changeset
304
kono
parents:
diff changeset
305 template <typename T, typename Alloc>
kono
parents:
diff changeset
306 inline bool
kono
parents:
diff changeset
307 insert_only_hash_map <T, Alloc>::key_type::equals (
kono
parents:
diff changeset
308 const typename insert_only_hash_map <T, Alloc>::key_type *k) const
kono
parents:
diff changeset
309 {
kono
parents:
diff changeset
310 const char* x = reinterpret_cast <const char *> (k);
kono
parents:
diff changeset
311 const char* y = reinterpret_cast <const char *> (this);
kono
parents:
diff changeset
312 return (load8bytes (x) == load8bytes (y)
kono
parents:
diff changeset
313 && memcmp (x + 8, y + 8, this->n) == 0);
kono
parents:
diff changeset
314 }
kono
parents:
diff changeset
315
kono
parents:
diff changeset
316 #endif /* _VTV_MAP_H */