damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

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 */