Skip to content

Commit

Permalink
folly/hash/traits.h
Browse files Browse the repository at this point in the history
Summary: There are hash-related traits in folly/Traits.h that would ideally be colocated with hash-related code.

Reviewed By: DenisYaroshevskiy

Differential Revision: D62502066

fbshipit-source-id: 0d0d50e8744eeedad1b0adcdcefdb33a0d6cc2cf
  • Loading branch information
yfeldblum authored and facebook-github-bot committed Sep 12, 2024
1 parent ac6f850 commit a662cd3
Show file tree
Hide file tree
Showing 10 changed files with 207 additions and 134 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -886,6 +886,7 @@ if (BUILD_TESTS OR BUILD_BENCHMARKS)
SOURCES HashTest.cpp
TEST hash_spooky_hash_v1_test SOURCES SpookyHashV1Test.cpp
TEST hash_spooky_hash_v2_test SOURCES SpookyHashV2Test.cpp
TEST hash_traits_test SOURCES traits_test.cpp

DIRECTORY io/test/
TEST io_fs_util_test SOURCES FsUtilTest.cpp
Expand Down
1 change: 1 addition & 0 deletions folly/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -1053,6 +1053,7 @@ cpp_library(
":traits",
":utility",
"//folly/experimental/coro:coroutine",
"//folly/hash:traits",
"//folly/lang:exception",
],
)
Expand Down
1 change: 1 addition & 0 deletions folly/Optional.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
#include <folly/Portability.h>
#include <folly/Traits.h>
#include <folly/Utility.h>
#include <folly/hash/traits.h>
#include <folly/lang/Exception.h>

namespace folly {
Expand Down
89 changes: 0 additions & 89 deletions folly/Traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -1311,93 +1311,4 @@ inline constexpr std::size_t type_list_find_v =
template <typename V, typename List>
using type_list_find_t = index_constant<type_list_find_v<V, List>>;

/**
* Checks the requirements that the Hasher class must satisfy
* in order to be used with the standard library containers,
* for example `std::unordered_set<T, Hasher>`.
*/
template <typename T, typename Hasher>
using is_hasher_usable = std::integral_constant<
bool,
std::is_default_constructible_v<Hasher> &&
std::is_copy_constructible_v<Hasher> &&
std::is_move_constructible_v<Hasher> &&
std::is_invocable_r_v<size_t, Hasher, const T&>>;

/**
* Checks the requirements that the Hasher class must satisfy
* in order to be used with the standard library containers,
* for example `std::unordered_set<T, Hasher>`.
*/
template <typename T, typename Hasher>
inline constexpr bool is_hasher_usable_v = is_hasher_usable<T, Hasher>::value;

/**
* Checks that the given hasher template's specialization for the given type
* is usable with the standard library containters,
* for example `std::unordered_set<T, Hasher<T>>`.
*/
template <typename T, template <typename U> typename Hasher = std::hash>
using is_hashable =
std::integral_constant<bool, is_hasher_usable_v<T, Hasher<T>>>;

/**
* Checks that the given hasher template's specialization for the given type
* is usable with the standard library containters,
* for example `std::unordered_set<T, Hasher<T>>`.
*/
template <typename T, template <typename U> typename Hasher = std::hash>
inline constexpr bool is_hashable_v = is_hashable<T, Hasher>::value;

namespace detail {

template <typename T, typename>
using enable_hasher_helper_impl = T;

} // namespace detail

/**
* A helper for defining partial specializations of a hasher class that rely
* on other partial specializations of that hasher class being usable.
*
* Example:
* ```
* template <typename T>
* struct hash<
* folly::enable_std_hash_helper<folly::Optional<T>, remove_const_t<T>>> {
* size_t operator()(folly::Optional<T> const& obj) const {
* return static_cast<bool>(obj) ? hash<remove_const_t<T>>()(*obj) : 0;
* }
* };
* ```
*/
template <
typename T,
template <typename U>
typename Hasher,
typename... Dependencies>
using enable_hasher_helper = detail::enable_hasher_helper_impl<
T,
std::enable_if_t<
StrictConjunction<is_hashable<Dependencies, Hasher>...>::value>>;

/**
* A helper for defining partial specializations of a hasher class that rely
* on other partial specializations of that hasher class being usable.
*
* Example:
* ```
* template <typename T>
* struct hash<
* folly::enable_std_hash_helper<folly::Optional<T>, remove_const_t<T>>> {
* size_t operator()(folly::Optional<T> const& obj) const {
* return static_cast<bool>(obj) ? hash<remove_const_t<T>>()(*obj) : 0;
* }
* };
* ```
*/
template <typename T, typename... Dependencies>
using enable_std_hash_helper =
enable_hasher_helper<T, std::hash, Dependencies...>;

} // namespace folly
8 changes: 8 additions & 0 deletions folly/hash/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,14 @@ cpp_library(
],
)

cpp_library(
name = "traits",
headers = ["traits.h"],
exported_deps = [
"//folly:traits",
],
)

cpp_library(
name = "murmur_hash",
headers = ["MurmurHash.h"],
Expand Down
10 changes: 10 additions & 0 deletions folly/hash/test/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ cpp_unittest(
],
)

cpp_unittest(
name = "traits_test",
srcs = ["traits_test.cpp"],
headers = [],
deps = [
"fbcode//folly/hash:traits",
"fbcode//folly/portability:gtest",
],
)

