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 6724774 commit 08c9b14
Show file tree
Hide file tree
Showing 6 changed files with 186 additions and 133 deletions.
1 change: 1 addition & 0 deletions third-party/folly/src/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 third-party/folly/src/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 third-party/folly/src/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
69 changes: 69 additions & 0 deletions third-party/folly/src/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 third-party/folly/src/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
44 changes: 0 additions & 44 deletions third-party/folly/src/folly/test/TraitsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,52 +64,8 @@ template <class>
struct A {};
struct B {};

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);
}
};

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>>);

} // namespace std

namespace folly {
template <>
struct IsRelocatable<T1> : std::true_type {};
Expand Down

0 comments on commit 08c9b14

Please sign in to comment.