| // Protocol Buffers - Google's data interchange format |
| // Copyright 2023 Google LLC. All rights reserved. |
| // |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file or at |
| // https://developers.google.com/open-source/licenses/bsd |
| |
| /* |
| * upb_table |
| * |
| * This header is INTERNAL-ONLY! Its interfaces are not public or stable! |
| * This file defines very fast int->upb_value (inttable) and string->upb_value |
| * (strtable) hash tables. |
| * |
| * The table uses chained scatter with Brent's variation (inspired by the Lua |
| * implementation of hash tables). The hash function for strings is Austin |
| * Appleby's "MurmurHash." |
| * |
| * The inttable uses uintptr_t as its key, which guarantees it can be used to |
| * store pointers or integers of at least 32 bits (upb isn't really useful on |
| * systems where sizeof(void*) < 4). |
| * |
| * The table must be homogeneous (all values of the same type). In debug |
| * mode, we check this on insert and lookup. |
| */ |
| |
| #ifndef UPB_HASH_COMMON_H_ |
| #define UPB_HASH_COMMON_H_ |
| |
| #include <string.h> |
| |
| #include "upb/base/string_view.h" |
| #include "upb/mem/arena.h" |
| |
| // Must be last. |
| #include "upb/port/def.inc" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /* upb_value ******************************************************************/ |
| |
| typedef struct { |
| uint64_t val; |
| } upb_value; |
| |
| UPB_INLINE void _upb_value_setval(upb_value* v, uint64_t val) { v->val = val; } |
| |
| /* For each value ctype, define the following set of functions: |
| * |
| * // Get/set an int32 from a upb_value. |
| * int32_t upb_value_getint32(upb_value val); |
| * void upb_value_setint32(upb_value *val, int32_t cval); |
| * |
| * // Construct a new upb_value from an int32. |
| * upb_value upb_value_int32(int32_t val); */ |
| #define FUNCS(name, membername, type_t, converter) \ |
| UPB_INLINE void upb_value_set##name(upb_value* val, type_t cval) { \ |
| val->val = (converter)cval; \ |
| } \ |
| UPB_INLINE upb_value upb_value_##name(type_t val) { \ |
| upb_value ret; \ |
| upb_value_set##name(&ret, val); \ |
| return ret; \ |
| } \ |
| UPB_INLINE type_t upb_value_get##name(upb_value val) { \ |
| return (type_t)(converter)val.val; \ |
| } |
| |
| FUNCS(int32, int32, int32_t, int32_t) |
| FUNCS(int64, int64, int64_t, int64_t) |
| FUNCS(uint32, uint32, uint32_t, uint32_t) |
| FUNCS(uint64, uint64, uint64_t, uint64_t) |
| FUNCS(bool, _bool, bool, bool) |
| FUNCS(cstr, cstr, char*, uintptr_t) |
| FUNCS(uintptr, uptr, uintptr_t, uintptr_t) |
| FUNCS(ptr, ptr, void*, uintptr_t) |
| FUNCS(constptr, constptr, const void*, uintptr_t) |
| |
| #undef FUNCS |
| |
| UPB_INLINE void upb_value_setfloat(upb_value* val, float cval) { |
| memcpy(&val->val, &cval, sizeof(cval)); |
| } |
| |
| UPB_INLINE void upb_value_setdouble(upb_value* val, double cval) { |
| memcpy(&val->val, &cval, sizeof(cval)); |
| } |
| |
| UPB_INLINE upb_value upb_value_float(float cval) { |
| upb_value ret; |
| upb_value_setfloat(&ret, cval); |
| return ret; |
| } |
| |
| UPB_INLINE upb_value upb_value_double(double cval) { |
| upb_value ret; |
| upb_value_setdouble(&ret, cval); |
| return ret; |
| } |
| |
| /* upb_tabkey *****************************************************************/ |
| |
| /* Either: |
| * 1. an actual integer key, or |
| * 2. a pointer to a string prefixed by its uint32_t length, owned by us. |
| * |
| * ...depending on whether this is a string table or an int table. We would |
| * make this a union of those two types, but C89 doesn't support statically |
| * initializing a non-first union member. */ |
| typedef uintptr_t upb_tabkey; |
| |
| UPB_INLINE char* upb_tabstr(upb_tabkey key, uint32_t* len) { |
| char* mem = (char*)key; |
| if (len) memcpy(len, mem, sizeof(*len)); |
| return mem + sizeof(*len); |
| } |
| |
| UPB_INLINE upb_StringView upb_tabstrview(upb_tabkey key) { |
| upb_StringView ret; |
| uint32_t len; |
| ret.data = upb_tabstr(key, &len); |
| ret.size = len; |
| return ret; |
| } |
| |
| /* upb_tabval *****************************************************************/ |
| |
| typedef struct upb_tabval { |
| uint64_t val; |
| } upb_tabval; |
| |
| #define UPB_TABVALUE_EMPTY_INIT \ |
| { -1 } |
| |
| /* upb_table ******************************************************************/ |
| |
| typedef struct _upb_tabent { |
| upb_tabkey key; |
| upb_tabval val; |
| |
| /* Internal chaining. This is const so we can create static initializers for |
| * tables. We cast away const sometimes, but *only* when the containing |
| * upb_table is known to be non-const. This requires a bit of care, but |
| * the subtlety is confined to table.c. */ |
| const struct _upb_tabent* next; |
| } upb_tabent; |
| |
| typedef struct { |
| size_t count; /* Number of entries in the hash part. */ |
| uint32_t mask; /* Mask to turn hash value -> bucket. */ |
| uint32_t max_count; /* Max count before we hit our load limit. */ |
| uint8_t size_lg2; /* Size of the hashtable part is 2^size_lg2 entries. */ |
| upb_tabent* entries; |
| } upb_table; |
| |
| UPB_INLINE size_t upb_table_size(const upb_table* t) { |
| return t->size_lg2 ? 1 << t->size_lg2 : 0; |
| } |
| |
| // Internal-only functions, in .h file only out of necessity. |
| |
| UPB_INLINE bool upb_tabent_isempty(const upb_tabent* e) { return e->key == 0; } |
| |
| uint32_t _upb_Hash(const void* p, size_t n, uint64_t seed); |
| |
| #ifdef __cplusplus |
| } /* extern "C" */ |
| #endif |
| |
| #include "upb/port/undef.inc" |
| |
| #endif /* UPB_HASH_COMMON_H_ */ |