Commit a4cb1c8b by Abseil Team Committed by Ashley Hedberg

Export of internal Abseil changes.

--
6fdf24a197b964f9bacbebd0ceca305aef1654fc by Shaindel Schwartz <shaindel@google.com>:

Internal change

PiperOrigin-RevId: 231627312

--
65f7faf52bff01384171efb85fee159378dedf70 by CJ Johnson <johnsoncj@google.com>:

Relocates the definitions of the InputIterator-accepting parts of the InlinedVector API into the top-level. The removed functions had no other callers so there was no reason to keep the layer of indirection in the form of the function call.

PiperOrigin-RevId: 231527459

--
30e105b749b5ecc50fdaf26c7da589617efce425 by CJ Johnson <johnsoncj@google.com>:

Relocates closing brace for absl namespace in InlinedVector to the correct end location

PiperOrigin-RevId: 231477871

--
063c1e8b9d1f032662c46d574e20ecc357b87d0c by Eric Fiselier <ericwf@google.com>:

Cleanup std::hash probing metafunctions.

Previously there were two different ways to probe for
std::hash. One in hash.h and another in type_traits.h,
and they were both implemented differently, and neither
correctly worked around bad STL implementations.

This patch unifies the implementations into a single IsHashable trait.
It also:

* Correctly checks for old libc++ versions where this won't work.
* Avoids undefined behavior which resulted from calling std::is_constructible
  incomplete types.
* Unifies the feature test macro used in the headers and the tests.

Additionally it also slightly changes the behavior of when absl::variant
is hashable. Previously we disable hashing when std::hash<T>()(key) was
formed but when std::hash<T> couldn't be destructed. This seems wrong. If a
user provides a evil specialization of std::hash, then it's OK for variant's
hash to blow up.

PiperOrigin-RevId: 231468345

--
05d75dd4b07c893de9b104731644d0d207b01253 by Abseil Team <absl-team@google.com>:

Import of CCTZ from GitHub.

PiperOrigin-RevId: 231397518

--
a0ee9032f9e04039f3410ed17fcf45ae1a3868f5 by CJ Johnson <johnsoncj@google.com>:

Remove unused EnableIfAtLeastInputIterator from InlinedVector

PiperOrigin-RevId: 231348903

--
4dcd4e9a6780a81d7a6974c7bf22a037e6482b49 by Abseil Team <absl-team@google.com>:

Remove unnecessary register keyword from absl/base/internal/endian.h.

PiperOrigin-RevId: 231316570

--
c8584836caa3a10f90a8604a85d4b831310b72ee by Abseil Team <absl-team@google.com>:

Fix hashtablez_sampler compilation on older Android NDK builds

