mirror of
https://github.com/greg7mdp/parallel-hashmap.git
synced 2026-08-29 08:34:39 +08:00
improve the hash "combine" support.
This commit is contained in:
Vendored
+1
-1
@@ -49,7 +49,7 @@ before_build:
|
||||
|
||||
build_script:
|
||||
- cmake --version
|
||||
- cmake -H. -Bbuild -DPHMAP_BUILD_TESTS=%TEST% -G %CMAKE_GENERATOR%
|
||||
- cmake -H. -Bbuild -DPHMAP_BUILD_TESTS=%TEST% -DPHMAP_BUILD_EXAMPLES=%TEST% -G %CMAKE_GENERATOR%
|
||||
- cmake --build build --config %CONFIG% --target ALL_BUILD -- /maxcpucount
|
||||
|
||||
test_script:
|
||||
|
||||
Vendored
+1
-1
@@ -115,4 +115,4 @@ matrix:
|
||||
dist: trusty
|
||||
|
||||
script:
|
||||
mkdir build && cd build && cmake -DPHMAP_BUILD_TESTS=ON -DCMAKE_CXX_COMPILER=${COMPILER} -DCXXFLAGS="${CXX_FLAGS}" .. && cmake --build . && make test
|
||||
mkdir build && cd build && cmake -DPHMAP_BUILD_TESTS=ON -DPHMAP_BUILD_EXAMPLES=ON -DCMAKE_CXX_COMPILER=${COMPILER} -DCXXFLAGS="${CXX_FLAGS}" .. && cmake --build . && make test
|
||||
|
||||
@@ -159,67 +159,20 @@ The rules are the same as for std::unordered_map, and are valid for all the phma
|
||||
|
||||
## Example 2 - providing a hash function for a user-defined class
|
||||
|
||||
In order to use a flat_hash_set or flat_hash_map, a hash function should be provided. Even though a the hash function can be provided via the HashFcn template parameter, we recommend injecting a specialization of `std::hash` for the class into the "std" namespace. For example:
|
||||
In order to use a flat_hash_set or flat_hash_map, a hash function should be provided. Even though a the hash function can be provided via the HashFcn template parameter, we recommend injecting a specialization of `std::hash` for the class into the "std" namespace. We provide a convenient and small header `phmap_utils.h` which allows to easily add such specializations.
|
||||
|
||||
For example:
|
||||
|
||||
** file <Person.h> **
|
||||
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <parallel_hashmap/phmap_utils.h> // minimal header providing phmap::HashState()
|
||||
#include <string>
|
||||
#include <parallel_hashmap/phmap.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
struct Person
|
||||
struct Person
|
||||
{
|
||||
bool operator==(const Person &o) const
|
||||
{ return _first == o._first && _last == o._last; }
|
||||
|
||||
string _first;
|
||||
string _last;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
// inject specialization of std::hash for Person into namespace std
|
||||
// ----------------------------------------------------------------
|
||||
template<>
|
||||
struct hash<Person>
|
||||
{
|
||||
std::size_t operator()(Person const &p) const
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
phmap::hash_combine(seed, p._first);
|
||||
phmap::hash_combine(seed, p._last);
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
// As we have defined a specialization of std::hash() for Person,
|
||||
// we can now create flat_hash_set or flat_hash_map of Persons
|
||||
// ----------------------------------------------------------------
|
||||
phmap::flat_hash_set<Person> persons = { { "John", "Galt" },
|
||||
{ "Jane", "Doe" } };
|
||||
for (auto& p: persons)
|
||||
std::cout << p._first << ' ' << p._last << '\n';
|
||||
}
|
||||
```
|
||||
|
||||
The `std::hash` specialization for `Person` combines the hash values for both first and last name using the convenient phmap::hash_combine function, and returns the combined hash value.
|
||||
|
||||
phmap::hash_combine is provided by the header `parallel_hashmap/phmap.h`. However, class definitions often appear in header files, and it is desirable to limit the size of headers included in such header files, so we provide the very small header `parallel_hashmap/phmap_utils.h` for that purpose:
|
||||
|
||||
```c++
|
||||
#include <string>
|
||||
#include <parallel_hashmap/phmap_utils.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
struct Person
|
||||
{
|
||||
bool operator==(const Person &o) const
|
||||
bool operator==(const Person &o) const
|
||||
{
|
||||
return _first == o._first && _last == o._last && _age == o._age;
|
||||
}
|
||||
@@ -233,21 +186,43 @@ namespace std
|
||||
{
|
||||
// inject specialization of std::hash for Person into namespace std
|
||||
// ----------------------------------------------------------------
|
||||
template<>
|
||||
struct hash<Person>
|
||||
template<> struct hash<Person>
|
||||
{
|
||||
std::size_t operator()(Person const &p) const
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
phmap::hash_combine(seed, p._first);
|
||||
phmap::hash_combine(seed, p._last);
|
||||
phmap::hash_combine(seed, p._age);
|
||||
return seed;
|
||||
return phmap::HashState().combine(0, p._first, p._last, p._age);
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
The `std::hash` specialization for `Person` combines the hash values for both first and last name and age, using the convenient phmap::HashState() function, and returns the combined hash value.
|
||||
|
||||
** file <main.cpp> **
|
||||
|
||||
```c++
|
||||
#include "Person.h" // defines Person with std::hash specialization
|
||||
|
||||
#include <iostream>
|
||||
#include <parallel_hashmap/phmap.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
// As we have defined a specialization of std::hash() for Person,
|
||||
// we can now create sparse_hash_set or sparse_hash_map of Persons
|
||||
// ----------------------------------------------------------------
|
||||
phmap::flat_hash_set<Person> persons =
|
||||
{ { "John", "Mitchell", 35 },
|
||||
{ "Jane", "Smith", 32 },
|
||||
{ "Jane", "Smith", 30 },
|
||||
};
|
||||
|
||||
for (auto& p: persons)
|
||||
std::cout << p._first << ' ' << p._last << " (" << p._age << ")" << '\n';
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Thread safety
|
||||
|
||||
|
||||
@@ -9,11 +9,12 @@ int main()
|
||||
// we can now create sparse_hash_set or sparse_hash_map of Persons
|
||||
// ----------------------------------------------------------------
|
||||
phmap::flat_hash_set<Person> persons =
|
||||
{ { "John", "Galt" },
|
||||
{ "Jane", "Doe" }
|
||||
{ { "John", "Mitchell", 35 },
|
||||
{ "Jane", "Smith", 32 },
|
||||
{ "Jane", "Smith", 30 },
|
||||
};
|
||||
|
||||
for (auto& p: persons)
|
||||
std::cout << p._first << ' ' << p._last << '\n';
|
||||
std::cout << p._first << ' ' << p._last << " (" << p._age << ")" << '\n';
|
||||
|
||||
}
|
||||
|
||||
Vendored
+7
-11
@@ -1,8 +1,7 @@
|
||||
#ifndef phmap_example_hash_std_
|
||||
#define phmap_example_hash_std_
|
||||
|
||||
#include <parallel_hashmap/phmap_utils.h>
|
||||
|
||||
#include <parallel_hashmap/phmap_utils.h> // minimal header providing phmap::hash_combine
|
||||
#include <string>
|
||||
using std::string;
|
||||
|
||||
@@ -10,26 +9,23 @@ struct Person
|
||||
{
|
||||
bool operator==(const Person &o) const
|
||||
{
|
||||
return _first == o._first && _last == o._last;
|
||||
return _first == o._first && _last == o._last && _age == o._age;
|
||||
}
|
||||
|
||||
string _first;
|
||||
string _last;
|
||||
int _age;
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
// inject specialization of std::hash for Person into namespace std
|
||||
// ----------------------------------------------------------------
|
||||
template<>
|
||||
struct hash<Person>
|
||||
// inject specialization of std::hash for Person into namespace std
|
||||
// ----------------------------------------------------------------
|
||||
template<> struct hash<Person>
|
||||
{
|
||||
std::size_t operator()(Person const &p) const
|
||||
{
|
||||
std::size_t seed = 0;
|
||||
phmap::hash_combine(seed, p._first);
|
||||
phmap::hash_combine(seed, p._last);
|
||||
return seed;
|
||||
return phmap::HashState().combine(0, p._first, p._last, p._age);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Vendored
+159
-1
@@ -46,11 +46,11 @@
|
||||
#include <utility>
|
||||
#include <mutex>
|
||||
#include <array>
|
||||
#include <functional>
|
||||
#include <cassert>
|
||||
|
||||
#include "phmap_bits.h"
|
||||
#include "phmap_base.h"
|
||||
#include "phmap_utils.h"
|
||||
#include "phmap_fwd_decl.h"
|
||||
|
||||
#if PHMAP_HAVE_STD_STRING_VIEW
|
||||
@@ -58,6 +58,164 @@
|
||||
#endif
|
||||
|
||||
namespace phmap {
|
||||
|
||||
// ---------------------------------------------------------------
|
||||
// phmap::Hash
|
||||
// ---------------------------------------------------------------
|
||||
template <class T>
|
||||
struct Hash
|
||||
{
|
||||
inline size_t operator()(const T& __v) const
|
||||
{
|
||||
return std::hash<T>()(__v);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Hash<T *>
|
||||
{
|
||||
inline size_t operator()(const T *__v) const noexcept
|
||||
{
|
||||
static const size_t shift = 3;
|
||||
const uintptr_t i = (const uintptr_t)__v;
|
||||
return static_cast<size_t>(i >> shift);
|
||||
}
|
||||
};
|
||||
|
||||
// from http://burtleburtle.net/bob/hash/integer.html
|
||||
// fast and efficient for power of two table sizes where we always
|
||||
// consider the last bits.
|
||||
// ---------------------------------------------------------------
|
||||
inline size_t phmap_mix_32(uint32_t a)
|
||||
{
|
||||
a = a ^ (a >> 4);
|
||||
a = (a ^ 0xdeadbeef) + (a << 5);
|
||||
a = a ^ (a >> 11);
|
||||
return static_cast<size_t>(a);
|
||||
}
|
||||
|
||||
// More thorough scrambling as described in
|
||||
// https://gist.github.com/badboy/6267743
|
||||
// ----------------------------------------
|
||||
inline size_t phmap_mix_64(uint64_t a)
|
||||
{
|
||||
a = (~a) + (a << 21); // a = (a << 21) - a - 1;
|
||||
a = a ^ (a >> 24);
|
||||
a = (a + (a << 3)) + (a << 8); // a * 265
|
||||
a = a ^ (a >> 14);
|
||||
a = (a + (a << 2)) + (a << 4); // a * 21
|
||||
a = a ^ (a >> 28);
|
||||
a = a + (a << 31);
|
||||
return static_cast<size_t>(a);
|
||||
}
|
||||
|
||||
template<class ArgumentType, class ResultType>
|
||||
struct phmap_unary_function
|
||||
{
|
||||
typedef ArgumentType argument_type;
|
||||
typedef ResultType result_type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<bool> : public phmap_unary_function<bool, size_t>
|
||||
{
|
||||
inline size_t operator()(bool __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<char> : public phmap_unary_function<char, size_t>
|
||||
{
|
||||
inline size_t operator()(char __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<signed char> : public phmap_unary_function<signed char, size_t>
|
||||
{
|
||||
inline size_t operator()(signed char __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<unsigned char> : public phmap_unary_function<unsigned char, size_t>
|
||||
{
|
||||
inline size_t operator()(unsigned char __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<wchar_t> : public phmap_unary_function<wchar_t, size_t>
|
||||
{
|
||||
inline size_t operator()(wchar_t __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<int16_t> : public phmap_unary_function<int16_t, size_t>
|
||||
{
|
||||
inline size_t operator()(int16_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<uint16_t> : public phmap_unary_function<uint16_t, size_t>
|
||||
{
|
||||
inline size_t operator()(uint16_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<int32_t> : public phmap_unary_function<int32_t, size_t>
|
||||
{
|
||||
inline size_t operator()(int32_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<uint32_t> : public phmap_unary_function<uint32_t, size_t>
|
||||
{
|
||||
inline size_t operator()(uint32_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<int64_t> : public phmap_unary_function<int64_t, size_t>
|
||||
{
|
||||
inline size_t operator()(int64_t __v) const noexcept
|
||||
{ return phmap_mix_64(static_cast<uint64_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<uint64_t> : public phmap_unary_function<uint64_t, size_t>
|
||||
{
|
||||
inline size_t operator()(uint64_t __v) const noexcept
|
||||
{ return phmap_mix_64(static_cast<uint64_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<float> : public phmap_unary_function<float, size_t>
|
||||
{
|
||||
inline size_t operator()(float __v) const noexcept
|
||||
{
|
||||
// -0.0 and 0.0 should return same hash
|
||||
uint32_t *as_int = reinterpret_cast<uint32_t *>(&__v);
|
||||
return (__v == 0) ? static_cast<size_t>(0) : phmap_mix_32(*as_int);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<double> : public phmap_unary_function<double, size_t>
|
||||
{
|
||||
inline size_t operator()(double __v) const noexcept
|
||||
{
|
||||
// -0.0 and 0.0 should return same hash
|
||||
uint64_t *as_int = reinterpret_cast<uint64_t *>(&__v);
|
||||
return (__v == 0) ? static_cast<size_t>(0) : phmap_mix_64(*as_int);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
namespace container_internal {
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
|
||||
Vendored
+37
-171
@@ -4,6 +4,8 @@
|
||||
// ---------------------------------------------------------------------------
|
||||
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
|
||||
//
|
||||
// minimal header providing phmap::hash_combine
|
||||
//
|
||||
// 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
|
||||
@@ -17,195 +19,59 @@
|
||||
// limitations under the License.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
//#include <cstddef>
|
||||
#include <functional>
|
||||
#include <cstddef>
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<class Key> struct hash;
|
||||
} // namespace std
|
||||
|
||||
namespace phmap
|
||||
{
|
||||
|
||||
template <class T>
|
||||
struct Hash
|
||||
template <class H, int sz> struct Combiner
|
||||
{
|
||||
inline size_t operator()(const T& __v) const
|
||||
H operator()(H seed, size_t value);
|
||||
};
|
||||
|
||||
template <class H> struct Combiner<H, 4>
|
||||
{
|
||||
H operator()(H seed, size_t value)
|
||||
{
|
||||
return std::hash<T>()(__v);
|
||||
return seed ^ (value + 0x9e3779b9 + (seed << 6) + (seed >> 2));
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct Hash<T *>
|
||||
template <class H> struct Combiner<H, 8>
|
||||
{
|
||||
inline size_t operator()(const T *__v) const noexcept
|
||||
H operator()(H seed, size_t value)
|
||||
{
|
||||
static const size_t shift = 3;
|
||||
const uintptr_t i = (const uintptr_t)__v;
|
||||
return static_cast<size_t>(i >> shift);
|
||||
return seed ^ (value + size_t(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2));
|
||||
}
|
||||
};
|
||||
|
||||
// from http://burtleburtle.net/bob/hash/integer.html
|
||||
// fast and efficient for power of two table sizes where we always
|
||||
// consider the last bits.
|
||||
// ---------------------------------------------------------------
|
||||
inline size_t phmap_mix_32(uint32_t a)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
template <typename H>
|
||||
class HashStateBase {
|
||||
public:
|
||||
template <typename T, typename... Ts>
|
||||
static H combine(H state, const T& value, const Ts&... values);
|
||||
|
||||
static H combine(H state) { return state; }
|
||||
};
|
||||
|
||||
template <typename H>
|
||||
template <typename T, typename... Ts>
|
||||
H HashStateBase<H>::combine(H seed, const T& v, const Ts&... vs)
|
||||
{
|
||||
a = a ^ (a >> 4);
|
||||
a = (a ^ 0xdeadbeef) + (a << 5);
|
||||
a = a ^ (a >> 11);
|
||||
return static_cast<size_t>(a);
|
||||
return HashStateBase<H>::combine(Combiner<H, sizeof(H)>()(
|
||||
seed, std::hash<T>()(v)), vs...);
|
||||
}
|
||||
|
||||
// More thorough scrambling as described in
|
||||
// https://gist.github.com/badboy/6267743
|
||||
// ----------------------------------------
|
||||
inline size_t phmap_mix_64(uint64_t a)
|
||||
{
|
||||
a = (~a) + (a << 21); // a = (a << 21) - a - 1;
|
||||
a = a ^ (a >> 24);
|
||||
a = (a + (a << 3)) + (a << 8); // a * 265
|
||||
a = a ^ (a >> 14);
|
||||
a = (a + (a << 2)) + (a << 4); // a * 21
|
||||
a = a ^ (a >> 28);
|
||||
a = a + (a << 31);
|
||||
return static_cast<size_t>(a);
|
||||
}
|
||||
using HashState = HashStateBase<size_t>;
|
||||
|
||||
template<class ArgumentType, class ResultType>
|
||||
struct phmap_unary_function
|
||||
{
|
||||
typedef ArgumentType argument_type;
|
||||
typedef ResultType result_type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<bool> : public phmap_unary_function<bool, size_t>
|
||||
{
|
||||
inline size_t operator()(bool __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<char> : public phmap_unary_function<char, size_t>
|
||||
{
|
||||
inline size_t operator()(char __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<signed char> : public phmap_unary_function<signed char, size_t>
|
||||
{
|
||||
inline size_t operator()(signed char __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<unsigned char> : public phmap_unary_function<unsigned char, size_t>
|
||||
{
|
||||
inline size_t operator()(unsigned char __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<wchar_t> : public phmap_unary_function<wchar_t, size_t>
|
||||
{
|
||||
inline size_t operator()(wchar_t __v) const noexcept
|
||||
{ return static_cast<size_t>(__v); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<int16_t> : public phmap_unary_function<int16_t, size_t>
|
||||
{
|
||||
inline size_t operator()(int16_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<uint16_t> : public phmap_unary_function<uint16_t, size_t>
|
||||
{
|
||||
inline size_t operator()(uint16_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<int32_t> : public phmap_unary_function<int32_t, size_t>
|
||||
{
|
||||
inline size_t operator()(int32_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<uint32_t> : public phmap_unary_function<uint32_t, size_t>
|
||||
{
|
||||
inline size_t operator()(uint32_t __v) const noexcept
|
||||
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<int64_t> : public phmap_unary_function<int64_t, size_t>
|
||||
{
|
||||
inline size_t operator()(int64_t __v) const noexcept
|
||||
{ return phmap_mix_64(static_cast<uint64_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<uint64_t> : public phmap_unary_function<uint64_t, size_t>
|
||||
{
|
||||
inline size_t operator()(uint64_t __v) const noexcept
|
||||
{ return phmap_mix_64(static_cast<uint64_t>(__v)); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<float> : public phmap_unary_function<float, size_t>
|
||||
{
|
||||
inline size_t operator()(float __v) const noexcept
|
||||
{
|
||||
// -0.0 and 0.0 should return same hash
|
||||
uint32_t *as_int = reinterpret_cast<uint32_t *>(&__v);
|
||||
return (__v == 0) ? static_cast<size_t>(0) : phmap_mix_32(*as_int);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Hash<double> : public phmap_unary_function<double, size_t>
|
||||
{
|
||||
inline size_t operator()(double __v) const noexcept
|
||||
{
|
||||
// -0.0 and 0.0 should return same hash
|
||||
uint64_t *as_int = reinterpret_cast<uint64_t *>(&__v);
|
||||
return (__v == 0) ? static_cast<size_t>(0) : phmap_mix_64(*as_int);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T, int sz> struct Combiner
|
||||
{
|
||||
inline void operator()(T& seed, T value);
|
||||
};
|
||||
|
||||
template <class T> struct Combiner<T, 4>
|
||||
{
|
||||
inline void operator()(T& seed, T value)
|
||||
{
|
||||
seed ^= value + 0x9e3779b9 + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct Combiner<T, 8>
|
||||
{
|
||||
inline void operator()(T& seed, T value)
|
||||
{
|
||||
seed ^= value + T(0xc6a4a7935bd1e995) + (seed << 6) + (seed >> 2);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
inline void hash_combine(std::size_t& seed, T const& v)
|
||||
{
|
||||
Combiner<std::size_t, sizeof(std::size_t)> combiner;
|
||||
|
||||
combiner(seed, phmap::Hash<T>()(v));
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace phmap
|
||||
|
||||
|
||||
#endif // phmap_utils_h_guard_
|
||||
|
||||
Reference in New Issue
Block a user