table.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2009-2021, Google LLC
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of Google LLC nor the
13  * names of its contributors may be used to endorse or promote products
14  * derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27 
28 /*
29  * upb_table Implementation
30  *
31  * Implementation is heavily inspired by Lua's ltable.c.
32  */
33 
34 #include <string.h>
35 
36 #include "upb/table_internal.h"
37 
38 /* Must be last. */
39 #include "upb/port_def.inc"
40 
41 #define UPB_MAXARRSIZE 16 /* 64k. */
42 
43 /* From Chromium. */
44 #define ARRAY_SIZE(x) \
45  ((sizeof(x) / sizeof(0 [x])) / ((size_t)(!(sizeof(x) % sizeof(0 [x])))))
46 
47 static const double MAX_LOAD = 0.85;
48 
49 /* The minimum utilization of the array part of a mixed hash/array table. This
50  * is a speed/memory-usage tradeoff (though it's not straightforward because of
51  * cache effects). The lower this is, the more memory we'll use. */
52 static const double MIN_DENSITY = 0.1;
53 
54 static bool is_pow2(uint64_t v) { return v == 0 || (v & (v - 1)) == 0; }
55 
57  upb_value ret;
58  _upb_value_setval(&ret, val);
59  return ret;
60 }
61 
62 static int log2ceil(uint64_t v) {
63  int ret = 0;
64  bool pow2 = is_pow2(v);
65  while (v >>= 1) ret++;
66  ret = pow2 ? ret : ret + 1; /* Ceiling. */
67  return UPB_MIN(UPB_MAXARRSIZE, ret);
68 }
69 
70 char* upb_strdup2(const char* s, size_t len, upb_Arena* a) {
71  size_t n;
72  char* p;
73 
74  /* Prevent overflow errors. */
75  if (len == SIZE_MAX) return NULL;
76  /* Always null-terminate, even if binary data; but don't rely on the input to
77  * have a null-terminating byte since it may be a raw binary buffer. */
78  n = len + 1;
79  p = upb_Arena_Malloc(a, n);
80  if (p) {
81  memcpy(p, s, len);
82  p[len] = 0;
83  }
84  return p;
85 }
86 
87 /* A type to represent the lookup key of either a strtable or an inttable. */
88 typedef union {
89  uintptr_t num;
90  struct {
91  const char* str;
92  size_t len;
93  } str;
94 } lookupkey_t;
95 
96 static lookupkey_t strkey2(const char* str, size_t len) {
97  lookupkey_t k;
98  k.str.str = str;
99  k.str.len = len;
100  return k;
101 }
102 
104  lookupkey_t k;
105  k.num = key;
106  return k;
107 }
108 
111 
112 /* Base table (shared code) ***************************************************/
113 
115 
116 static const upb_tabent* upb_getentry(const upb_table* t, uint32_t hash) {
117  return t->entries + (hash & t->mask);
118 }
119 
120 static bool upb_arrhas(upb_tabval key) { return key.val != (uint64_t)-1; }
121 
122 static bool isfull(upb_table* t) { return t->count == t->max_count; }
123 
124 static bool init(upb_table* t, uint8_t size_lg2, upb_Arena* a) {
125  size_t bytes;
126 
127  t->count = 0;
128  t->size_lg2 = size_lg2;
129  t->mask = upb_table_size(t) ? upb_table_size(t) - 1 : 0;
130  t->max_count = upb_table_size(t) * MAX_LOAD;
131  bytes = upb_table_size(t) * sizeof(upb_tabent);
132  if (bytes > 0) {
133  t->entries = upb_Arena_Malloc(a, bytes);
134  if (!t->entries) return false;
135  memset(t->entries, 0, bytes);
136  } else {
137  t->entries = NULL;
138  }
139  return true;
140 }
141 
143  upb_tabent* begin = t->entries;
145  for (e = e + 1; e < end; e++) {
146  if (upb_tabent_isempty(e)) return e;
147  }
148  for (e = begin; e < end; e++) {
149  if (upb_tabent_isempty(e)) return e;
150  }
151  UPB_ASSERT(false);
152  return NULL;
153 }
154 
156  return (upb_tabent*)upb_getentry(t, hash);
157 }
158 
159 static const upb_tabent* findentry(const upb_table* t, lookupkey_t key,
160  uint32_t hash, eqlfunc_t* eql) {
161  const upb_tabent* e;
162 
163  if (t->size_lg2 == 0) return NULL;
164  e = upb_getentry(t, hash);
165  if (upb_tabent_isempty(e)) return NULL;
166  while (1) {
167  if (eql(e->key, key)) return e;
168  if ((e = e->next) == NULL) return NULL;
169  }
170 }
171 
173  uint32_t hash, eqlfunc_t* eql) {
174  return (upb_tabent*)findentry(t, key, hash, eql);
175 }
176 
177 static bool lookup(const upb_table* t, lookupkey_t key, upb_value* v,
178  uint32_t hash, eqlfunc_t* eql) {
179  const upb_tabent* e = findentry(t, key, hash, eql);
180  if (e) {
181  if (v) {
182  _upb_value_setval(v, e->val.val);
183  }
184  return true;
185  } else {
186  return false;
187  }
188 }
189 
190 /* The given key must not already exist in the table. */
191 static void insert(upb_table* t, lookupkey_t key, upb_tabkey tabkey,
192  upb_value val, uint32_t hash, hashfunc_t* hashfunc,
193  eqlfunc_t* eql) {
194  upb_tabent* mainpos_e;
195  upb_tabent* our_e;
196 
197  UPB_ASSERT(findentry(t, key, hash, eql) == NULL);
198 
199  t->count++;
200  mainpos_e = getentry_mutable(t, hash);
201  our_e = mainpos_e;
202 
203  if (upb_tabent_isempty(mainpos_e)) {
204  /* Our main position is empty; use it. */
205  our_e->next = NULL;
206  } else {
207  /* Collision. */
208  upb_tabent* new_e = emptyent(t, mainpos_e);
209  /* Head of collider's chain. */
210  upb_tabent* chain = getentry_mutable(t, hashfunc(mainpos_e->key));
211  if (chain == mainpos_e) {
212  /* Existing ent is in its main position (it has the same hash as us, and
213  * is the head of our chain). Insert to new ent and append to this chain.
214  */
215  new_e->next = mainpos_e->next;
216  mainpos_e->next = new_e;
217  our_e = new_e;
218  } else {
219  /* Existing ent is not in its main position (it is a node in some other
220  * chain). This implies that no existing ent in the table has our hash.
221  * Evict it (updating its chain) and use its ent for head of our chain. */
222  *new_e = *mainpos_e; /* copies next. */
223  while (chain->next != mainpos_e) {
224  chain = (upb_tabent*)chain->next;
225  UPB_ASSERT(chain);
226  }
227  chain->next = new_e;
228  our_e = mainpos_e;
229  our_e->next = NULL;
230  }
231  }
232  our_e->key = tabkey;
233  our_e->val.val = val.val;
234  UPB_ASSERT(findentry(t, key, hash, eql) == our_e);
235 }
236 
237 static bool rm(upb_table* t, lookupkey_t key, upb_value* val,
238  upb_tabkey* removed, uint32_t hash, eqlfunc_t* eql) {
239  upb_tabent* chain = getentry_mutable(t, hash);
240  if (upb_tabent_isempty(chain)) return false;
241  if (eql(chain->key, key)) {
242  /* Element to remove is at the head of its chain. */
243  t->count--;
244  if (val) _upb_value_setval(val, chain->val.val);
245  if (removed) *removed = chain->key;
246  if (chain->next) {
247  upb_tabent* move = (upb_tabent*)chain->next;
248  *chain = *move;
249  move->key = 0; /* Make the slot empty. */
250  } else {
251  chain->key = 0; /* Make the slot empty. */
252  }
253  return true;
254  } else {
255  /* Element to remove is either in a non-head position or not in the
256  * table. */
257  while (chain->next && !eql(chain->next->key, key)) {
258  chain = (upb_tabent*)chain->next;
259  }
260  if (chain->next) {
261  /* Found element to remove. */
262  upb_tabent* rm = (upb_tabent*)chain->next;
263  t->count--;
264  if (val) _upb_value_setval(val, chain->next->val.val);
265  if (removed) *removed = rm->key;
266  rm->key = 0; /* Make the slot empty. */
267  chain->next = rm->next;
268  return true;
269  } else {
270  /* Element to remove is not in the table. */
271  return false;
272  }
273  }
274 }
275 
276 static size_t next(const upb_table* t, size_t i) {
277  do {
278  if (++i >= upb_table_size(t)) return SIZE_MAX - 1; /* Distinct from -1. */
279  } while (upb_tabent_isempty(&t->entries[i]));
280 
281  return i;
282 }
283 
284 static size_t begin(const upb_table* t) { return next(t, -1); }
285 
286 /* upb_strtable ***************************************************************/
287 
288 /* A simple "subclass" of upb_table that only adds a hash function for strings.
289  */
290 
292  uint32_t len = (uint32_t)k2.str.len;
293  char* str = upb_Arena_Malloc(a, k2.str.len + sizeof(uint32_t) + 1);
294  if (str == NULL) return 0;
295  memcpy(str, &len, sizeof(uint32_t));
296  if (k2.str.len) memcpy(str + sizeof(uint32_t), k2.str.str, k2.str.len);
297  str[sizeof(uint32_t) + k2.str.len] = '\0';
298  return (uintptr_t)str;
299 }
300 
301 /* Adapted from ABSL's wyhash. */
302 
303 static uint64_t UnalignedLoad64(const void* p) {
304  uint64_t val;
305  memcpy(&val, p, 8);
306  return val;
307 }
308 
309 static uint32_t UnalignedLoad32(const void* p) {
310  uint32_t val;
311  memcpy(&val, p, 4);
312  return val;
313 }
314 
315 #if defined(_MSC_VER) && defined(_M_X64)
316 #include <intrin.h>
317 #endif
318 
319 /* Computes a * b, returning the low 64 bits of the result and storing the high
320  * 64 bits in |*high|. */
321 static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t* out_high) {
322 #ifdef __SIZEOF_INT128__
323  __uint128_t p = v0;
324  p *= v1;
325  *out_high = (uint64_t)(p >> 64);
326  return (uint64_t)p;
327 #elif defined(_MSC_VER) && defined(_M_X64)
328  return _umul128(v0, v1, out_high);
329 #else
330  uint64_t a32 = v0 >> 32;
331  uint64_t a00 = v0 & 0xffffffff;
332  uint64_t b32 = v1 >> 32;
333  uint64_t b00 = v1 & 0xffffffff;
334  uint64_t high = a32 * b32;
335  uint64_t low = a00 * b00;
336  uint64_t mid1 = a32 * b00;
337  uint64_t mid2 = a00 * b32;
338  low += (mid1 << 32) + (mid2 << 32);
339  // Omit carry bit, for mixing we do not care about exact numerical precision.
340  high += (mid1 >> 32) + (mid2 >> 32);
341  *out_high = high;
342  return low;
343 #endif
344 }
345 
347  uint64_t high;
348  uint64_t low = upb_umul128(v0, v1, &high);
349  return low ^ high;
350 }
351 
352 static uint64_t Wyhash(const void* data, size_t len, uint64_t seed,
353  const uint64_t salt[]) {
354  const uint8_t* ptr = (const uint8_t*)data;
355  uint64_t starting_length = (uint64_t)len;
356  uint64_t current_state = seed ^ salt[0];
357 
358  if (len > 64) {
359  // If we have more than 64 bytes, we're going to handle chunks of 64
360  // bytes at a time. We're going to build up two separate hash states
361  // which we will then hash together.
362  uint64_t duplicated_state = current_state;
363 
364  do {
366  uint64_t b = UnalignedLoad64(ptr + 8);
367  uint64_t c = UnalignedLoad64(ptr + 16);
368  uint64_t d = UnalignedLoad64(ptr + 24);
369  uint64_t e = UnalignedLoad64(ptr + 32);
370  uint64_t f = UnalignedLoad64(ptr + 40);
371  uint64_t g = UnalignedLoad64(ptr + 48);
372  uint64_t h = UnalignedLoad64(ptr + 56);
373 
374  uint64_t cs0 = WyhashMix(a ^ salt[1], b ^ current_state);
375  uint64_t cs1 = WyhashMix(c ^ salt[2], d ^ current_state);
376  current_state = (cs0 ^ cs1);
377 
378  uint64_t ds0 = WyhashMix(e ^ salt[3], f ^ duplicated_state);
379  uint64_t ds1 = WyhashMix(g ^ salt[4], h ^ duplicated_state);
380  duplicated_state = (ds0 ^ ds1);
381 
382  ptr += 64;
383  len -= 64;
384  } while (len > 64);
385 
386  current_state = current_state ^ duplicated_state;
387  }
388 
389  // We now have a data `ptr` with at most 64 bytes and the current state
390  // of the hashing state machine stored in current_state.
391  while (len > 16) {
393  uint64_t b = UnalignedLoad64(ptr + 8);
394 
395  current_state = WyhashMix(a ^ salt[1], b ^ current_state);
396 
397  ptr += 16;
398  len -= 16;
399  }
400 
401  // We now have a data `ptr` with at most 16 bytes.
402  uint64_t a = 0;
403  uint64_t b = 0;
404  if (len > 8) {
405  // When we have at least 9 and at most 16 bytes, set A to the first 64
406  // bits of the input and B to the last 64 bits of the input. Yes, they will
407  // overlap in the middle if we are working with less than the full 16
408  // bytes.
409  a = UnalignedLoad64(ptr);
410  b = UnalignedLoad64(ptr + len - 8);
411  } else if (len > 3) {
412  // If we have at least 4 and at most 8 bytes, set A to the first 32
413  // bits and B to the last 32 bits.
414  a = UnalignedLoad32(ptr);
415  b = UnalignedLoad32(ptr + len - 4);
416  } else if (len > 0) {
417  // If we have at least 1 and at most 3 bytes, read all of the provided
418  // bits into A, with some adjustments.
419  a = ((ptr[0] << 16) | (ptr[len >> 1] << 8) | ptr[len - 1]);
420  b = 0;
421  } else {
422  a = 0;
423  b = 0;
424  }
425 
426  uint64_t w = WyhashMix(a ^ salt[1], b ^ current_state);
427  uint64_t z = salt[1] ^ starting_length;
428  return WyhashMix(w, z);
429 }
430 
431 const uint64_t kWyhashSalt[5] = {
432  0x243F6A8885A308D3ULL, 0x13198A2E03707344ULL, 0xA4093822299F31D0ULL,
433  0x082EFA98EC4E6C89ULL, 0x452821E638D01377ULL,
434 };
435 
436 uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed) {
437  return Wyhash(p, n, seed, kWyhashSalt);
438 }
439 
440 static uint32_t _upb_Hash_NoSeed(const char* p, size_t n) {
441  return _upb_Hash(p, n, 0);
442 }
443 
445  uint32_t len;
446  char* str = upb_tabstr(key, &len);
447  return _upb_Hash_NoSeed(str, len);
448 }
449 
451  uint32_t len;
452  char* str = upb_tabstr(k1, &len);
453  return len == k2.str.len && (len == 0 || memcmp(str, k2.str.str, len) == 0);
454 }
455 
456 bool upb_strtable_init(upb_strtable* t, size_t expected_size, upb_Arena* a) {
457  // Multiply by approximate reciprocal of MAX_LOAD (0.85), with pow2
458  // denominator.
459  size_t need_entries = (expected_size + 1) * 1204 / 1024;
460  UPB_ASSERT(need_entries >= expected_size * 0.85);
461  int size_lg2 = _upb_Log2Ceiling(need_entries);
462  return init(&t->t, size_lg2, a);
463 }
464 
466  size_t bytes = upb_table_size(&t->t) * sizeof(upb_tabent);
467  t->t.count = 0;
468  memset((char*)t->t.entries, 0, bytes);
469 }
470 
471 bool upb_strtable_resize(upb_strtable* t, size_t size_lg2, upb_Arena* a) {
472  upb_strtable new_table;
474 
475  if (!init(&new_table.t, size_lg2, a)) return false;
476  upb_strtable_begin(&i, t);
477  for (; !upb_strtable_done(&i); upb_strtable_next(&i)) {
479  upb_strtable_insert(&new_table, key.data, key.size,
481  }
482  *t = new_table;
483  return true;
484 }
485 
486 bool upb_strtable_insert(upb_strtable* t, const char* k, size_t len,
487  upb_value v, upb_Arena* a) {
489  upb_tabkey tabkey;
490  uint32_t hash;
491 
492  if (isfull(&t->t)) {
493  /* Need to resize. New table of double the size, add old elements to it. */
494  if (!upb_strtable_resize(t, t->t.size_lg2 + 1, a)) {
495  return false;
496  }
497  }
498 
499  key = strkey2(k, len);
500  tabkey = strcopy(key, a);
501  if (tabkey == 0) return false;
502 
503  hash = _upb_Hash_NoSeed(key.str.str, key.str.len);
504  insert(&t->t, key, tabkey, v, hash, &strhash, &streql);
505  return true;
506 }
507 
508 bool upb_strtable_lookup2(const upb_strtable* t, const char* key, size_t len,
509  upb_value* v) {
511  return lookup(&t->t, strkey2(key, len), v, hash, &streql);
512 }
513 
514 bool upb_strtable_remove2(upb_strtable* t, const char* key, size_t len,
515  upb_value* val) {
517  upb_tabkey tabkey;
518  return rm(&t->t, strkey2(key, len), val, &tabkey, hash, &streql);
519 }
520 
521 /* Iteration */
522 
524  i->t = t;
525  i->index = begin(&t->t);
526 }
527 
529  i->index = next(&i->t->t, i->index);
530 }
531 
533  if (!i->t) return true;
534  return i->index >= upb_table_size(&i->t->t) ||
536 }
537 
540  uint32_t len;
542  key.data = upb_tabstr(str_tabent(i)->key, &len);
543  key.size = len;
544  return key;
545 }
546 
549  return _upb_value_val(str_tabent(i)->val.val);
550 }
551 
553  i->t = NULL;
554  i->index = SIZE_MAX;
555 }
556 
558  const upb_strtable_iter* i2) {
559  if (upb_strtable_done(i1) && upb_strtable_done(i2)) return true;
560  return i1->t == i2->t && i1->index == i2->index;
561 }
562 
563 /* upb_inttable ***************************************************************/
564 
565 /* For inttables we use a hybrid structure where small keys are kept in an
566  * array and large keys are put in the hash table. */
567 
569 
570 static bool inteql(upb_tabkey k1, lookupkey_t k2) { return k1 == k2.num; }
571 
573  return (upb_tabval*)t->array;
574 }
575 
577  if (key < t->array_size) {
578  return upb_arrhas(t->array[key]) ? &(mutable_array(t)[key]) : NULL;
579  } else {
580  upb_tabent* e =
582  return e ? &e->val : NULL;
583  }
584 }
585 
587  uintptr_t key) {
588  return inttable_val((upb_inttable*)t, key);
589 }
590 
592  return t->t.count + t->array_count;
593 }
594 
595 static void check(upb_inttable* t) {
596  UPB_UNUSED(t);
597 #if defined(UPB_DEBUG_TABLE) && !defined(NDEBUG)
598  {
599  /* This check is very expensive (makes inserts/deletes O(N)). */
600  size_t count = 0;
602  upb_inttable_begin(&i, t);
603  for (; !upb_inttable_done(&i); upb_inttable_next(&i), count++) {
605  }
607  }
608 #endif
609 }
610 
611 bool upb_inttable_sizedinit(upb_inttable* t, size_t asize, int hsize_lg2,
612  upb_Arena* a) {
613  size_t array_bytes;
614 
615  if (!init(&t->t, hsize_lg2, a)) return false;
616  /* Always make the array part at least 1 long, so that we know key 0
617  * won't be in the hash part, which simplifies things. */
618  t->array_size = UPB_MAX(1, asize);
619  t->array_count = 0;
620  array_bytes = t->array_size * sizeof(upb_value);
621  t->array = upb_Arena_Malloc(a, array_bytes);
622  if (!t->array) {
623  return false;
624  }
625  memset(mutable_array(t), 0xff, array_bytes);
626  check(t);
627  return true;
628 }
629 
631  return upb_inttable_sizedinit(t, 0, 4, a);
632 }
633 
635  upb_Arena* a) {
636  upb_tabval tabval;
637  tabval.val = val.val;
638  UPB_ASSERT(
639  upb_arrhas(tabval)); /* This will reject (uint64_t)-1. Fix this. */
640 
641  if (key < t->array_size) {
642  UPB_ASSERT(!upb_arrhas(t->array[key]));
643  t->array_count++;
644  mutable_array(t)[key].val = val.val;
645  } else {
646  if (isfull(&t->t)) {
647  /* Need to resize the hash part, but we re-use the array part. */
648  size_t i;
649  upb_table new_table;
650 
651  if (!init(&new_table, t->t.size_lg2 + 1, a)) {
652  return false;
653  }
654 
655  for (i = begin(&t->t); i < upb_table_size(&t->t); i = next(&t->t, i)) {
656  const upb_tabent* e = &t->t.entries[i];
657  uint32_t hash;
658  upb_value v;
659 
660  _upb_value_setval(&v, e->val.val);
661  hash = upb_inthash(e->key);
662  insert(&new_table, intkey(e->key), e->key, v, hash, &inthash, &inteql);
663  }
664 
665  UPB_ASSERT(t->t.count == new_table.count);
666 
667  t->t = new_table;
668  }
669  insert(&t->t, intkey(key), key, val, upb_inthash(key), &inthash, &inteql);
670  }
671  check(t);
672  return true;
673 }
674 
676  const upb_tabval* table_v = inttable_val_const(t, key);
677  if (!table_v) return false;
678  if (v) _upb_value_setval(v, table_v->val);
679  return true;
680 }
681 
683  upb_tabval* table_v = inttable_val(t, key);
684  if (!table_v) return false;
685  table_v->val = val.val;
686  return true;
687 }
688 
690  bool success;
691  if (key < t->array_size) {
692  if (upb_arrhas(t->array[key])) {
694  t->array_count--;
695  if (val) {
696  _upb_value_setval(val, t->array[key].val);
697  }
698  mutable_array(t)[key] = empty;
699  success = true;
700  } else {
701  success = false;
702  }
703  } else {
704  success = rm(&t->t, intkey(key), val, NULL, upb_inthash(key), &inteql);
705  }
706  check(t);
707  return success;
708 }
709 
711  /* A power-of-two histogram of the table keys. */
712  size_t counts[UPB_MAXARRSIZE + 1] = {0};
713 
714  /* The max key in each bucket. */
715  uintptr_t max[UPB_MAXARRSIZE + 1] = {0};
716 
718  size_t arr_count;
719  int size_lg2;
720  upb_inttable new_t;
721 
722  upb_inttable_begin(&i, t);
723  for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
725  int bucket = log2ceil(key);
726  max[bucket] = UPB_MAX(max[bucket], key);
727  counts[bucket]++;
728  }
729 
730  /* Find the largest power of two that satisfies the MIN_DENSITY
731  * definition (while actually having some keys). */
732  arr_count = upb_inttable_count(t);
733 
734  for (size_lg2 = ARRAY_SIZE(counts) - 1; size_lg2 > 0; size_lg2--) {
735  if (counts[size_lg2] == 0) {
736  /* We can halve again without losing any entries. */
737  continue;
738  } else if (arr_count >= (1 << size_lg2) * MIN_DENSITY) {
739  break;
740  }
741 
742  arr_count -= counts[size_lg2];
743  }
744 
745  UPB_ASSERT(arr_count <= upb_inttable_count(t));
746 
747  {
748  /* Insert all elements into new, perfectly-sized table. */
749  size_t arr_size = max[size_lg2] + 1; /* +1 so arr[max] will fit. */
750  size_t hash_count = upb_inttable_count(t) - arr_count;
751  size_t hash_size = hash_count ? (hash_count / MAX_LOAD) + 1 : 0;
752  int hashsize_lg2 = log2ceil(hash_size);
753 
754  upb_inttable_sizedinit(&new_t, arr_size, hashsize_lg2, a);
755  upb_inttable_begin(&i, t);
756  for (; !upb_inttable_done(&i); upb_inttable_next(&i)) {
759  }
760  UPB_ASSERT(new_t.array_size == arr_size);
761  UPB_ASSERT(new_t.t.size_lg2 == hashsize_lg2);
762  }
763  *t = new_t;
764 }
765 
766 /* Iteration. */
767 
768 static const upb_tabent* int_tabent(const upb_inttable_iter* i) {
769  UPB_ASSERT(!i->array_part);
770  return &i->t->t.entries[i->index];
771 }
772 
774  UPB_ASSERT(i->array_part);
775  return i->t->array[i->index];
776 }
777 
779  i->t = t;
780  i->index = -1;
781  i->array_part = true;
783 }
784 
786  const upb_inttable* t = iter->t;
787  if (iter->array_part) {
788  while (++iter->index < t->array_size) {
789  if (upb_arrhas(int_arrent(iter))) {
790  return;
791  }
792  }
793  iter->array_part = false;
794  iter->index = begin(&t->t);
795  } else {
796  iter->index = next(&t->t, iter->index);
797  }
798 }
799 
801  intptr_t* iter) {
802  intptr_t i = *iter;
803  if (i < t->array_size) {
804  while (++i < t->array_size) {
805  upb_tabval ent = t->array[i];
806  if (upb_arrhas(ent)) {
807  *key = i;
808  *val = _upb_value_val(ent.val);
809  *iter = i;
810  return true;
811  }
812  }
813  }
814 
815  size_t tab_idx = next(&t->t, i == -1 ? -1 : i - t->array_size);
816  if (tab_idx < upb_table_size(&t->t)) {
817  upb_tabent* ent = &t->t.entries[tab_idx];
818  *key = ent->key;
819  *val = _upb_value_val(ent->val.val);
820  *iter = tab_idx + t->array_size;
821  return true;
822  }
823 
824  return false;
825 }
826 
828  intptr_t i = *iter;
829  if (i < t->array_size) {
830  t->array_count--;
831  mutable_array(t)[i].val = -1;
832  } else {
833  upb_tabent* ent = &t->t.entries[i - t->array_size];
834  upb_tabent* prev = NULL;
835 
836  // Linear search, not great.
837  upb_tabent* end = &t->t.entries[upb_table_size(&t->t)];
838  for (upb_tabent* e = t->t.entries; e != end; e++) {
839  if (e->next == ent) {
840  prev = e;
841  break;
842  }
843  }
844 
845  if (prev) {
846  prev->next = ent->next;
847  }
848 
849  t->t.count--;
850  ent->key = 0;
851  ent->next = NULL;
852  }
853 }
854 
856  upb_value* val, intptr_t* iter) {
857  size_t tab_idx = next(&t->t, *iter);
858  if (tab_idx < upb_table_size(&t->t)) {
859  upb_tabent* ent = &t->t.entries[tab_idx];
860  uint32_t len;
861  key->data = upb_tabstr(ent->key, &len);
862  key->size = len;
863  *val = _upb_value_val(ent->val.val);
864  *iter = tab_idx;
865  return true;
866  }
867 
868  return false;
869 }
870 
872  intptr_t i = *iter;
873  upb_tabent* ent = &t->t.entries[i];
874  upb_tabent* prev = NULL;
875 
876  // Linear search, not great.
877  upb_tabent* end = &t->t.entries[upb_table_size(&t->t)];
878  for (upb_tabent* e = t->t.entries; e != end; e++) {
879  if (e->next == ent) {
880  prev = e;
881  break;
882  }
883  }
884 
885  if (prev) {
886  prev->next = ent->next;
887  }
888 
889  t->t.count--;
890  ent->key = 0;
891  ent->next = NULL;
892 }
893 
895  if (!i->t) return true;
896  if (i->array_part) {
897  return i->index >= i->t->array_size || !upb_arrhas(int_arrent(i));
898  } else {
899  return i->index >= upb_table_size(&i->t->t) ||
901  }
902 }
903 
906  return i->array_part ? i->index : int_tabent(i)->key;
907 }
908 
911  return _upb_value_val(i->array_part ? i->t->array[i->index].val
912  : int_tabent(i)->val.val);
913 }
914 
916  i->t = NULL;
917  i->index = SIZE_MAX;
918  i->array_part = false;
919 }
920 
922  const upb_inttable_iter* i2) {
923  if (upb_inttable_done(i1) && upb_inttable_done(i2)) return true;
924  return i1->t == i2->t && i1->index == i2->index &&
925  i1->array_part == i2->array_part;
926 }
xds_interop_client.str
str
Definition: xds_interop_client.py:487
ptr
char * ptr
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:45
strkey2
static lookupkey_t strkey2(const char *str, size_t len)
Definition: table.c:96
log2ceil
static int log2ceil(uint64_t v)
Definition: table.c:62
upb_inttable_sizedinit
bool upb_inttable_sizedinit(upb_inttable *t, size_t asize, int hsize_lg2, upb_Arena *a)
Definition: table.c:611
upb_inttable_removeiter
void upb_inttable_removeiter(upb_inttable *t, intptr_t *iter)
Definition: table.c:827
hashfunc_t
uint32_t hashfunc_t(upb_tabkey key)
Definition: table.c:109
begin
static size_t begin(const upb_table *t)
Definition: table.c:284
mutable_array
static upb_tabval * mutable_array(upb_inttable *t)
Definition: table.c:572
upb_strtable_clear
void upb_strtable_clear(upb_strtable *t)
Definition: table.c:465
memset
return memset(p, 0, total)
UnalignedLoad64
static uint64_t UnalignedLoad64(const void *p)
Definition: table.c:303
upb_tabent_isempty
UPB_INLINE bool upb_tabent_isempty(const upb_tabent *e)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:871
ARRAY_SIZE
#define ARRAY_SIZE(x)
Definition: table.c:44
next
static size_t next(const upb_table *t, size_t i)
Definition: table.c:276
findentry_mutable
static upb_tabent * findentry_mutable(upb_table *t, lookupkey_t key, uint32_t hash, eqlfunc_t *eql)
Definition: table.c:172
upb_inttable_init
bool upb_inttable_init(upb_inttable *t, upb_Arena *a)
Definition: table.c:630
upb_value
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:681
init
static bool init(upb_table *t, uint8_t size_lg2, upb_Arena *a)
Definition: table.c:124
check
static void check(upb_inttable *t)
Definition: table.c:595
string.h
seed
static const uint8_t seed[20]
Definition: dsa_test.cc:79
upb_strtable_next
void upb_strtable_next(upb_strtable_iter *i)
Definition: table.c:528
upb_strtable_lookup2
bool upb_strtable_lookup2(const upb_strtable *t, const char *key, size_t len, upb_value *v)
Definition: table.c:508
Wyhash
static uint64_t Wyhash(const void *data, size_t len, uint64_t seed, const uint64_t salt[])
Definition: table.c:352
upb_tabent
struct _upb_tabent upb_tabent
upb_strdup2
char * upb_strdup2(const char *s, size_t len, upb_Arena *a)
Definition: table.c:70
upb_inttable_replace
bool upb_inttable_replace(upb_inttable *t, uintptr_t key, upb_value val)
Definition: table.c:682
absl::hash_internal::k2
static const uint64_t k2
Definition: abseil-cpp/absl/hash/internal/city.cc:55
int_tabent
static const upb_tabent * int_tabent(const upb_inttable_iter *i)
Definition: table.c:768
inttable_val_const
static const upb_tabval * inttable_val_const(const upb_inttable *t, uintptr_t key)
Definition: table.c:586
upb_tabstr
UPB_INLINE char * upb_tabstr(upb_tabkey key, uint32_t *len)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:789
upb_inttable_begin
void upb_inttable_begin(upb_inttable_iter *i, const upb_inttable *t)
Definition: table.c:778
a
int a
Definition: abseil-cpp/absl/container/internal/hash_policy_traits_test.cc:88
upb_inttable_iter_isequal
bool upb_inttable_iter_isequal(const upb_inttable_iter *i1, const upb_inttable_iter *i2)
Definition: table.c:921
xds_manager.p
p
Definition: xds_manager.py:60
upb_inttable::t
upb_table t
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:849
z
Uncopyable z
Definition: bloaty/third_party/googletest/googlemock/test/gmock-matchers_test.cc:3612
int_arrent
static upb_tabval int_arrent(const upb_inttable_iter *i)
Definition: table.c:773
uint8_t
unsigned char uint8_t
Definition: stdint-msvc2008.h:78
setup.k
k
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
streql
static bool streql(upb_tabkey k1, lookupkey_t k2)
Definition: table.c:450
upb_inttable_next2
bool upb_inttable_next2(const upb_inttable *t, uintptr_t *key, upb_value *val, intptr_t *iter)
Definition: table.c:800
UPB_MIN
#define UPB_MIN(x, y)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:126
hash
uint64_t hash
Definition: ring_hash.cc:284
upb_inttable_count
size_t upb_inttable_count(const upb_inttable *t)
Definition: table.c:591
uint32_t
unsigned int uint32_t
Definition: stdint-msvc2008.h:80
upb_table::count
size_t count
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:819
MAX_LOAD
static const double MAX_LOAD
Definition: table.c:47
upb_strtable_init
bool upb_strtable_init(upb_strtable *t, size_t expected_size, upb_Arena *a)
Definition: table.c:456
ULL
#define ULL(x)
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:57
inteql
static bool inteql(upb_tabkey k1, lookupkey_t k2)
Definition: table.c:570
memcpy
memcpy(mem, inblock.get(), min(CONTAINING_RECORD(inblock.get(), MEMBLOCK, data) ->size, size))
c
void c(T a)
Definition: miscompile_with_no_unique_address_test.cc:40
autogen_x86imm.f
f
Definition: autogen_x86imm.py:9
i1
int i1
Definition: abseil-cpp/absl/container/btree_test.cc:2772
absl::move
constexpr absl::remove_reference_t< T > && move(T &&t) noexcept
Definition: abseil-cpp/absl/utility/utility.h:221
end
char * end
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1008
upb_strtable_removeiter
void upb_strtable_removeiter(upb_strtable *t, intptr_t *iter)
Definition: table.c:871
max
int max
Definition: bloaty/third_party/zlib/examples/enough.c:170
SIZE_MAX
#define SIZE_MAX
Definition: stdint-msvc2008.h:206
_upb_tabent::val
upb_tabval val
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:809
upb_table::size_lg2
uint8_t size_lg2
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:822
eqlfunc_t
bool eqlfunc_t(upb_tabkey k1, lookupkey_t k2)
Definition: table.c:110
setup.v
v
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
upb_inttable_iter
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:1113
inttable_val
static upb_tabval * inttable_val(upb_inttable *t, uintptr_t key)
Definition: table.c:576
upb_Arena_Malloc
UPB_INLINE void * upb_Arena_Malloc(upb_Arena *a, size_t size)
Definition: upb/upb/upb.h:222
getentry_mutable
static upb_tabent * getentry_mutable(upb_table *t, uint32_t hash)
Definition: table.c:155
UPB_MAXARRSIZE
#define UPB_MAXARRSIZE
Definition: table.c:41
table_internal.h
uint64_t
unsigned __int64 uint64_t
Definition: stdint-msvc2008.h:90
upb_tabkey
uintptr_t upb_tabkey
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:787
upb_inttable
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:848
upb_tabval
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:798
upb_strtable_done
bool upb_strtable_done(const upb_strtable_iter *i)
Definition: table.c:532
intptr_t
_W64 signed int intptr_t
Definition: stdint-msvc2008.h:118
upb_inttable_done
bool upb_inttable_done(const upb_inttable_iter *i)
Definition: table.c:894
UPB_ASSERT
#define UPB_ASSERT(expr)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:135
upb_strtable_iter_setdone
void upb_strtable_iter_setdone(upb_strtable_iter *i)
Definition: table.c:552
data
char data[kBufferLength]
Definition: abseil-cpp/absl/strings/internal/str_format/float_conversion.cc:1006
kWyhashSalt
const uint64_t kWyhashSalt[5]
Definition: table.c:431
emptyent
static upb_tabent * emptyent(upb_table *t, upb_tabent *e)
Definition: table.c:142
uintptr_t
_W64 unsigned int uintptr_t
Definition: stdint-msvc2008.h:119
isfull
static bool isfull(upb_table *t)
Definition: table.c:122
b
uint64_t b
Definition: abseil-cpp/absl/container/internal/layout_test.cc:53
MIN_DENSITY
static const double MIN_DENSITY
Definition: table.c:52
g
struct @717 g
_upb_Hash_NoSeed
static uint32_t _upb_Hash_NoSeed(const char *p, size_t n)
Definition: table.c:440
upb_umul128
static uint64_t upb_umul128(uint64_t v0, uint64_t v1, uint64_t *out_high)
Definition: table.c:321
d
static const fe d
Definition: curve25519_tables.h:19
inthash
static uint32_t inthash(upb_tabkey key)
Definition: table.c:568
n
int n
Definition: abseil-cpp/absl/container/btree_test.cc:1080
UPB_TABVALUE_EMPTY_INIT
#define UPB_TABVALUE_EMPTY_INIT
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:802
is_pow2
static bool is_pow2(uint64_t v)
Definition: table.c:54
google_benchmark.example.empty
def empty(state)
Definition: example.py:31
WyhashMix
static uint64_t WyhashMix(uint64_t v0, uint64_t v1)
Definition: table.c:346
_upb_tabent::next
const struct _upb_tabent * next
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:815
UPB_MAX
#define UPB_MAX(x, y)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:125
upb_value::val
uint64_t val
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:682
findentry
static const upb_tabent * findentry(const upb_table *t, lookupkey_t key, uint32_t hash, eqlfunc_t *eql)
Definition: table.c:159
strhash
static uint32_t strhash(upb_tabkey key)
Definition: table.c:444
rm
static bool rm(upb_table *t, lookupkey_t key, upb_value *val, upb_tabkey *removed, uint32_t hash, eqlfunc_t *eql)
Definition: table.c:237
key
const char * key
Definition: hpack_parser_table.cc:164
upb_inttable::array_size
size_t array_size
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:851
upb_strtable_insert
bool upb_strtable_insert(upb_strtable *t, const char *k, size_t len, upb_value v, upb_Arena *a)
Definition: table.c:486
upb_inttable_iter_setdone
void upb_inttable_iter_setdone(upb_inttable_iter *i)
Definition: table.c:915
upb_StringView
Definition: upb/upb/upb.h:72
bytes
uint8 bytes[10]
Definition: bloaty/third_party/protobuf/src/google/protobuf/io/coded_stream_unittest.cc:153
count
int * count
Definition: bloaty/third_party/googletest/googlemock/test/gmock_stress_test.cc:96
upb_strtable::t
upb_table t
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:845
upb_inthash
static uint32_t upb_inthash(uintptr_t key)
Definition: table.c:114
intkey
static lookupkey_t intkey(uintptr_t key)
Definition: table.c:103
upb_inttable_compact
void upb_inttable_compact(upb_inttable *t, upb_Arena *a)
Definition: table.c:710
UPB_UNUSED
#define UPB_UNUSED(var)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:128
_upb_value_setval
UPB_INLINE void _upb_value_setval(upb_value *v, uint64_t val, upb_ctype_t ctype)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:706
str_tabent
static const upb_tabent * str_tabent(const upb_strtable_iter *i)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:1632
_upb_tabent
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:807
upb_table
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:818
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
insert
static void insert(upb_table *t, lookupkey_t key, upb_tabkey tabkey, upb_value val, uint32_t hash, hashfunc_t *hashfunc, eqlfunc_t *eql)
Definition: table.c:191
strcopy
static upb_tabkey strcopy(lookupkey_t k2, upb_Arena *a)
Definition: table.c:291
_upb_Log2Ceiling
UPB_INLINE int _upb_Log2Ceiling(int x)
Definition: upb/upb/upb.h:354
upb_arrhas
static bool upb_arrhas(upb_tabval key)
Definition: table.c:120
xds_manager.num
num
Definition: xds_manager.py:56
upb_inttable_iter_value
upb_value upb_inttable_iter_value(const upb_inttable_iter *i)
Definition: table.c:909
upb_strtable_begin
void upb_strtable_begin(upb_strtable_iter *i, const upb_strtable *t)
Definition: table.c:523
absl::hash_internal::k1
static const uint64_t k1
Definition: abseil-cpp/absl/hash/internal/city.cc:54
upb_inttable_next
void upb_inttable_next(upb_inttable_iter *iter)
Definition: table.c:785
upb_strtable_iter_isequal
bool upb_strtable_iter_isequal(const upb_strtable_iter *i1, const upb_strtable_iter *i2)
Definition: table.c:557
upb_inttable_lookup
bool upb_inttable_lookup(const upb_inttable *t, uintptr_t key, upb_value *v)
Definition: table.c:675
UnalignedLoad32
static uint32_t UnalignedLoad32(const void *p)
Definition: table.c:309
upb_strtable
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:844
upb_tabval::val
uint64_t val
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:799
lookup
static bool lookup(const upb_table *t, lookupkey_t key, upb_value *v, uint32_t hash, eqlfunc_t *eql)
Definition: table.c:177
_upb_value_val
static upb_value _upb_value_val(uint64_t val)
Definition: table.c:56
upb_strtable_resize
bool upb_strtable_resize(upb_strtable *t, size_t size_lg2, upb_Arena *a)
Definition: table.c:471
iter
Definition: test_winkernel.cpp:47
upb_inttable_iter_key
uintptr_t upb_inttable_iter_key(const upb_inttable_iter *i)
Definition: table.c:904
i2
int i2
Definition: abseil-cpp/absl/container/btree_test.cc:2773
upb_inttable_remove
bool upb_inttable_remove(upb_inttable *t, uintptr_t key, upb_value *val)
Definition: table.c:689
len
int len
Definition: abseil-cpp/absl/base/internal/low_level_alloc_test.cc:46
intrin.h
upb_getentry
static const upb_tabent * upb_getentry(const upb_table *t, uint32_t hash)
Definition: table.c:116
upb_inttable_insert
bool upb_inttable_insert(upb_inttable *t, uintptr_t key, upb_value val, upb_Arena *a)
Definition: table.c:634
upb_strtable_iter
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:1086
_upb_tabent::key
upb_tabkey key
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:808
lookupkey_t
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:1324
upb_strtable_next2
bool upb_strtable_next2(const upb_strtable *t, upb_StringView *key, upb_value *val, intptr_t *iter)
Definition: table.c:855
upb_Arena
Definition: upb_internal.h:36
_upb_Hash
uint32_t _upb_Hash(const void *p, size_t n, uint64_t seed)
Definition: table.c:436
upb_table_size
UPB_INLINE size_t upb_table_size(const upb_table *t)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.h:863
if
if(p->owned &&p->wrapped !=NULL)
Definition: call.c:42
upb_strtable_remove2
bool upb_strtable_remove2(upb_strtable *t, const char *key, size_t len, upb_value *val)
Definition: table.c:514
i
uint64_t i
Definition: abseil-cpp/absl/container/btree_benchmark.cc:230
upb_strtable_iter_value
upb_value upb_strtable_iter_value(const upb_strtable_iter *i)
Definition: table.c:547
upb_strtable_iter_key
upb_StringView upb_strtable_iter_key(const upb_strtable_iter *i)
Definition: table.c:538


grpc
Author(s):
autogenerated on Thu Mar 13 2025 03:01:29