PiperOrigin-RevId: 231283542
GitOrigin-RevId: 6fdf24a197b964f9bacbebd0ceca305aef1654fc
Change-Id: I185b12fb8347e3ad0ffcb2cbb83a53450e5eb938
parent 540e2537
...@@ -75,7 +75,7 @@ inline uint64_t gbswap_64(uint64_t host_int) { ...@@ -75,7 +75,7 @@ inline uint64_t gbswap_64(uint64_t host_int) {
if (__builtin_constant_p(host_int)) { if (__builtin_constant_p(host_int)) {
return __bswap_constant_64(host_int); return __bswap_constant_64(host_int);
} else { } else {
register uint64_t result; uint64_t result;
__asm__("bswap %0" : "=r"(result) : "0"(host_int)); __asm__("bswap %0" : "=r"(result) : "0"(host_int));
return result; return result;
} }
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
// This code is compiled directly on many platforms, including client // This code is compiled directly on many platforms, including client
// platforms like Windows, Mac, and embedded systems. Before making // platforms like Windows, Mac, and embedded systems. Before making
// any changes here, make sure that you're not breaking any platforms. // any changes here, make sure that you're not breaking any platforms.
//
#ifndef ABSL_BASE_MACROS_H_ #ifndef ABSL_BASE_MACROS_H_
#define ABSL_BASE_MACROS_H_ #define ABSL_BASE_MACROS_H_
......
...@@ -72,20 +72,11 @@ class InlinedVector { ...@@ -72,20 +72,11 @@ class InlinedVector {
} }
template <typename Iterator> template <typename Iterator>
using IsAtLeastInputIterator = std::is_convertible<
typename std::iterator_traits<Iterator>::iterator_category,
std::input_iterator_tag>;
template <typename Iterator>
using IsAtLeastForwardIterator = std::is_convertible< using IsAtLeastForwardIterator = std::is_convertible<
typename std::iterator_traits<Iterator>::iterator_category, typename std::iterator_traits<Iterator>::iterator_category,
std::forward_iterator_tag>; std::forward_iterator_tag>;
template <typename Iterator> template <typename Iterator>
using EnableIfAtLeastInputIterator =
absl::enable_if_t<IsAtLeastInputIterator<Iterator>::value>;
template <typename Iterator>
using EnableIfAtLeastForwardIterator = using EnableIfAtLeastForwardIterator =
absl::enable_if_t<IsAtLeastForwardIterator<Iterator>::value>; absl::enable_if_t<IsAtLeastForwardIterator<Iterator>::value>;
...@@ -163,7 +154,7 @@ class InlinedVector { ...@@ -163,7 +154,7 @@ class InlinedVector {
InlinedVector(InputIterator first, InputIterator last, InlinedVector(InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type()) const allocator_type& alloc = allocator_type())
: allocator_and_tag_(alloc) { : allocator_and_tag_(alloc) {
AppendInputRange(first, last); std::copy(first, last, std::back_inserter(*this));
} }
// Creates a copy of `other` using `other`'s allocator. // Creates a copy of `other` using `other`'s allocator.
...@@ -534,7 +525,13 @@ class InlinedVector { ...@@ -534,7 +525,13 @@ class InlinedVector {
template <typename InputIterator, template <typename InputIterator,
DisableIfAtLeastForwardIterator<InputIterator>* = nullptr> DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
void assign(InputIterator first, InputIterator last) { void assign(InputIterator first, InputIterator last) {
AssignInputRange(first, last); size_type assign_index = 0;
for (; (assign_index < size()) && (first != last);
static_cast<void>(++assign_index), static_cast<void>(++first)) {
*(data() + assign_index) = *first;
}
erase(data() + assign_index, data() + size());
std::copy(first, last, std::back_inserter(*this));
} }
// `InlinedVector::resize()` // `InlinedVector::resize()`
...@@ -630,7 +627,12 @@ class InlinedVector { ...@@ -630,7 +627,12 @@ class InlinedVector {
template <typename InputIterator, template <typename InputIterator,
DisableIfAtLeastForwardIterator<InputIterator>* = nullptr> DisableIfAtLeastForwardIterator<InputIterator>* = nullptr>
iterator insert(const_iterator pos, InputIterator first, InputIterator last) { iterator insert(const_iterator pos, InputIterator first, InputIterator last) {
return InsertWithInputRange(pos, first, last); size_type initial_insert_index = std::distance(cbegin(), pos);
for (size_type insert_index = initial_insert_index; first != last;
static_cast<void>(++insert_index), static_cast<void>(++first)) {
insert(data() + insert_index, *first);
}
return iterator(data() + initial_insert_index);
} }
// `InlinedVector::emplace()` // `InlinedVector::emplace()`
...@@ -1131,20 +1133,6 @@ class InlinedVector { ...@@ -1131,20 +1133,6 @@ class InlinedVector {
} }
} }
template <typename InputIterator>
void AssignInputRange(InputIterator first, InputIterator last) {
static_assert(IsAtLeastInputIterator<InputIterator>::value, "");
// Optimized to avoid reallocation.
// Prefer reassignment to copy construction for elements.
iterator out = begin();
for (; first != last && out != end(); ++first, ++out) {
*out = *first;
}
erase(out, end());
std::copy(first, last, std::back_inserter(*this));
}
template <typename ForwardIterator> template <typename ForwardIterator>
void AppendForwardRange(ForwardIterator first, ForwardIterator last) { void AppendForwardRange(ForwardIterator first, ForwardIterator last) {
static_assert(IsAtLeastForwardIterator<ForwardIterator>::value, ""); static_assert(IsAtLeastForwardIterator<ForwardIterator>::value, "");
...@@ -1160,13 +1148,6 @@ class InlinedVector { ...@@ -1160,13 +1148,6 @@ class InlinedVector {
} }
} }
template <typename InputIterator>
void AppendInputRange(InputIterator first, InputIterator last) {
static_assert(IsAtLeastInputIterator<InputIterator>::value, "");
std::copy(first, last, std::back_inserter(*this));
}
iterator InsertWithCount(const_iterator position, size_type n, iterator InsertWithCount(const_iterator position, size_type n,
const_reference v) { const_reference v) {
assert(position >= begin() && position <= end()); assert(position >= begin() && position <= end());
...@@ -1198,18 +1179,6 @@ class InlinedVector { ...@@ -1198,18 +1179,6 @@ class InlinedVector {
return it_pair.first; return it_pair.first;
} }
template <typename InputIterator>
iterator InsertWithInputRange(const_iterator position, InputIterator first,
InputIterator last) {
static_assert(IsAtLeastInputIterator<InputIterator>::value, "");
assert(position >= begin() && position <= end());
size_type index = position - cbegin();
size_type i = index;
while (first != last) insert(begin() + i++, *first++);
return begin() + index;
}
void SwapImpl(InlinedVector& other) { void SwapImpl(InlinedVector& other) {
using std::swap; // Augment ADL with `std::swap`. using std::swap; // Augment ADL with `std::swap`.
...@@ -1393,6 +1362,7 @@ auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H { ...@@ -1393,6 +1362,7 @@ auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H {
auto n = v.size(); auto n = v.size();
return H::combine(H::combine_contiguous(std::move(h), p, n), n); return H::combine(H::combine_contiguous(std::move(h), p, n), n);
} }
} // namespace absl
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Implementation of InlinedVector // Implementation of InlinedVector
...@@ -1400,6 +1370,4 @@ auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H { ...@@ -1400,6 +1370,4 @@ auto AbslHashValue(H h, const InlinedVector<TheT, TheN, TheA>& v) -> H {
// Do not depend on any below implementation details! // Do not depend on any below implementation details!
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
} // namespace absl
#endif // ABSL_CONTAINER_INLINED_VECTOR_H_ #endif // ABSL_CONTAINER_INLINED_VECTOR_H_
...@@ -93,7 +93,7 @@ int64_t GetGeometricVariable(int64_t mean) { ...@@ -93,7 +93,7 @@ int64_t GetGeometricVariable(int64_t mean) {
// under piii debug for some binaries. // under piii debug for some binaries.
double q = static_cast<uint32_t>(rng >> (prng_mod_power - 26)) + 1.0; double q = static_cast<uint32_t>(rng >> (prng_mod_power - 26)) + 1.0;
// Put the computed p-value through the CDF of a geometric. // Put the computed p-value through the CDF of a geometric.
double interval = (std::log2(q) - 26) * (-std::log(2.0) * mean); double interval = (log2(q) - 26) * (-std::log(2.0) * mean);
// Very large values of interval overflow int64_t. If we happen to // Very large values of interval overflow int64_t. If we happen to
// hit such improbable condition, we simply cheat and clamp interval // hit such improbable condition, we simply cheat and clamp interval
......
...@@ -541,17 +541,8 @@ hash_range_or_bytes(H hash_state, const T* data, size_t size) { ...@@ -541,17 +541,8 @@ hash_range_or_bytes(H hash_state, const T* data, size_t size) {
// * If is_uniquely_represented, hash bytes directly. // * If is_uniquely_represented, hash bytes directly.
// * ADL AbslHashValue(H, const T&) call. // * ADL AbslHashValue(H, const T&) call.
// * std::hash<T> // * std::hash<T>
// In MSVC we can't probe std::hash or stdext::hash because it triggers a
// static_assert instead of failing substitution.
#if defined(_MSC_VER)
#define ABSL_HASH_INTERNAL_CAN_POISON_ 0
#else // _MSC_VER
#define ABSL_HASH_INTERNAL_CAN_POISON_ 1
#endif // _MSC_VER
#if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \ #if defined(ABSL_INTERNAL_LEGACY_HASH_NAMESPACE) && \
ABSL_HASH_INTERNAL_CAN_POISON_ ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
#define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 1
#else #else
#define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0 #define ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ 0
...@@ -616,13 +607,7 @@ struct HashSelect { ...@@ -616,13 +607,7 @@ struct HashSelect {
#endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_ #endif // ABSL_HASH_INTERNAL_SUPPORT_LEGACY_HASH_
template <typename U> template <typename U>
using ProbeStdHash = using ProbeStdHash = absl::type_traits_internal::IsHashable<U>;
#if ABSL_HASH_INTERNAL_CAN_POISON_
std::is_convertible<decltype(std::hash<U>()(std::declval<const U&>())),
size_t>;
#else // ABSL_HASH_INTERNAL_CAN_POISON_
std::true_type;
#endif // ABSL_HASH_INTERNAL_CAN_POISON_
template <typename U> template <typename U>
using ProbeNone = std::true_type; using ProbeNone = std::true_type;
......
...@@ -200,7 +200,7 @@ bool RunOnStartup<f>::run = (f(), true); ...@@ -200,7 +200,7 @@ bool RunOnStartup<f>::run = (f(), true);
template < template <
typename T, typename U, typename T, typename U,
// Only trigger for when (T != U), // Only trigger for when (T != U),
absl::enable_if_t<!std::is_same<T, U>::value, int> = 0, typename = absl::enable_if_t<!std::is_same<T, U>::value>,
// This statement works in two ways: // This statement works in two ways:
// - First, it instantiates RunOnStartup and forces the initialization of // - First, it instantiates RunOnStartup and forces the initialization of
// `run`, which set the global variable. // `run`, which set the global variable.
......
...@@ -413,21 +413,73 @@ template <typename T> ...@@ -413,21 +413,73 @@ template <typename T>
using result_of_t = typename std::result_of<T>::type; using result_of_t = typename std::result_of<T>::type;
namespace type_traits_internal { namespace type_traits_internal {
// In MSVC we can't probe std::hash or stdext::hash because it triggers a
// static_assert instead of failing substitution. Libc++ prior to 4.0
// also used a static_assert.
//
#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \
_LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 0
#else
#define ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_ 1
#endif
#if !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
template <typename Key, typename = size_t> template <typename Key, typename = size_t>
struct IsHashable : std::true_type {};
#else // ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
template <typename Key, typename = void>
struct IsHashable : std::false_type {}; struct IsHashable : std::false_type {};
template <typename Key> template <typename Key>
struct IsHashable<Key, struct IsHashable<
decltype(std::declval<std::hash<Key>>()(std::declval<Key>()))> Key,
: std::true_type {}; absl::enable_if_t<std::is_convertible<
decltype(std::declval<std::hash<Key>&>()(std::declval<Key const&>())),
std::size_t>::value>> : std::true_type {};
#endif // !ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
struct AssertHashEnabledHelper {
private:
static void Sink(...) {}
struct NAT {};
template <class Key>
static auto GetReturnType(int)
-> decltype(std::declval<std::hash<Key>>()(std::declval<Key const&>()));
template <class Key>
static NAT GetReturnType(...);
template <class Key>
static std::nullptr_t DoIt() {
static_assert(IsHashable<Key>::value,
"std::hash<Key> does not provide a call operator");
static_assert(
std::is_default_constructible<std::hash<Key>>::value,
"std::hash<Key> must be default constructible when it is enabled");
static_assert(
std::is_copy_constructible<std::hash<Key>>::value,
"std::hash<Key> must be copy constructible when it is enabled");
static_assert(absl::is_copy_assignable<std::hash<Key>>::value,
"std::hash<Key> must be copy assignable when it is enabled");
// is_destructible is unchecked as it's implied by each of the
// is_constructible checks.
using ReturnType = decltype(GetReturnType<Key>(0));
static_assert(std::is_same<ReturnType, NAT>::value ||
std::is_same<ReturnType, size_t>::value,
"std::hash<Key> must return size_t");
return nullptr;
}
template <class... Ts>
friend void AssertHashEnabled();
};
template <typename Key> template <class... Ts>
struct IsHashEnabled inline void AssertHashEnabled() {
: absl::conjunction<std::is_default_constructible<std::hash<Key>>, using Helper = AssertHashEnabledHelper;
std::is_copy_constructible<std::hash<Key>>, Helper::Sink(Helper::DoIt<Ts>()...);
std::is_destructible<std::hash<Key>>, }
absl::is_copy_assignable<std::hash<Key>>,
IsHashable<Key>> {};
} // namespace type_traits_internal } // namespace type_traits_internal
......
...@@ -1021,7 +1021,7 @@ TEST(MakeTime, LocalTimeLibC) { ...@@ -1021,7 +1021,7 @@ TEST(MakeTime, LocalTimeLibC) {
// 1) we know how to change the time zone used by localtime()/mktime(), // 1) we know how to change the time zone used by localtime()/mktime(),
// 2) cctz and localtime()/mktime() will use similar-enough tzdata, and // 2) cctz and localtime()/mktime() will use similar-enough tzdata, and
// 3) we have some idea about how mktime() behaves during transitions. // 3) we have some idea about how mktime() behaves during transitions.
#if defined(__linux__) #if defined(__linux__) && !defined(__ANDROID__)
const char* const ep = getenv("TZ"); const char* const ep = getenv("TZ");
std::string tz_name = (ep != nullptr) ? ep : ""; std::string tz_name = (ep != nullptr) ? ep : "";
for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) { for (const char* const* np = kTimeZoneNames; *np != nullptr; ++np) {
......
...@@ -1605,11 +1605,12 @@ struct VariantHashVisitor { ...@@ -1605,11 +1605,12 @@ struct VariantHashVisitor {
template <typename Variant, typename... Ts> template <typename Variant, typename... Ts>
struct VariantHashBase<Variant, struct VariantHashBase<Variant,
absl::enable_if_t<absl::conjunction< absl::enable_if_t<absl::conjunction<
type_traits_internal::IsHashEnabled<Ts>...>::value>, type_traits_internal::IsHashable<Ts>...>::value>,
Ts...> { Ts...> {
using argument_type = Variant; using argument_type = Variant;
using result_type = size_t; using result_type = size_t;
size_t operator()(const Variant& var) const { size_t operator()(const Variant& var) const {
type_traits_internal::AssertHashEnabled<Ts...>();
if (var.valueless_by_exception()) { if (var.valueless_by_exception()) {
return 239799884; return 239799884;
} }
......
...@@ -467,6 +467,7 @@ struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()( ...@@ -467,6 +467,7 @@ struct optional_hash_base<T, decltype(std::hash<absl::remove_const_t<T> >()(
using argument_type = absl::optional<T>; using argument_type = absl::optional<T>;
using result_type = size_t; using result_type = size_t;
size_t operator()(const absl::optional<T>& opt) const { size_t operator()(const absl::optional<T>& opt) const {
absl::type_traits_internal::AssertHashEnabled<absl::remove_const_t<T>>();
if (opt) { if (opt) {
return std::hash<absl::remove_const_t<T> >()(*opt); return std::hash<absl::remove_const_t<T> >()(*opt);
} else { } else {
......
...@@ -1504,18 +1504,19 @@ TEST(optionalTest, Hash) { ...@@ -1504,18 +1504,19 @@ TEST(optionalTest, Hash) {
static_assert(is_hash_enabled_for<absl::optional<int>>::value, ""); static_assert(is_hash_enabled_for<absl::optional<int>>::value, "");
static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, ""); static_assert(is_hash_enabled_for<absl::optional<Hashable>>::value, "");
static_assert(
absl::type_traits_internal::IsHashable<absl::optional<int>>::value, "");
static_assert(
absl::type_traits_internal::IsHashable<absl::optional<Hashable>>::value,
"");
absl::type_traits_internal::AssertHashEnabled<absl::optional<int>>();
absl::type_traits_internal::AssertHashEnabled<absl::optional<Hashable>>();
#if defined(_MSC_VER) || (defined(_LIBCPP_VERSION) && \ #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
_LIBCPP_VERSION < 4000 && _LIBCPP_STD_VER > 11)
// For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
// static_assert to catch any user-defined type that doesn't provide a hash
// specialization. So instantiating std::hash<absl::optional<T>> will result
// in a hard error which is not SFINAE friendly.
#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
#endif
#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY
static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, ""); static_assert(!is_hash_enabled_for<absl::optional<NonHashable>>::value, "");
static_assert(!absl::type_traits_internal::IsHashable<
absl::optional<NonHashable>>::value,
"");
#endif #endif
// libstdc++ std::optional is missing remove_const_t, i.e. it's using // libstdc++ std::optional is missing remove_const_t, i.e. it's using
......
...@@ -1977,29 +1977,17 @@ TEST(VariantTest, MonostateHash) { ...@@ -1977,29 +1977,17 @@ TEST(VariantTest, MonostateHash) {
} }
TEST(VariantTest, Hash) { TEST(VariantTest, Hash) {
static_assert(type_traits_internal::IsHashEnabled<variant<int>>::value, ""); static_assert(type_traits_internal::IsHashable<variant<int>>::value, "");
static_assert(type_traits_internal::IsHashEnabled<variant<Hashable>>::value, static_assert(type_traits_internal::IsHashable<variant<Hashable>>::value, "");
static_assert(type_traits_internal::IsHashable<variant<int, Hashable>>::value,
""); "");
static_assert(
type_traits_internal::IsHashEnabled<variant<int, Hashable>>::value, "");
#if defined(_MSC_VER) || \
(defined(_LIBCPP_VERSION) && _LIBCPP_VERSION < 4000 && \
_LIBCPP_STD_VER > 11) || \
defined(__APPLE__)
// For MSVC and libc++ (< 4.0 and c++14), std::hash primary template has a
// static_assert to catch any user-defined type T that doesn't provide a hash
// specialization. So instantiating std::hash<variant<T>> will result
// in a hard error which is not SFINAE friendly.
#define ABSL_STD_HASH_NOT_SFINAE_FRIENDLY 1
#endif
#ifndef ABSL_STD_HASH_NOT_SFINAE_FRIENDLY #if ABSL_META_INTERNAL_STD_HASH_SFINAE_FRIENDLY_
static_assert( static_assert(!type_traits_internal::IsHashable<variant<NonHashable>>::value,
!type_traits_internal::IsHashEnabled<variant<NonHashable>>::value, "");
static_assert(!type_traits_internal::IsHashEnabled<
variant<Hashable, NonHashable>>::value,
""); "");
static_assert(
!type_traits_internal::IsHashable<variant<Hashable, NonHashable>>::value,
"");
#endif #endif
// MSVC std::hash<std::variant> does not use the index, thus produce the same // MSVC std::hash<std::variant> does not use the index, thus produce the same
...@@ -2023,11 +2011,10 @@ TEST(VariantTest, Hash) { ...@@ -2023,11 +2011,10 @@ TEST(VariantTest, Hash) {
EXPECT_GT(hashcodes.size(), 90); EXPECT_GT(hashcodes.size(), 90);
// test const-qualified // test const-qualified
static_assert(type_traits_internal::IsHashable<variant<const int>>::value,
"");
static_assert( static_assert(
type_traits_internal::IsHashEnabled<variant<const int>>::value, ""); type_traits_internal::IsHashable<variant<const Hashable>>::value, "");
static_assert(
type_traits_internal::IsHashEnabled<variant<const Hashable>>::value,
"");
std::hash<absl::variant<const int>> c_hash; std::hash<absl::variant<const int>> c_hash;
for (int i = 0; i < 100; ++i) { for (int i = 0; i < 100; ++i) {
EXPECT_EQ(hash(i), c_hash(i)); EXPECT_EQ(hash(i), c_hash(i));
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment