blob: 062ad8823e1669635850952dc4013739070b35cd [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2001-2005 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38#include <vppinfra/hash.h>
39#include <vppinfra/error.h>
40#include <vppinfra/mem.h>
41#include <vppinfra/byte_order.h> /* for clib_arch_is_big_endian */
42
Dave Barachc3799992016-08-15 11:12:27 -040043always_inline void
44zero_pair (hash_t * h, hash_pair_t * p)
45{
46 memset (p, 0, hash_pair_bytes (h));
47}
Ed Warnickecb9cada2015-12-08 15:45:58 -070048
Dave Barachc3799992016-08-15 11:12:27 -040049always_inline void
50init_pair (hash_t * h, hash_pair_t * p)
51{
52 memset (p->value, ~0, hash_value_bytes (h));
53}
Ed Warnickecb9cada2015-12-08 15:45:58 -070054
55always_inline hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -040056get_pair (void *v, uword i)
Ed Warnickecb9cada2015-12-08 15:45:58 -070057{
Dave Barachc3799992016-08-15 11:12:27 -040058 hash_t *h = hash_header (v);
59 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -070060 ASSERT (i < vec_len (v));
61 p = v;
62 p += i << h->log2_pair_size;
63 return (hash_pair_union_t *) p;
64}
65
Dave Barachc3799992016-08-15 11:12:27 -040066always_inline void
67set_is_user (void *v, uword i, uword is_user)
Ed Warnickecb9cada2015-12-08 15:45:58 -070068{
Dave Barachc3799992016-08-15 11:12:27 -040069 hash_t *h = hash_header (v);
70 uword i0 = i / BITS (h->is_user[0]);
71 uword i1 = (uword) 1 << (i % BITS (h->is_user[0]));
Ed Warnickecb9cada2015-12-08 15:45:58 -070072 if (is_user)
73 h->is_user[i0] |= i1;
74 else
75 h->is_user[i0] &= ~i1;
76}
77
Dave Barachc3799992016-08-15 11:12:27 -040078static u8 *hash_format_pair_default (u8 * s, va_list * args);
Ed Warnickecb9cada2015-12-08 15:45:58 -070079
80#if uword_bits == 64
81
Dave Barachc3799992016-08-15 11:12:27 -040082static inline u64
83zap64 (u64 x, word n)
Ed Warnickecb9cada2015-12-08 15:45:58 -070084{
85#define _(n) (((u64) 1 << (u64) (8*(n))) - (u64) 1)
Dave Barachc3799992016-08-15 11:12:27 -040086 static u64 masks_little_endian[] = {
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 0, _(1), _(2), _(3), _(4), _(5), _(6), _(7),
88 };
89 static u64 masks_big_endian[] = {
90 0, ~_(7), ~_(6), ~_(5), ~_(4), ~_(3), ~_(2), ~_(1),
91 };
92#undef _
93 if (clib_arch_is_big_endian)
94 return x & masks_big_endian[n];
95 else
96 return x & masks_little_endian[n];
97}
98
Dave Barachc3799992016-08-15 11:12:27 -040099static inline u64
100hash_memory64 (void *p, word n_bytes, u64 state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101{
Dave Barachc3799992016-08-15 11:12:27 -0400102 u64 *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700103 u64 a, b, c, n;
104
105 a = b = 0x9e3779b97f4a7c13LL;
106 c = state;
107 n = n_bytes;
108
Dave Barachc3799992016-08-15 11:12:27 -0400109 while (n >= 3 * sizeof (u64))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110 {
111 a += clib_mem_unaligned (q + 0, u64);
112 b += clib_mem_unaligned (q + 1, u64);
113 c += clib_mem_unaligned (q + 2, u64);
114 hash_mix64 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400115 n -= 3 * sizeof (u64);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 q += 3;
117 }
118
119 c += n_bytes;
120 switch (n / sizeof (u64))
121 {
122 case 2:
123 a += clib_mem_unaligned (q + 0, u64);
124 b += clib_mem_unaligned (q + 1, u64);
125 if (n % sizeof (u64))
Dave Barachc3799992016-08-15 11:12:27 -0400126 c += zap64 (clib_mem_unaligned (q + 2, u64), n % sizeof (u64)) << 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700127 break;
128
129 case 1:
130 a += clib_mem_unaligned (q + 0, u64);
131 if (n % sizeof (u64))
Dave Barachc3799992016-08-15 11:12:27 -0400132 b += zap64 (clib_mem_unaligned (q + 1, u64), n % sizeof (u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700133 break;
134
135 case 0:
136 if (n % sizeof (u64))
Dave Barachc3799992016-08-15 11:12:27 -0400137 a += zap64 (clib_mem_unaligned (q + 0, u64), n % sizeof (u64));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138 break;
139 }
140
141 hash_mix64 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400142
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143 return c;
144}
145
146#else /* if uword_bits == 64 */
147
Dave Barachc3799992016-08-15 11:12:27 -0400148static inline u32
149zap32 (u32 x, word n)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700150{
151#define _(n) (((u32) 1 << (u32) (8*(n))) - (u32) 1)
152 static u32 masks_little_endian[] = {
153 0, _(1), _(2), _(3),
154 };
155 static u32 masks_big_endian[] = {
156 0, ~_(3), ~_(2), ~_(1),
157 };
158#undef _
159 if (clib_arch_is_big_endian)
160 return x & masks_big_endian[n];
161 else
162 return x & masks_little_endian[n];
163}
164
Dave Barachc3799992016-08-15 11:12:27 -0400165static inline u32
166hash_memory32 (void *p, word n_bytes, u32 state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167{
Dave Barachc3799992016-08-15 11:12:27 -0400168 u32 *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700169 u32 a, b, c, n;
170
171 a = b = 0x9e3779b9;
172 c = state;
173 n = n_bytes;
174
Dave Barachc3799992016-08-15 11:12:27 -0400175 while (n >= 3 * sizeof (u32))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176 {
177 a += clib_mem_unaligned (q + 0, u32);
178 b += clib_mem_unaligned (q + 1, u32);
179 c += clib_mem_unaligned (q + 2, u32);
180 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400181 n -= 3 * sizeof (u32);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700182 q += 3;
183 }
184
185 c += n_bytes;
186 switch (n / sizeof (u32))
187 {
188 case 2:
189 a += clib_mem_unaligned (q + 0, u32);
190 b += clib_mem_unaligned (q + 1, u32);
191 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400192 c += zap32 (clib_mem_unaligned (q + 2, u32), n % sizeof (u32)) << 8;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700193 break;
194
195 case 1:
196 a += clib_mem_unaligned (q + 0, u32);
197 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400198 b += zap32 (clib_mem_unaligned (q + 1, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 break;
200
201 case 0:
202 if (n % sizeof (u32))
Dave Barachc3799992016-08-15 11:12:27 -0400203 a += zap32 (clib_mem_unaligned (q + 0, u32), n % sizeof (u32));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204 break;
205 }
206
207 hash_mix32 (a, b, c);
Dave Barachc3799992016-08-15 11:12:27 -0400208
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209 return c;
210}
211#endif
212
Dave Barachc3799992016-08-15 11:12:27 -0400213uword
214hash_memory (void *p, word n_bytes, uword state)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700215{
Dave Barachc3799992016-08-15 11:12:27 -0400216 uword *q = p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217
218#if uword_bits == 64
219 return hash_memory64 (q, n_bytes, state);
220#else
221 return hash_memory32 (q, n_bytes, state);
222#endif
223}
224
225#if uword_bits == 64
Dave Barachc3799992016-08-15 11:12:27 -0400226always_inline uword
227hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228{
229 u64 a, b, c;
230
231 a = b = 0x9e3779b97f4a7c13LL;
232 c = 0;
233 a += x;
234 hash_mix64 (a, b, c);
235 return c;
236}
237#else
Dave Barachc3799992016-08-15 11:12:27 -0400238always_inline uword
239hash_uword (uword x)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700240{
241 u32 a, b, c;
242
243 a = b = 0x9e3779b9;
244 c = 0;
245 a += x;
246 hash_mix32 (a, b, c);
247 return c;
248}
249#endif
250
251/* Call sum function. Hash code will be sum function value
252 modulo the prime length of the hash table. */
Dave Barachc3799992016-08-15 11:12:27 -0400253always_inline uword
254key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700255{
256 uword sum;
257 switch (pointer_to_uword ((void *) h->key_sum))
258 {
259 case KEY_FUNC_NONE:
260 sum = hash_uword (key);
261 break;
262
263 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400264 sum = hash_uword (*uword_to_pointer (key, uword *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700265 break;
266
267 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400268 sum = hash_uword (*uword_to_pointer (key, u32 *));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700269 break;
270
271 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400272 sum = string_key_sum (h, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700273 break;
274
275 default:
276 sum = h->key_sum (h, key);
277 break;
278 }
279
280 return sum;
281}
282
Dave Barachc3799992016-08-15 11:12:27 -0400283always_inline uword
284key_equal1 (hash_t * h, uword key1, uword key2, uword e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285{
286 switch (pointer_to_uword ((void *) h->key_equal))
287 {
288 case KEY_FUNC_NONE:
289 break;
290
291 case KEY_FUNC_POINTER_UWORD:
Dave Barachc3799992016-08-15 11:12:27 -0400292 e =
293 *uword_to_pointer (key1, uword *) == *uword_to_pointer (key2,
294 uword *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 break;
296
297 case KEY_FUNC_POINTER_U32:
Dave Barachc3799992016-08-15 11:12:27 -0400298 e = *uword_to_pointer (key1, u32 *) == *uword_to_pointer (key2, u32 *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299 break;
300
301 case KEY_FUNC_STRING:
Dave Barachc3799992016-08-15 11:12:27 -0400302 e = string_key_equal (h, key1, key2);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700303 break;
304
305 default:
306 e = h->key_equal (h, key1, key2);
307 break;
308 }
309 return e;
310}
311
312/* Compares two keys: returns 1 if equal, 0 if not. */
Dave Barachc3799992016-08-15 11:12:27 -0400313always_inline uword
314key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315{
316 uword e = key1 == key2;
317 if (CLIB_DEBUG > 0 && key1 == key2)
318 ASSERT (key_equal1 (h, key1, key2, e));
Dave Barachc3799992016-08-15 11:12:27 -0400319 if (!e)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320 e = key_equal1 (h, key1, key2, e);
321 return e;
322}
323
324static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400325get_indirect (void *v, hash_pair_indirect_t * pi, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326{
Dave Barachc3799992016-08-15 11:12:27 -0400327 hash_t *h = hash_header (v);
328 hash_pair_t *p0, *p1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700329
330 p0 = p1 = pi->pairs;
331 if (h->log2_pair_size > 0)
332 p1 = hash_forward (h, p0, indirect_pair_get_len (pi));
333 else
334 p1 += vec_len (p0);
335
336 while (p0 < p1)
337 {
338 if (key_equal (h, p0->key, key))
339 return (hash_pair_union_t *) p0;
340 p0 = hash_forward1 (h, p0);
341 }
342
343 return (hash_pair_union_t *) 0;
344}
345
346static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400347set_indirect_is_user (void *v, uword i, hash_pair_union_t * p, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700348{
Dave Barachc3799992016-08-15 11:12:27 -0400349 hash_t *h = hash_header (v);
350 hash_pair_t *q;
351 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700352 uword log2_bytes = 0;
353
354 if (h->log2_pair_size == 0)
355 q = vec_new (hash_pair_t, 2);
356 else
357 {
358 log2_bytes = 1 + hash_pair_log2_bytes (h);
Dave Barach6f6f34f2016-08-08 13:05:31 -0400359 q = clib_mem_alloc (1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700360 }
Damjan Marionf1213b82016-03-13 02:22:06 +0100361 clib_memcpy (q, &p->direct, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700362
363 pi->pairs = q;
364 if (h->log2_pair_size > 0)
365 indirect_pair_set (pi, log2_bytes, 2);
366
367 set_is_user (v, i, 0);
368
369 /* First element is used by existing pair, second will be used by caller. */
370 q = hash_forward1 (h, q);
371 q->key = key;
372 init_pair (h, q);
373 return (hash_pair_union_t *) q;
374}
375
376static hash_pair_union_t *
Dave Barachc3799992016-08-15 11:12:27 -0400377set_indirect (void *v, hash_pair_indirect_t * pi, uword key,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378 uword * found_key)
379{
Dave Barachc3799992016-08-15 11:12:27 -0400380 hash_t *h = hash_header (v);
381 hash_pair_t *new_pair;
382 hash_pair_union_t *q;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383
384 q = get_indirect (v, pi, key);
385 if (q)
386 {
387 *found_key = 1;
388 return q;
389 }
390
391 if (h->log2_pair_size == 0)
392 vec_add2 (pi->pairs, new_pair, 1);
393 else
394 {
395 uword len, new_len, log2_bytes;
396
397 len = indirect_pair_get_len (pi);
398 log2_bytes = indirect_pair_get_log2_bytes (pi);
399
400 new_len = len + 1;
Dave Barach6f6f34f2016-08-08 13:05:31 -0400401 if (new_len * hash_pair_bytes (h) > (1ULL << log2_bytes))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700402 {
403 pi->pairs = clib_mem_realloc (pi->pairs,
Dave Barachdd522cb2016-08-10 16:56:16 -0400404 1ULL << (log2_bytes + 1),
405 1ULL << log2_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406 log2_bytes++;
407 }
408
409 indirect_pair_set (pi, log2_bytes, new_len);
410 new_pair = pi->pairs + (len << h->log2_pair_size);
411 }
412 new_pair->key = key;
413 init_pair (h, new_pair);
414 *found_key = 0;
415 return (hash_pair_union_t *) new_pair;
416}
417
Dave Barachc3799992016-08-15 11:12:27 -0400418static void
419unset_indirect (void *v, uword i, hash_pair_t * q)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420{
Dave Barachc3799992016-08-15 11:12:27 -0400421 hash_t *h = hash_header (v);
422 hash_pair_union_t *p = get_pair (v, i);
423 hash_pair_t *e;
424 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700425 uword len, is_vec;
426
427 is_vec = h->log2_pair_size == 0;
428
Dave Barachc3799992016-08-15 11:12:27 -0400429 ASSERT (!hash_is_user (v, i));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430 len = is_vec ? vec_len (pi->pairs) : indirect_pair_get_len (pi);
431 e = hash_forward (h, pi->pairs, len - 1);
432 ASSERT (q >= pi->pairs && q <= e);
433
434 /* We have two or fewer pairs and we are delete one pair.
435 Make indirect pointer direct and free indirect memory. */
436 if (len <= 2)
437 {
Dave Barachc3799992016-08-15 11:12:27 -0400438 hash_pair_t *r = pi->pairs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439
440 if (len == 2)
441 {
Dave Barachc3799992016-08-15 11:12:27 -0400442 clib_memcpy (p, q == r ? hash_forward1 (h, r) : r,
443 hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444 set_is_user (v, i, 1);
445 }
446 else
447 zero_pair (h, &p->direct);
448
449 if (is_vec)
450 vec_free (r);
451 else if (r)
452 clib_mem_free (r);
453 }
454 else
455 {
456 /* If deleting a pair we need to keep non-null pairs together. */
457 if (q < e)
Damjan Marionf1213b82016-03-13 02:22:06 +0100458 clib_memcpy (q, e, hash_pair_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700459 else
460 zero_pair (h, q);
461 if (is_vec)
462 _vec_len (pi->pairs) -= 1;
463 else
Dave Barachc3799992016-08-15 11:12:27 -0400464 indirect_pair_set (pi, indirect_pair_get_log2_bytes (pi), len - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700465 }
466}
467
Dave Barachc3799992016-08-15 11:12:27 -0400468enum lookup_opcode
469{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470 GET = 1,
471 SET = 2,
472 UNSET = 3,
473};
474
Dave Barachc3799992016-08-15 11:12:27 -0400475static hash_pair_t *
476lookup (void *v, uword key, enum lookup_opcode op,
477 void *new_value, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478{
Dave Barachc3799992016-08-15 11:12:27 -0400479 hash_t *h = hash_header (v);
480 hash_pair_union_t *p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 uword found_key = 0;
482 uword i;
483
Dave Barachc3799992016-08-15 11:12:27 -0400484 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485 return 0;
486
487 i = key_sum (h, key) & (_vec_len (v) - 1);
488 p = get_pair (v, i);
489
490 if (hash_is_user (v, i))
491 {
492 found_key = key_equal (h, p->direct.key, key);
493 if (found_key)
494 {
495 if (op == UNSET)
496 {
497 set_is_user (v, i, 0);
498 if (old_value)
Dave Barachc3799992016-08-15 11:12:27 -0400499 clib_memcpy (old_value, p->direct.value,
500 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700501 zero_pair (h, &p->direct);
502 }
503 }
504 else
505 {
506 if (op == SET)
507 p = set_indirect_is_user (v, i, p, key);
508 else
509 p = 0;
510 }
511 }
512 else
513 {
Dave Barachc3799992016-08-15 11:12:27 -0400514 hash_pair_indirect_t *pi = &p->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
516 if (op == SET)
517 {
Dave Barachc3799992016-08-15 11:12:27 -0400518 if (!pi->pairs)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700519 {
520 p->direct.key = key;
521 set_is_user (v, i, 1);
522 }
523 else
524 p = set_indirect (v, pi, key, &found_key);
525 }
526 else
527 {
528 p = get_indirect (v, pi, key);
529 found_key = p != 0;
530 if (found_key && op == UNSET)
531 {
532 if (old_value)
Dave Barachc3799992016-08-15 11:12:27 -0400533 clib_memcpy (old_value, &p->direct.value,
534 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535
536 unset_indirect (v, i, &p->direct);
537
538 /* Nullify p (since it's just been deleted).
Dave Barachc3799992016-08-15 11:12:27 -0400539 Otherwise we might be tempted to play with it. */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700540 p = 0;
541 }
542 }
543 }
544
545 if (op == SET && p != 0)
546 {
547 /* Save away old value for caller. */
548 if (old_value && found_key)
Damjan Marionf1213b82016-03-13 02:22:06 +0100549 clib_memcpy (old_value, &p->direct.value, hash_value_bytes (h));
550 clib_memcpy (&p->direct.value, new_value, hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551 }
552
553 if (op == SET)
554 h->elts += !found_key;
555 if (op == UNSET)
556 h->elts -= found_key;
557
558 return &p->direct;
559}
560
561/* Fetch value of key. */
Dave Barachc3799992016-08-15 11:12:27 -0400562uword *
563_hash_get (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700564{
Dave Barachc3799992016-08-15 11:12:27 -0400565 hash_t *h = hash_header (v);
566 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700567
568 /* Don't even search table if its empty. */
Dave Barachc3799992016-08-15 11:12:27 -0400569 if (!v || h->elts == 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700570 return 0;
571
572 p = lookup (v, key, GET, 0, 0);
Dave Barachc3799992016-08-15 11:12:27 -0400573 if (!p)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700574 return 0;
575 if (h->log2_pair_size == 0)
576 return &p->key;
577 else
578 return &p->value[0];
579}
580
Dave Barachc3799992016-08-15 11:12:27 -0400581hash_pair_t *
582_hash_get_pair (void *v, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700583{
Dave Barachc3799992016-08-15 11:12:27 -0400584 return lookup (v, key, GET, 0, 0);
585}
586
587hash_pair_t *
588hash_next (void *v, hash_next_t * hn)
589{
590 hash_t *h = hash_header (v);
591 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700592
593 while (1)
594 {
595 if (hn->i == 0 && hn->j == 0)
596 {
597 /* Save flags. */
598 hn->f = h->flags;
599
600 /* Prevent others from re-sizing hash table. */
601 h->flags |=
Dave Barachc3799992016-08-15 11:12:27 -0400602 (HASH_FLAG_NO_AUTO_GROW
603 | HASH_FLAG_NO_AUTO_SHRINK | HASH_FLAG_HASH_NEXT_IN_PROGRESS);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604 }
605 else if (hn->i >= hash_capacity (v))
606 {
607 /* Restore flags. */
608 h->flags = hn->f;
609 memset (hn, 0, sizeof (hn[0]));
610 return 0;
611 }
612
613 p = hash_forward (h, v, hn->i);
614 if (hash_is_user (v, hn->i))
615 {
616 hn->i++;
617 return p;
618 }
619 else
620 {
Dave Barachc3799992016-08-15 11:12:27 -0400621 hash_pair_indirect_t *pi = (void *) p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700622 uword n;
623
624 if (h->log2_pair_size > 0)
625 n = indirect_pair_get_len (pi);
626 else
627 n = vec_len (pi->pairs);
628
629 if (hn->j >= n)
630 {
631 hn->i++;
632 hn->j = 0;
633 }
634 else
635 return hash_forward (h, pi->pairs, hn->j++);
636 }
637 }
638}
639
640/* Remove key from table. */
Dave Barachc3799992016-08-15 11:12:27 -0400641void *
642_hash_unset (void *v, uword key, void *old_value)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700643{
Dave Barachc3799992016-08-15 11:12:27 -0400644 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700645
Dave Barachc3799992016-08-15 11:12:27 -0400646 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700647 return v;
648
649 (void) lookup (v, key, UNSET, 0, old_value);
650
651 h = hash_header (v);
Dave Barachc3799992016-08-15 11:12:27 -0400652 if (!(h->flags & HASH_FLAG_NO_AUTO_SHRINK))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653 {
654 /* Resize when 1/4 full. */
655 if (h->elts > 32 && 4 * (h->elts + 1) < vec_len (v))
656 v = hash_resize (v, vec_len (v) / 2);
657 }
658
659 return v;
660}
661
Dave Barachc3799992016-08-15 11:12:27 -0400662void *
663_hash_create (uword elts, hash_t * h_user)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700664{
Dave Barachc3799992016-08-15 11:12:27 -0400665 hash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700666 uword log2_pair_size;
Dave Barachc3799992016-08-15 11:12:27 -0400667 void *v;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700668
669 /* Size of hash is power of 2 >= ELTS and larger than
670 number of bits in is_user bitmap elements. */
671 elts = clib_max (elts, BITS (h->is_user[0]));
Dave Barach6f6f34f2016-08-08 13:05:31 -0400672 elts = 1ULL << max_log2 (elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673
674 log2_pair_size = 1;
675 if (h_user)
676 log2_pair_size = h_user->log2_pair_size;
677
678 v = _vec_resize (0,
Dave Barachc3799992016-08-15 11:12:27 -0400679 /* vec len: */ elts,
680 /* data bytes: */
681 (elts << log2_pair_size) * sizeof (hash_pair_t),
682 /* header bytes: */
683 sizeof (h[0]) +
684 (elts / BITS (h->is_user[0])) * sizeof (h->is_user[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685 /* alignment */ sizeof (hash_pair_t));
686 h = hash_header (v);
687
688 if (h_user)
689 h[0] = h_user[0];
690
691 h->log2_pair_size = log2_pair_size;
692 h->elts = 0;
693
694 /* Default flags to never shrinking hash tables.
695 Shrinking tables can cause "jackpot" cases. */
Dave Barachc3799992016-08-15 11:12:27 -0400696 if (!h_user)
697 h->flags = HASH_FLAG_NO_AUTO_SHRINK;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698
Dave Barachc3799992016-08-15 11:12:27 -0400699 if (!h->format_pair)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700 {
701 h->format_pair = hash_format_pair_default;
702 h->format_pair_arg = 0;
703 }
704
705 return v;
706}
707
Dave Barachc3799992016-08-15 11:12:27 -0400708void *
709_hash_free (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710{
Dave Barachc3799992016-08-15 11:12:27 -0400711 hash_t *h = hash_header (v);
712 hash_pair_union_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713 uword i;
714
Dave Barachc3799992016-08-15 11:12:27 -0400715 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716 return v;
717
718 /* We zero all freed memory in case user would be tempted to use it. */
719 for (i = 0; i < hash_capacity (v); i++)
720 {
721 if (hash_is_user (v, i))
722 continue;
723 p = get_pair (v, i);
724 if (h->log2_pair_size == 0)
725 vec_free (p->indirect.pairs);
726 else if (p->indirect.pairs)
727 clib_mem_free (p->indirect.pairs);
728 }
729
730 vec_free_header (h);
731
732 return 0;
733}
734
Dave Barachc3799992016-08-15 11:12:27 -0400735static void *
736hash_resize_internal (void *old, uword new_size, uword free_old)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737{
Dave Barachc3799992016-08-15 11:12:27 -0400738 void *new;
739 hash_pair_t *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700740
741 new = 0;
742 if (new_size > 0)
743 {
Dave Barachc3799992016-08-15 11:12:27 -0400744 hash_t *h = old ? hash_header (old) : 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700745 new = _hash_create (new_size, h);
Dave Barachc3799992016-08-15 11:12:27 -0400746 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747 hash_foreach_pair (p, old, {
748 new = _hash_set3 (new, p->key, &p->value[0], 0);
749 });
Dave Barachc3799992016-08-15 11:12:27 -0400750 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700751 }
752
753 if (free_old)
754 hash_free (old);
755 return new;
756}
757
Dave Barachc3799992016-08-15 11:12:27 -0400758void *
759hash_resize (void *old, uword new_size)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760{
Dave Barachc3799992016-08-15 11:12:27 -0400761 return hash_resize_internal (old, new_size, 1);
762}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700763
Dave Barachc3799992016-08-15 11:12:27 -0400764void *
765hash_dup (void *old)
766{
767 return hash_resize_internal (old, vec_len (old), 0);
768}
769
770void *
771_hash_set3 (void *v, uword key, void *value, void *old_value)
772{
773 hash_t *h;
774
775 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700776 v = hash_create (0, sizeof (uword));
777
778 h = hash_header (v);
779 (void) lookup (v, key, SET, value, old_value);
780
Dave Barachc3799992016-08-15 11:12:27 -0400781 if (!(h->flags & HASH_FLAG_NO_AUTO_GROW))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700782 {
783 /* Resize when 3/4 full. */
784 if (4 * (h->elts + 1) > 3 * vec_len (v))
785 v = hash_resize (v, 2 * vec_len (v));
786 }
787
788 return v;
789}
790
Dave Barachc3799992016-08-15 11:12:27 -0400791uword
792vec_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700793{
Dave Barachc3799992016-08-15 11:12:27 -0400794 void *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700795 return hash_memory (v, vec_len (v) * h->user, 0);
796}
797
Dave Barachc3799992016-08-15 11:12:27 -0400798uword
799vec_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700800{
Dave Barachc3799992016-08-15 11:12:27 -0400801 void *v1 = uword_to_pointer (key1, void *);
802 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 uword l1 = vec_len (v1);
804 uword l2 = vec_len (v2);
805 return l1 == l2 && 0 == memcmp (v1, v2, l1 * h->user);
806}
807
Dave Barachc3799992016-08-15 11:12:27 -0400808u8 *
809vec_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810{
Dave Barachc3799992016-08-15 11:12:27 -0400811 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
812 void *v = va_arg (*args, void *);
813 hash_pair_t *p = va_arg (*args, hash_pair_t *);
814 hash_t *h = hash_header (v);
815 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816 int i;
817
Dave Barachc3799992016-08-15 11:12:27 -0400818 switch (h->user)
819 {
820 case 1:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821 s = format (s, "%v", u);
822 break;
823
Dave Barachc3799992016-08-15 11:12:27 -0400824 case 2:
825 {
826 u16 *w = u;
827 for (i = 0; i < vec_len (w); i++)
828 s = format (s, "0x%x, ", w[i]);
829 break;
830 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700831
Dave Barachc3799992016-08-15 11:12:27 -0400832 case 4:
833 {
834 u32 *w = u;
835 for (i = 0; i < vec_len (w); i++)
836 s = format (s, "0x%x, ", w[i]);
837 break;
838 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700839
Dave Barachc3799992016-08-15 11:12:27 -0400840 case 8:
841 {
842 u64 *w = u;
843 for (i = 0; i < vec_len (w); i++)
844 s = format (s, "0x%Lx, ", w[i]);
845 break;
846 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700847
Dave Barachc3799992016-08-15 11:12:27 -0400848 default:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700849 s = format (s, "0x%U", format_hex_bytes, u, vec_len (u) * h->user);
850 break;
Dave Barachc3799992016-08-15 11:12:27 -0400851 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700852
853 if (hash_value_bytes (h) > 0)
854 s = format (s, " -> 0x%wx", p->value[0]);
855
856 return s;
857}
858
Dave Barachc3799992016-08-15 11:12:27 -0400859uword
860mem_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700861{
Dave Barachc3799992016-08-15 11:12:27 -0400862 uword *v = uword_to_pointer (key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700863 return hash_memory (v, h->user, 0);
864}
865
Dave Barachc3799992016-08-15 11:12:27 -0400866uword
867mem_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700868{
Dave Barachc3799992016-08-15 11:12:27 -0400869 void *v1 = uword_to_pointer (key1, void *);
870 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700871 return v1 && v2 && 0 == memcmp (v1, v2, h->user);
872}
873
Dave Barachc3799992016-08-15 11:12:27 -0400874uword
875string_key_sum (hash_t * h, uword key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700876{
Dave Barachc3799992016-08-15 11:12:27 -0400877 char *v = uword_to_pointer (key, char *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700878 return hash_memory (v, strlen (v), 0);
879}
880
Dave Barachc3799992016-08-15 11:12:27 -0400881uword
882string_key_equal (hash_t * h, uword key1, uword key2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700883{
Dave Barachc3799992016-08-15 11:12:27 -0400884 void *v1 = uword_to_pointer (key1, void *);
885 void *v2 = uword_to_pointer (key2, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700886 return v1 && v2 && 0 == strcmp (v1, v2);
887}
888
Dave Barachc3799992016-08-15 11:12:27 -0400889u8 *
890string_key_format_pair (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700891{
Dave Barachc3799992016-08-15 11:12:27 -0400892 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
893 void *v = va_arg (*args, void *);
894 hash_pair_t *p = va_arg (*args, hash_pair_t *);
895 hash_t *h = hash_header (v);
896 void *u = uword_to_pointer (p->key, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700897
898 s = format (s, "%s", u);
899
900 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400901 s =
902 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
903 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700904
905 return s;
906}
907
Dave Barachc3799992016-08-15 11:12:27 -0400908static u8 *
909hash_format_pair_default (u8 * s, va_list * args)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700910{
Dave Barachc3799992016-08-15 11:12:27 -0400911 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
912 void *v = va_arg (*args, void *);
913 hash_pair_t *p = va_arg (*args, hash_pair_t *);
914 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915
916 s = format (s, "0x%08x", p->key);
917 if (hash_value_bytes (h) > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400918 s =
919 format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
920 hash_value_bytes (h));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700921 return s;
922}
923
Dave Barachc3799992016-08-15 11:12:27 -0400924uword
925hash_bytes (void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700926{
927 uword i, bytes;
Dave Barachc3799992016-08-15 11:12:27 -0400928 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700929
Dave Barachc3799992016-08-15 11:12:27 -0400930 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700931 return 0;
932
933 bytes = vec_capacity (v, hash_header_bytes (v));
934
935 for (i = 0; i < hash_capacity (v); i++)
936 {
Dave Barachc3799992016-08-15 11:12:27 -0400937 if (!hash_is_user (v, i))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938 {
Dave Barachc3799992016-08-15 11:12:27 -0400939 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700940 if (h->log2_pair_size > 0)
Dave Barachc3799992016-08-15 11:12:27 -0400941 bytes += 1 << indirect_pair_get_log2_bytes (&p->indirect);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700942 else
943 bytes += vec_capacity (p->indirect.pairs, 0);
944 }
945 }
946 return bytes;
947}
948
Dave Barachc3799992016-08-15 11:12:27 -0400949u8 *
950format_hash (u8 * s, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700951{
Dave Barachc3799992016-08-15 11:12:27 -0400952 void *v = va_arg (*va, void *);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700953 int verbose = va_arg (*va, int);
Dave Barachc3799992016-08-15 11:12:27 -0400954 hash_pair_t *p;
955 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956 uword i;
957
958 s = format (s, "hash %p, %wd elts, capacity %wd, %wd bytes used,\n",
Dave Barachc3799992016-08-15 11:12:27 -0400959 v, hash_elts (v), hash_capacity (v), hash_bytes (v));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960
961 {
Dave Barachc3799992016-08-15 11:12:27 -0400962 uword *occupancy = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700963
964 /* Count number of buckets with each occupancy. */
965 for (i = 0; i < hash_capacity (v); i++)
966 {
967 uword j;
968
969 if (hash_is_user (v, i))
970 {
971 j = 1;
972 }
973 else
974 {
Dave Barachc3799992016-08-15 11:12:27 -0400975 hash_pair_union_t *p = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700976 if (h->log2_pair_size > 0)
977 j = indirect_pair_get_len (&p->indirect);
978 else
979 j = vec_len (p->indirect.pairs);
980 }
981
982 vec_validate (occupancy, j);
983 occupancy[j]++;
984 }
985
986 s = format (s, " profile ");
987 for (i = 0; i < vec_len (occupancy); i++)
988 s = format (s, "%wd%c", occupancy[i],
989 i + 1 == vec_len (occupancy) ? '\n' : ' ');
990
991 s = format (s, " lookup # of compares: ");
992 for (i = 1; i < vec_len (occupancy); i++)
993 s = format (s, "%wd: .%03d%c", i,
994 (1000 * i * occupancy[i]) / hash_elts (v),
995 i + 1 == vec_len (occupancy) ? '\n' : ' ');
996
997 vec_free (occupancy);
998 }
999
1000 if (verbose)
1001 {
Dave Barachc3799992016-08-15 11:12:27 -04001002 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001003 hash_foreach_pair (p, v, {
1004 s = format (s, " %U\n", h->format_pair, h->format_pair_arg, v, p);
1005 });
Dave Barachc3799992016-08-15 11:12:27 -04001006 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001007 }
1008
1009 return s;
1010}
1011
1012static uword
1013unformat_hash_string_internal (unformat_input_t * input,
Dave Barachc3799992016-08-15 11:12:27 -04001014 va_list * va, int is_vec)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001015{
Dave Barachc3799992016-08-15 11:12:27 -04001016 uword *hash = va_arg (*va, uword *);
1017 int *result = va_arg (*va, int *);
1018 u8 *string = 0;
1019 uword *p;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001020
Dave Barachc3799992016-08-15 11:12:27 -04001021 if (!unformat (input, is_vec ? "%v%_" : "%s%_", &string))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001022 return 0;
1023
1024 p = hash_get_mem (hash, string);
1025 if (p)
1026 *result = *p;
1027
1028 vec_free (string);
1029 return p ? 1 : 0;
1030}
1031
1032uword
1033unformat_hash_vec_string (unformat_input_t * input, va_list * va)
Dave Barachc3799992016-08-15 11:12:27 -04001034{
1035 return unformat_hash_string_internal (input, va, /* is_vec */ 1);
1036}
Ed Warnickecb9cada2015-12-08 15:45:58 -07001037
1038uword
1039unformat_hash_string (unformat_input_t * input, va_list * va)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001040{
Dave Barachc3799992016-08-15 11:12:27 -04001041 return unformat_hash_string_internal (input, va, /* is_vec */ 0);
1042}
1043
1044clib_error_t *
1045hash_validate (void *v)
1046{
1047 hash_t *h = hash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001048 uword i, j;
Dave Barachc3799992016-08-15 11:12:27 -04001049 uword *keys = 0;
1050 clib_error_t *error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051
1052#define CHECK(x) if ((error = ERROR_ASSERT (x))) goto done;
1053
1054 for (i = 0; i < hash_capacity (v); i++)
1055 {
Dave Barachc3799992016-08-15 11:12:27 -04001056 hash_pair_union_t *pu = get_pair (v, i);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001057
1058 if (hash_is_user (v, i))
1059 {
1060 CHECK (pu->direct.key != 0);
1061 vec_add1 (keys, pu->direct.key);
1062 }
1063 else
1064 {
Dave Barachc3799992016-08-15 11:12:27 -04001065 hash_pair_t *p;
1066 hash_pair_indirect_t *pi = &pu->indirect;
Ed Warnickecb9cada2015-12-08 15:45:58 -07001067 uword n;
1068
1069 n = h->log2_pair_size > 0
Dave Barachc3799992016-08-15 11:12:27 -04001070 ? indirect_pair_get_len (pi) : vec_len (pi->pairs);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001071
1072 for (p = pi->pairs; n-- > 0; p = hash_forward1 (h, p))
1073 {
1074 /* Assert key uniqueness. */
1075 for (j = 0; j < vec_len (keys); j++)
1076 CHECK (keys[j] != p->key);
1077 vec_add1 (keys, p->key);
1078 }
1079 }
1080 }
1081
1082 CHECK (vec_len (keys) == h->elts);
1083
1084 vec_free (keys);
Dave Barachc3799992016-08-15 11:12:27 -04001085done:
Ed Warnickecb9cada2015-12-08 15:45:58 -07001086 return error;
1087}
Dave Barachc3799992016-08-15 11:12:27 -04001088
1089/*
1090 * fd.io coding-style-patch-verification: ON
1091 *
1092 * Local Variables:
1093 * eval: (c-set-style "gnu")
1094 * End:
1095 */