cpp_unittest(
name = "murmur_hash_test",
srcs = ["MurmurHashTest.cpp"],
Expand Down
69 changes: 69 additions & 0 deletions folly/hash/test/traits_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#include <folly/hash/traits.h>

#include <folly/portability/GTest.h>

using namespace folly;

namespace {

struct HashableStruct1 {};
struct HashableStruct2 {};
struct UnhashableStruct {};

template <typename X, typename Y>
struct CompositeStruct {
X x;
Y y;
};

} // namespace

namespace std {

template <>
struct hash<HashableStruct1> {
[[maybe_unused]] size_t operator()(const HashableStruct1&) const noexcept {
return 0;
}
};

template <>
struct hash<HashableStruct2> {
[[maybe_unused]] size_t operator()(const HashableStruct2&) const noexcept {
return 0;
}
};

template <typename X, typename Y>
struct hash<enable_std_hash_helper<CompositeStruct<X, Y>, X, Y>> {
[[maybe_unused]] size_t operator()(
const CompositeStruct<X, Y>& value) const noexcept {
return std::hash<X>{}(value.x) + std::hash<Y>{}(value.y);
}
};

} // namespace std

static_assert(is_hashable_v<HashableStruct1>);
static_assert(is_hashable_v<HashableStruct2>);
static_assert(!is_hashable_v<UnhashableStruct>);
static_assert(is_hashable_v<CompositeStruct<HashableStruct1, HashableStruct1>>);
static_assert(is_hashable_v<CompositeStruct<HashableStruct1, HashableStruct2>>);
static_assert(
!is_hashable_v<CompositeStruct<HashableStruct1, UnhashableStruct>>);
115 changes: 115 additions & 0 deletions folly/hash/traits.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <functional>
#include <type_traits>

#include <folly/Traits.h>

namespace folly {

/**
* Checks the requirements that the Hasher class must satisfy
* in order to be used with the standard library containers,
* for example `std::unordered_set<T, Hasher>`.
*/
template <typename T, typename Hasher>
using is_hasher_usable = std::integral_constant<
bool,
std::is_default_constructible_v<Hasher> &&
std::is_copy_constructible_v<Hasher> &&
std::is_move_constructible_v<Hasher> &&
std::is_invocable_r_v<size_t, Hasher, const T&>>;

/**
* Checks the requirements that the Hasher class must satisfy
* in order to be used with the standard library containers,
* for example `std::unordered_set<T, Hasher>`.
*/
template <typename T, typename Hasher>
inline constexpr bool is_hasher_usable_v = is_hasher_usable<T, Hasher>::value;

/**
* Checks that the given hasher template's specialization for the given type
* is usable with the standard library containters,
* for example `std::unordered_set<T, Hasher<T>>`.
*/
template <typename T, template <typename U> typename Hasher = std::hash>
using is_hashable =
std::integral_constant<bool, is_hasher_usable_v<T, Hasher<T>>>;

/**
* Checks that the given hasher template's specialization for the given type
* is usable with the standard library containters,
* for example `std::unordered_set<T, Hasher<T>>`.
*/
template <typename T, template <typename U> typename Hasher = std::hash>
inline constexpr bool is_hashable_v = is_hashable<T, Hasher>::value;

namespace detail {

template <typename T, typename>
using enable_hasher_helper_impl = T;

} // namespace detail

/**
* A helper for defining partial specializations of a hasher class that rely
* on other partial specializations of that hasher class being usable.
*
* Example:
* ```
* template <typename T>
* struct hash<
* folly::enable_std_hash_helper<folly::Optional<T>, remove_const_t<T>>> {
* size_t operator()(folly::Optional<T> const& obj) const {
* return static_cast<bool>(obj) ? hash<remove_const_t<T>>()(*obj) : 0;
* }
* };
* ```
*/
template <
typename T,
template <typename U>
typename Hasher,
typename... Dependencies>
using enable_hasher_helper = detail::enable_hasher_helper_impl<
T,
std::enable_if_t<
StrictConjunction<is_hashable<Dependencies, Hasher>...>::value>>;

/**
* A helper for defining partial specializations of a hasher class that rely
* on other partial specializations of that hasher class being usable.
*
* Example:
* ```
* template <typename T>
* struct hash<
* folly::enable_std_hash_helper<folly::Optional<T>, remove_const_t<T>>> {
* size_t operator()(folly::Optional<T> const& obj) const {
* return static_cast<bool>(obj) ? hash<remove_const_t<T>>()(*obj) : 0;
* }
* };
* ```
*/
template <typename T, typename... Dependencies>
using enable_std_hash_helper =
enable_hasher_helper<T, std::hash, Dependencies...>;

} // namespace folly
3 changes: 2 additions & 1 deletion folly/somerge_defs.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Generated by xplat/cross_plat_devx/somerge_maps/compute_merge_maps.py
@generated SignedSource<<925b105e8ef10298b39dee24bf1deb9b>>
@generated SignedSource<<4d6c648a98484ebd6d13a39719f413d2>>
"""

# Entry Points:
Expand Down Expand Up @@ -60,6 +60,7 @@ FOLLY_NATIVE_LIBRARY_MERGE_MAP = [
"fbsource//xplat/folly:hash_murmur_hashAndroid",
"fbsource//xplat/folly:hash_spooky_hash_v1Android",
"fbsource//xplat/folly:hash_spooky_hash_v2Android",
"fbsource//xplat/folly:hash_traitsAndroid",
"fbsource//xplat/folly:headers_only_do_not_useAndroid",
"fbsource//xplat/folly:likelyAndroid",
"fbsource//xplat/folly:mathAndroid",
Expand Down
Loading

0 comments on commit a662cd3

Please sign in to comment.