From 6e2e909b5c9737ec169ddbdb9ed9b8aa2e908aa1 Mon Sep 17 00:00:00 2001 From: Christian Helmich Date: Sat, 24 Feb 2018 03:29:37 +0900 Subject: [PATCH] template specialized Hash functions for 16-bit hash types (#4631) added access to HashFunction for 16 bit --- include/flatbuffers/hash.h | 28 +++++++++++++++++++++++++++- src/flathash.cpp | 19 +++++++++++++++---- src/idl_parser.cpp | 21 ++++++++++++++++++++- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/include/flatbuffers/hash.h b/include/flatbuffers/hash.h index 855e92d9e..16536cb49 100644 --- a/include/flatbuffers/hash.h +++ b/include/flatbuffers/hash.h @@ -57,13 +57,28 @@ template T HashFnv1a(const char *input) { return hash; } -template struct NamedHashFunction { +template <> inline uint16_t HashFnv1(const char *input) { + uint32_t hash = HashFnv1(input); + return (hash >> 16) ^ (hash & 0xffff); +} + +template <> inline uint16_t HashFnv1a(const char *input) { + uint32_t hash = HashFnv1a(input); + return (hash >> 16) ^ (hash & 0xffff); +} + +template struct NamedHashFunction { const char *name; typedef T (*HashFunction)(const char *); HashFunction function; }; +const NamedHashFunction kHashFunctions16[] = { + { "fnv1_16", HashFnv1 }, + { "fnv1a_16", HashFnv1a }, +}; + const NamedHashFunction kHashFunctions32[] = { { "fnv1_32", HashFnv1 }, { "fnv1a_32", HashFnv1a }, @@ -74,6 +89,17 @@ const NamedHashFunction kHashFunctions64[] = { { "fnv1a_64", HashFnv1a }, }; +inline NamedHashFunction::HashFunction FindHashFunction16( + const char *name) { + std::size_t size = sizeof(kHashFunctions16) / sizeof(kHashFunctions16[0]); + for (std::size_t i = 0; i < size; ++i) { + if (std::strcmp(name, kHashFunctions16[i].name) == 0) { + return kHashFunctions16[i].function; + } + } + return nullptr; +} + inline NamedHashFunction::HashFunction FindHashFunction32( const char *name) { std::size_t size = sizeof(kHashFunctions32) / sizeof(kHashFunctions32[0]); diff --git a/src/flathash.cpp b/src/flathash.cpp index 64e3f35bf..2194e3086 100644 --- a/src/flathash.cpp +++ b/src/flathash.cpp @@ -26,8 +26,15 @@ int main(int argc, char *argv[]) { const char *name = argv[0]; if (argc <= 1) { printf("%s HASH [OPTION]... STRING... [-- STRING...]\n", name); - printf("Available hashing algorithms:\n 32 bit:\n"); - size_t size = sizeof(flatbuffers::kHashFunctions32) / + printf("Available hashing algorithms:\n"); + printf(" 16 bit:\n"); + size_t size = sizeof(flatbuffers::kHashFunctions16) / + sizeof(flatbuffers::kHashFunctions16[0]); + for (size_t i = 0; i < size; ++i) { + printf(" * %s\n", flatbuffers::kHashFunctions16[i].name); + } + printf(" 32 bit:\n"); + size = sizeof(flatbuffers::kHashFunctions32) / sizeof(flatbuffers::kHashFunctions32[0]); for (size_t i = 0; i < size; ++i) { printf(" * %s\n", flatbuffers::kHashFunctions32[i].name); @@ -48,12 +55,14 @@ int main(int argc, char *argv[]) { const char *hash_algorithm = argv[1]; + flatbuffers::NamedHashFunction::HashFunction hash_function16 = + flatbuffers::FindHashFunction16(hash_algorithm); flatbuffers::NamedHashFunction::HashFunction hash_function32 = flatbuffers::FindHashFunction32(hash_algorithm); flatbuffers::NamedHashFunction::HashFunction hash_function64 = flatbuffers::FindHashFunction64(hash_algorithm); - if (!hash_function32 && !hash_function64) { + if (!hash_function16 && !hash_function32 && !hash_function64) { printf("\"%s\" is not a known hash algorithm.\n", hash_algorithm); return 0; } @@ -87,7 +96,9 @@ int main(int argc, char *argv[]) { ss << std::hex; ss << "0x"; } - if (hash_function32) + if (hash_function16) + ss << hash_function16(arg); + else if (hash_function32) ss << hash_function32(arg); else if (hash_function64) ss << hash_function64(arg); diff --git a/src/idl_parser.cpp b/src/idl_parser.cpp index f3e40f581..ebb90de6f 100644 --- a/src/idl_parser.cpp +++ b/src/idl_parser.cpp @@ -681,6 +681,13 @@ CheckedError Parser::ParseField(StructDef &struct_def) { auto hash_name = field->attributes.Lookup("hash"); if (hash_name) { switch ((type.base_type == BASE_TYPE_VECTOR) ? type.element : type.base_type) { + case BASE_TYPE_SHORT: + case BASE_TYPE_USHORT: { + if (FindHashFunction16(hash_name->constant.c_str()) == nullptr) + return Error("Unknown hashing algorithm for 16 bit types: " + + hash_name->constant); + break; + } case BASE_TYPE_INT: case BASE_TYPE_UINT: { if (FindHashFunction32(hash_name->constant.c_str()) == nullptr) @@ -697,7 +704,7 @@ CheckedError Parser::ParseField(StructDef &struct_def) { } default: return Error( - "only int, uint, long and ulong data types support hashing."); + "only short, ushort, int, uint, long and ulong data types support hashing."); } } auto cpp_type = field->attributes.Lookup("cpp_type"); @@ -1278,6 +1285,18 @@ CheckedError Parser::ParseHash(Value &e, FieldDef *field) { assert(field); Value *hash_name = field->attributes.Lookup("hash"); switch (e.type.base_type) { + case BASE_TYPE_SHORT: { + auto hash = FindHashFunction16(hash_name->constant.c_str()); + int16_t hashed_value = static_cast(hash(attribute_.c_str())); + e.constant = NumToString(hashed_value); + break; + } + case BASE_TYPE_USHORT: { + auto hash = FindHashFunction16(hash_name->constant.c_str()); + uint16_t hashed_value = hash(attribute_.c_str()); + e.constant = NumToString(hashed_value); + break; + } case BASE_TYPE_INT: { auto hash = FindHashFunction32(hash_name->constant.c_str()); int32_t hashed_value = static_cast(hash(attribute_.c_str()));