flatcc_identifier.h (4778B)
1 #ifndef FLATCC_IDENTIFIER_H 2 #define FLATCC_IDENTIFIER_H 3 4 #ifdef __cplusplus 5 extern "C" { 6 #endif 7 8 #ifndef FLATCC_FLATBUFFERS_H 9 #error "include via flatcc/flatcc_flatbuffers.h" 10 #endif 11 12 #ifndef UINT8_MAX 13 #include <stdint.h> 14 #endif 15 16 /* 17 * FlatBuffers identifiers are normally specified by "file_identifer" in 18 * the schema, but a standard hash of the fully qualified type name can 19 * also be used. This file implements such a mapping, but the generated 20 * headers also contain the necessary information for known types. 21 */ 22 23 24 /* 25 * Returns the type hash of a given name in native endian format. 26 * Generated code already provides these, but if a name was changed 27 * in the schema it may be relevant to recompute the hash manually. 28 * 29 * The wire-format of this value should always be little endian. 30 * 31 * Note: this must be the fully qualified name, e.g. in the namespace 32 * "MyGame.Example": 33 * 34 * flatbuffers_type_hash_from_name("MyGame.Example.Monster"); 35 * 36 * or, in the global namespace just: 37 * 38 * flatbuffers_type_hash_from_name("MyTable"); 39 * 40 * This assumes 32 bit hash type. For other sizes, other FNV-1a 41 * constants would be required. 42 * 43 * Note that we reserve hash value 0 for missing or ignored value. 44 */ 45 static inline flatbuffers_thash_t flatbuffers_type_hash_from_name(const char *name) 46 { 47 uint32_t hash = UINT32_C(2166136261); 48 while (*name) { 49 hash ^= (unsigned char)*name; 50 hash = hash * UINT32_C(16777619); 51 ++name; 52 } 53 if (hash == 0) { 54 hash = UINT32_C(2166136261); 55 } 56 return hash; 57 } 58 59 /* 60 * Type hash encoded as little endian file identifier string. 61 * Note: if type hash is 0, the identifier should be null which 62 * we cannot return in this interface. 63 */ 64 static inline void flatbuffers_identifier_from_type_hash(flatbuffers_thash_t type_hash, flatbuffers_fid_t out_identifier) 65 { 66 out_identifier[0] = (char)(type_hash & 0xff); 67 type_hash >>= 8; 68 out_identifier[1] = (char)(type_hash & 0xff); 69 type_hash >>= 8; 70 out_identifier[2] = (char)(type_hash & 0xff); 71 type_hash >>= 8; 72 out_identifier[3] = (char)(type_hash & 0xff); 73 } 74 75 /* Native integer encoding of file identifier. */ 76 static inline flatbuffers_thash_t flatbuffers_type_hash_from_identifier(const flatbuffers_fid_t identifier) 77 { 78 uint8_t *p = (uint8_t *)identifier; 79 80 return identifier ? 81 (uint32_t)p[0] + (((uint32_t)p[1]) << 8) + (((uint32_t)p[2]) << 16) + (((uint32_t)p[3]) << 24) : 0; 82 } 83 84 /* 85 * Convert a null terminated string identifier like "MONS" or "X" into a 86 * native type hash identifier, usually for comparison. This will not 87 * work with type hash strings because they can contain null bytes. 88 */ 89 static inline flatbuffers_thash_t flatbuffers_type_hash_from_string(const char *identifier) 90 { 91 flatbuffers_thash_t h = 0; 92 const uint8_t *p = (const uint8_t *)identifier; 93 94 if (!p[0]) return h; 95 h += ((flatbuffers_thash_t)p[0]); 96 if (!p[1]) return h; 97 h += ((flatbuffers_thash_t)p[1]) << 8; 98 if (!p[2]) return h; 99 h += ((flatbuffers_thash_t)p[2]) << 16; 100 /* No need to test for termination here. */ 101 h += ((flatbuffers_thash_t)p[3]) << 24; 102 return h; 103 } 104 105 /* 106 * Computes the little endian wire format of the type hash. It can be 107 * used as a file identifer argument to various flatcc buffer calls. 108 * 109 * `flatbuffers_fid_t` is just `char [4]` for the default flatbuffers 110 * type system defined in `flatcc/flatcc_types.h`. 111 */ 112 static inline void flatbuffers_identifier_from_name(const char *name, flatbuffers_fid_t out_identifier) 113 { 114 flatbuffers_identifier_from_type_hash(flatbuffers_type_hash_from_name(name), out_identifier); 115 } 116 117 /* 118 * This is a collision free hash (a permutation) of the type hash to 119 * provide better distribution for use in hash tables. It is likely not 120 * necessary in praxis, and for uniqueness of identifiers it provides no 121 * advantage over just using the FNV-1a type hash, except when truncating 122 * the identifier to less than 32-bits. 123 * 124 * Note: the output should not be used in transmission. It provides no 125 * additional information and just complicates matters. Furthermore, the 126 * unmodified type hash has the benefit that it can seed a child namespace. 127 */ 128 static inline uint32_t flatbuffers_disperse_type_hash(flatbuffers_thash_t type_hash) 129 { 130 /* http://stackoverflow.com/a/12996028 */ 131 uint32_t x = type_hash; 132 133 x = ((x >> 16) ^ x) * UINT32_C(0x45d9f3b); 134 x = ((x >> 16) ^ x) * UINT32_C(0x45d9f3b); 135 x = ((x >> 16) ^ x); 136 return x; 137 } 138 139 140 /* We have hardcoded assumptions about identifier size. */ 141 static_assert(sizeof(flatbuffers_fid_t) == 4, "unexpected file identifier size"); 142 static_assert(sizeof(flatbuffers_thash_t) == 4, "unexpected type hash size"); 143 144 #ifdef __cplusplus 145 } 146 #endif 147 148 #endif /* FLATCC_IDENTIFIER_H */