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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 Copyright (c) 2010 Eliot Dresselhaus
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:
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
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.
38 #include <vppinfra/mhash.h>
41 load_partial_u32 (void *d, uword n)
44 return ((u32 *) d)[0];
46 return ((u16 *) d)[0] | (((u8 *) d)[2] << 16);
48 return ((u16 *) d)[0];
56 mhash_key_sum_inline (void *data, uword n_data_bytes, u32 seed)
62 n_left = n_data_bytes;
70 hash_v3_mix32 (a, b, c);
77 c += load_partial_u32 (d32 + 2, n_left - 8);
82 b += load_partial_u32 (d32 + 1, n_left - 4);
86 a += load_partial_u32 (d32 + 0, n_left - 0);
88 hash_v3_finalize32 (a, b, c);
93 #define foreach_mhash_key_size \
94 _ (2) _ (3) _ (4) _ (5) _ (6) _ (7) \
95 _ (8) _ (12) _ (16) _ (20) \
96 _ (24) _ (28) _ (32) _ (36) \
97 _ (40) _ (44) _ (48) _ (52) \
100 #define _(N_KEY_BYTES) \
102 mhash_key_sum_##N_KEY_BYTES (hash_t * h, uword key) \
104 mhash_t * hv = uword_to_pointer (h->user, mhash_t *); \
105 return mhash_key_sum_inline (mhash_key_to_mem (hv, key), \
111 mhash_key_equal_##N_KEY_BYTES (hash_t * h, uword key1, uword key2) \
113 mhash_t * hv = uword_to_pointer (h->user, mhash_t *); \
114 void * k1 = mhash_key_to_mem (hv, key1); \
115 void * k2 = mhash_key_to_mem (hv, key2); \
116 return ! memcmp (k1, k2, (N_KEY_BYTES)); \
119 foreach_mhash_key_size
122 mhash_key_sum_c_string (hash_t * h, uword key)
124 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
125 void *k = mhash_key_to_mem (hv, key);
126 return mhash_key_sum_inline (k, strlen (k), hv->hash_seed);
130 mhash_key_equal_c_string (hash_t * h, uword key1, uword key2)
132 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
133 void *k1 = mhash_key_to_mem (hv, key1);
134 void *k2 = mhash_key_to_mem (hv, key2);
135 return strcmp (k1, k2) == 0;
139 mhash_key_sum_vec_string (hash_t * h, uword key)
141 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
142 void *k = mhash_key_to_mem (hv, key);
143 return mhash_key_sum_inline (k, vec_len (k), hv->hash_seed);
147 mhash_key_equal_vec_string (hash_t * h, uword key1, uword key2)
149 mhash_t *hv = uword_to_pointer (h->user, mhash_t *);
150 void *k1 = mhash_key_to_mem (hv, key1);
151 void *k2 = mhash_key_to_mem (hv, key2);
152 return vec_len (k1) == vec_len (k2) && memcmp (k1, k2, vec_len (k1)) == 0;
155 /* The CLIB hash user pointer must always point to a valid mhash_t.
156 Now, the address of mhash_t can change (think vec_resize).
157 So we must always be careful that it points to the correct
160 mhash_sanitize_hash_user (mhash_t * mh)
162 uword *hash = mh->hash;
163 hash_t *h = hash_header (hash);
164 h->user = pointer_to_uword (mh);
167 static u8 *mhash_format_pair_default (u8 *s, va_list *args);
170 mhash_init (mhash_t * h, uword n_value_bytes, uword n_key_bytes)
174 hash_key_sum_function_t *key_sum;
175 hash_key_equal_function_t *key_equal;
178 #define _(N_KEY_BYTES) \
180 .key_sum = mhash_key_sum_##N_KEY_BYTES, \
181 .key_equal = mhash_key_equal_##N_KEY_BYTES, \
184 foreach_mhash_key_size
186 [MHASH_C_STRING_KEY] =
188 .key_sum = mhash_key_sum_c_string,.key_equal = mhash_key_equal_c_string,},
189 [MHASH_VEC_STRING_KEY] =
191 .key_sum = mhash_key_sum_vec_string,.key_equal =
192 mhash_key_equal_vec_string,},};
194 if (mhash_key_vector_is_heap (h))
195 heap_free (h->key_vector_or_heap);
197 vec_free (h->key_vector_or_heap);
198 vec_free (h->key_vector_free_indices);
201 for (i = 0; i < vec_len (h->key_tmps); i++)
202 vec_free (h->key_tmps[i]);
204 vec_free (h->key_tmps);
207 clib_memset (h, 0, sizeof (h[0]));
208 h->n_key_bytes = n_key_bytes;
210 vec_validate (h->key_tmps, os_get_nthreads () - 1);
212 ASSERT (n_key_bytes < ARRAY_LEN (t));
213 h->hash = hash_create2 (/* elts */ 0,
214 /* user */ pointer_to_uword (h),
215 /* value_bytes */ n_value_bytes,
216 t[n_key_bytes].key_sum, t[n_key_bytes].key_equal,
217 /* format pair/arg */
218 mhash_format_pair_default, 0);
222 mhash_set_tmp_key (mhash_t * h, const void *key)
225 int my_cpu = os_get_thread_index ();
227 key_tmp = h->key_tmps[my_cpu];
229 vec_reset_length (key_tmp);
231 if (mhash_key_vector_is_heap (h))
233 uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
236 vec_add (key_tmp, key, strlen (key) + 1);
238 vec_add (key_tmp, key, vec_len (key));
241 vec_add (key_tmp, key, h->n_key_bytes);
243 h->key_tmps[my_cpu] = key_tmp;
248 __clib_export hash_pair_t *
249 mhash_get_pair (mhash_t * h, const void *key)
252 mhash_sanitize_hash_user (h);
253 ikey = mhash_set_tmp_key (h, key);
254 return hash_get_pair (h->hash, ikey);
261 /* Must coincide with vec_header. */
263 } mhash_string_key_t;
266 mhash_set_mem (mhash_t * h, void *key, uword * new_value, uword * old_value)
269 uword ikey, i, l = 0, n_key_bytes, old_n_elts, key_alloc_from_free_list = 0;
271 mhash_sanitize_hash_user (h);
273 if (mhash_key_vector_is_heap (h))
275 mhash_string_key_t *sk;
276 uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
279 n_key_bytes = is_c_string ? (strlen (key) + 1) : vec_len (key);
281 heap_alloc (h->key_vector_or_heap, n_key_bytes + sizeof (sk[0]),
284 sk = (void *) (h->key_vector_or_heap + i);
285 sk->heap_handle = handle;
286 sk->vec.len = n_key_bytes;
287 clib_memcpy_fast (sk->vec.vector_data, key, n_key_bytes);
289 /* Advance key past vector header. */
294 key_alloc_from_free_list = (l =
295 vec_len (h->key_vector_free_indices)) > 0;
296 if (key_alloc_from_free_list)
298 i = h->key_vector_free_indices[l - 1];
299 k = vec_elt_at_index (h->key_vector_or_heap, i);
300 vec_set_len (h->key_vector_free_indices, l - 1);
304 vec_add2 (h->key_vector_or_heap, k, h->n_key_bytes);
305 i = k - h->key_vector_or_heap;
308 n_key_bytes = h->n_key_bytes;
309 clib_memcpy_fast (k, key, n_key_bytes);
313 old_n_elts = hash_elts (h->hash);
314 h->hash = _hash_set3 (h->hash, ikey, new_value, old_value);
316 /* If element already existed remove duplicate key. */
317 if (hash_elts (h->hash) == old_n_elts)
321 /* Fetch old key for return value. */
322 p = hash_get_pair (h->hash, ikey);
325 /* Remove duplicate key. */
326 if (mhash_key_vector_is_heap (h))
328 mhash_string_key_t *sk;
329 sk = (void *) (h->key_vector_or_heap + i - sizeof (sk[0]));
330 heap_dealloc (h->key_vector_or_heap, sk->heap_handle);
334 if (key_alloc_from_free_list)
336 vec_set_len (h->key_vector_free_indices, l);
337 h->key_vector_free_indices[l - 1] = i;
340 vec_dec_len (h->key_vector_or_heap, h->n_key_bytes);
348 mhash_unset (mhash_t * h, void *key, uword * old_value)
353 mhash_sanitize_hash_user (h);
354 i = mhash_set_tmp_key (h, key);
356 p = hash_get_pair (h->hash, i);
360 ASSERT (p->key != ~0);
363 if (mhash_key_vector_is_heap (h))
365 mhash_string_key_t *sk;
366 sk = (void *) (h->key_vector_or_heap + i) - sizeof (sk[0]);
367 heap_dealloc (h->key_vector_or_heap, sk->heap_handle);
370 vec_add1 (h->key_vector_free_indices, i);
372 hash_unset3 (h->hash, i, old_value);
377 format_mhash_key (u8 *s, va_list *va)
379 mhash_t *h = va_arg (*va, mhash_t *);
380 u32 ki = va_arg (*va, u32);
381 void *k = mhash_key_to_mem (h, ki);
383 if (mhash_key_vector_is_heap (h))
385 uword is_c_string = h->n_key_bytes == MHASH_C_STRING_KEY;
386 u32 l = is_c_string ? strlen (k) : vec_len (k);
389 else if (h->format_key)
390 s = format (s, "%U", h->format_key, k);
392 s = format (s, "0x%U", format_hex_bytes, k, h->n_key_bytes);
398 mhash_format_pair_default (u8 *s, va_list *args)
400 void *CLIB_UNUSED (user_arg) = va_arg (*args, void *);
401 void *v = va_arg (*args, void *);
402 hash_pair_t *p = va_arg (*args, hash_pair_t *);
403 hash_t *h = hash_header (v);
404 mhash_t *mh = uword_to_pointer (h->user, mhash_t *);
406 s = format (s, "%U", format_mhash_key, mh, (u32) p->key);
407 if (hash_value_bytes (h) > 0)
408 s = format (s, " -> 0x%8U", format_hex_bytes, &p->value[0],
409 hash_value_bytes (h));
414 format_mhash (u8 *s, va_list *va)
416 mhash_t *h = va_arg (*va, mhash_t *);
417 int verbose = va_arg (*va, int);
419 s = format (s, "mhash %p, %wd elts, \n", h, mhash_elts (h));
420 if (mhash_key_vector_is_heap (h))
421 s = format (s, " %U", format_heap, h->key_vector_or_heap, verbose);
423 s = format (s, " keys %wd elts, %wd size, %wd free, %wd bytes used\n",
424 vec_len (h->key_vector_or_heap) / h->n_key_bytes,
425 h->n_key_bytes, vec_len (h->key_vector_free_indices),
426 vec_bytes (h->key_vector_or_heap) +
427 vec_bytes (h->key_vector_free_indices));
428 s = format (s, " %U", format_hash, h->hash, verbose);
434 * fd.io coding-style-patch-verification: ON
437 * eval: (c-set-style "gnu")