From 353b31c7dae0cffb0d3bf82c2e4b5e715da33b83 Mon Sep 17 00:00:00 2001 From: Samuel Susla Date: Fri, 22 Sep 2023 05:53:13 -0700 Subject: [PATCH] introduce fnv1a hashing function (#39515) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/39515 changelog: [internal] Implements FNV hashing algorithm: http://www.isthe.com/chongo/tech/comp/fnv/ Reviewed By: javache Differential Revision: D49358327 fbshipit-source-id: b211da89ca7b6bea6ed1b0732e639bbc2de210f7 --- .../react/renderer/core/PropsMacros.h | 3 +- .../ReactCommon/react/utils/fnv1a.h | 36 +++++++++++++++++++ .../react/utils/tests/fnv1aTests.cpp | 24 +++++++++++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 packages/react-native/ReactCommon/react/utils/fnv1a.h create mode 100644 packages/react-native/ReactCommon/react/utils/tests/fnv1aTests.cpp diff --git a/packages/react-native/ReactCommon/react/renderer/core/PropsMacros.h b/packages/react-native/ReactCommon/react/renderer/core/PropsMacros.h index d940fd6069c..3d2e5b221d9 100644 --- a/packages/react-native/ReactCommon/react/renderer/core/PropsMacros.h +++ b/packages/react-native/ReactCommon/react/renderer/core/PropsMacros.h @@ -8,6 +8,7 @@ #pragma once #include +#include #include // We need to use clang pragmas inside of a macro below, @@ -23,7 +24,7 @@ ([]() constexpr->RawPropsPropNameHash { \ CLANG_PRAGMA("clang diagnostic push") \ CLANG_PRAGMA("clang diagnostic ignored \"-Wshadow\"") \ - return folly::hash::fnv32_buf(s, sizeof(s) - 1); \ + return facebook::react::fnv1a(s); \ CLANG_PRAGMA("clang diagnostic pop") \ }()) diff --git a/packages/react-native/ReactCommon/react/utils/fnv1a.h b/packages/react-native/ReactCommon/react/utils/fnv1a.h new file mode 100644 index 00000000000..fe2721d4bc0 --- /dev/null +++ b/packages/react-native/ReactCommon/react/utils/fnv1a.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +namespace facebook::react { + +/** + * FNV-1a hash function implementation. + * Implemented as described in http://www.isthe.com/chongo/tech/comp/fnv/. + * + * Please use std::hash if possible. `fnv1a` should only be used in cases + * when std::hash does not provide the needed functionality. For example, + * constexpr. + */ +constexpr uint32_t fnv1a(std::string_view string) noexcept { + constexpr uint32_t offset_basis = 2166136261; + + uint32_t hash = offset_basis; + + for (auto const& c : string) { + hash ^= static_cast(c); + // Using shifts and adds instead of multiplication with a prime number. + // This is faster when compiled with optimizations. + hash += + (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24); + } + + return hash; +} + +} // namespace facebook::react diff --git a/packages/react-native/ReactCommon/react/utils/tests/fnv1aTests.cpp b/packages/react-native/ReactCommon/react/utils/tests/fnv1aTests.cpp new file mode 100644 index 00000000000..5c7b76d099a --- /dev/null +++ b/packages/react-native/ReactCommon/react/utils/tests/fnv1aTests.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#include +#include + +namespace facebook::react { + +TEST(fnv1aTests, testBasicHashing) { + EXPECT_EQ(fnv1a("react"), fnv1a("react")); + + EXPECT_NE(fnv1a("react"), fnv1a("tceat")); + + auto string1 = "case 1"; + auto string2 = "different string"; + EXPECT_EQ(fnv1a(string1), fnv1a(string1)); + EXPECT_NE(fnv1a(string1), fnv1a(string2)); +} + +} // namespace facebook::react