Make variant's index part of the hash value

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@288554 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Eric Fiselier
2016-12-02 23:38:31 +00:00
parent 4975ccc637
commit 120401a4e0
4 changed files with 31 additions and 10 deletions

View File

@@ -3345,6 +3345,17 @@ struct __scalar_hash<_Tp, 4>
} }
}; };
_LIBCPP_INLINE_VISIBILITY
inline size_t __hash_combine(size_t __lhs, size_t __rhs) _NOEXCEPT {
struct _PairT {
size_t first;
size_t second;
};
typedef __scalar_hash<_PairT> _HashT;
const _PairT __p{__lhs, __rhs};
return _HashT()(__p);
}
template<class _Tp> template<class _Tp>
struct _LIBCPP_TYPE_VIS_ONLY hash<_Tp*> struct _LIBCPP_TYPE_VIS_ONLY hash<_Tp*>
: public unary_function<_Tp*, size_t> : public unary_function<_Tp*, size_t>

View File

@@ -1526,7 +1526,8 @@ struct _LIBCPP_TYPE_VIS_ONLY hash<variant<_Types...>> {
inline _LIBCPP_INLINE_VISIBILITY inline _LIBCPP_INLINE_VISIBILITY
result_type operator()(const argument_type& __v) const { result_type operator()(const argument_type& __v) const {
using __variant_detail::__visitation::__variant; using __variant_detail::__visitation::__variant;
return __v.valueless_by_exception() size_t __res =
__v.valueless_by_exception()
? __v.index() ? __v.index()
: __variant::__visit_alt( : __variant::__visit_alt(
[](const auto& __alt) { [](const auto& __alt) {
@@ -1535,6 +1536,7 @@ struct _LIBCPP_TYPE_VIS_ONLY hash<variant<_Types...>> {
return hash<__value_type>{}(__alt.__value); return hash<__value_type>{}(__alt.__value);
}, },
__v); __v);
return __hash_combine(__res, hash<size_t>{}(__v.index()));
} }
}; };

View File

@@ -6,6 +6,7 @@
// Source Licenses. See LICENSE.TXT for details. // Source Licenses. See LICENSE.TXT for details.
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#undef NDEBUG
#include "experimental/filesystem" #include "experimental/filesystem"
#include "string_view" #include "string_view"
#include "utility" #include "utility"
@@ -390,19 +391,13 @@ int path::__compare(string_view_t __s) const {
// path.nonmembers // path.nonmembers
size_t hash_value(const path& __p) noexcept { size_t hash_value(const path& __p) noexcept {
auto PP = PathParser::CreateBegin(__p.native()); auto PP = PathParser::CreateBegin(__p.native());
struct HashPairT { size_t hash_value = 0;
size_t first;
size_t second;
};
HashPairT hp = {0, 0};
std::hash<string_view> hasher; std::hash<string_view> hasher;
std::__scalar_hash<decltype(hp)> pair_hasher;
while (PP) { while (PP) {
hp.second = hasher(*PP); hash_value = __hash_combine(hash_value, hasher(*PP));
hp.first = pair_hasher(hp);
++PP; ++PP;
} }
return hp.first; return hash_value;
} }
//////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////

View File

@@ -105,7 +105,20 @@ void test_hash_monostate() {
} }
} }
void test_hash_variant_duplicate_elements() {
// Test that the index of the alternative participates in the hash value.
using V = std::variant<std::monostate, std::monostate>;
using H = std::hash<V>;
H h{};
const V v1(std::in_place_index<0>);
const V v2(std::in_place_index<1>);
assert(h(v1) == h(v1));
assert(h(v2) == h(v2));
LIBCPP_ASSERT(h(v1) != h(v2));
}
int main() { int main() {
test_hash_variant(); test_hash_variant();
test_hash_variant_duplicate_elements();
test_hash_monostate(); test_hash_monostate();
} }