building on linux

This commit is contained in:
greg
2019-03-26 08:35:11 -04:00
parent c043f2b363
commit 6c6383b5b7
5 changed files with 431 additions and 216 deletions
+133 -131
View File
@@ -577,6 +577,139 @@ void SetHashtablezSampleParameter(int32_t rate) {}
void SetHashtablezMaxSamples(int32_t max) {}
namespace memory_internal {
// Constructs T into uninitialized storage pointed by `ptr` using the args
// specified in the tuple.
// ----------------------------------------------------------------------------
template <class Alloc, class T, class Tuple, size_t... I>
void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t,
phmap::index_sequence<I...>) {
phmap::allocator_traits<Alloc>::construct(
*alloc, ptr, std::get<I>(std::forward<Tuple>(t))...);
}
template <class T, class F>
struct WithConstructedImplF {
template <class... Args>
decltype(std::declval<F>()(std::declval<T>())) operator()(
Args&&... args) const {
return std::forward<F>(f)(T(std::forward<Args>(args)...));
}
F&& f;
};
template <class T, class Tuple, size_t... Is, class F>
decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl(
Tuple&& t, phmap::index_sequence<Is...>, F&& f) {
return WithConstructedImplF<T, F>{std::forward<F>(f)}(
std::get<Is>(std::forward<Tuple>(t))...);
}
template <class T, size_t... Is>
auto TupleRefImpl(T&& t, phmap::index_sequence<Is...>)
-> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) {
return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
}
// Returns a tuple of references to the elements of the input tuple. T must be a
// tuple.
// ----------------------------------------------------------------------------
template <class T>
auto TupleRef(T&& t) -> decltype(
TupleRefImpl(std::forward<T>(t),
phmap::make_index_sequence<
std::tuple_size<typename std::decay<T>::type>::value>())) {
return TupleRefImpl(
std::forward<T>(t),
phmap::make_index_sequence<
std::tuple_size<typename std::decay<T>::type>::value>());
}
template <class F, class K, class V>
decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct,
std::declval<std::tuple<K>>(), std::declval<V>()))
DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p) {
const auto& key = std::get<0>(p.first);
return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
std::move(p.second));
}
} // namespace memory_internal
// Helper functions for asan and msan.
// ----------------------------------------------------------------------------
inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(m, s);
#endif
#ifdef MEMORY_SANITIZER
__msan_poison(m, s);
#endif
(void)m;
(void)s;
}
inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(m, s);
#endif
#ifdef MEMORY_SANITIZER
__msan_unpoison(m, s);
#endif
(void)m;
(void)s;
}
template <typename T>
inline void SanitizerPoisonObject(const T* object) {
SanitizerPoisonMemoryRegion(object, sizeof(T));
}
template <typename T>
inline void SanitizerUnpoisonObject(const T* object) {
SanitizerUnpoisonMemoryRegion(object, sizeof(T));
}
// ----------------------------------------------------------------------------
// Allocates at least n bytes aligned to the specified alignment.
// Alignment must be a power of 2. It must be positive.
//
// Note that many allocators don't honor alignment requirements above certain
// threshold (usually either alignof(std::max_align_t) or alignof(void*)).
// Allocate() doesn't apply alignment corrections. If the underlying allocator
// returns insufficiently alignment pointer, that's what you are going to get.
// ----------------------------------------------------------------------------
template <size_t Alignment, class Alloc>
void* Allocate(Alloc* alloc, size_t n) {
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
struct alignas(Alignment) M {};
using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>;
A mem_alloc(*alloc);
void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
"allocator does not respect alignment");
return p;
}
// ----------------------------------------------------------------------------
// The pointer must have been previously obtained by calling
// Allocate<Alignment>(alloc, n).
// ----------------------------------------------------------------------------
template <size_t Alignment, class Alloc>
void Deallocate(Alloc* alloc, void* p, size_t n) {
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
struct alignas(Alignment) M {};
using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>;
A mem_alloc(*alloc);
AT::deallocate(mem_alloc, static_cast<M*>(p),
(n + sizeof(M) - 1) / sizeof(M));
}
// ----------------------------------------------------------------------------
// R A W _ H A S H _ S E T
// ----------------------------------------------------------------------------
@@ -3330,104 +3463,6 @@ private:
}
};
// ----------------------------------------------------------------------------
// Allocates at least n bytes aligned to the specified alignment.
// Alignment must be a power of 2. It must be positive.
//
// Note that many allocators don't honor alignment requirements above certain
// threshold (usually either alignof(std::max_align_t) or alignof(void*)).
// Allocate() doesn't apply alignment corrections. If the underlying allocator
// returns insufficiently alignment pointer, that's what you are going to get.
// ----------------------------------------------------------------------------
template <size_t Alignment, class Alloc>
void* Allocate(Alloc* alloc, size_t n) {
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
struct alignas(Alignment) M {};
using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>;
A mem_alloc(*alloc);
void* p = AT::allocate(mem_alloc, (n + sizeof(M) - 1) / sizeof(M));
assert(reinterpret_cast<uintptr_t>(p) % Alignment == 0 &&
"allocator does not respect alignment");
return p;
}
// ----------------------------------------------------------------------------
// The pointer must have been previously obtained by calling
// Allocate<Alignment>(alloc, n).
// ----------------------------------------------------------------------------
template <size_t Alignment, class Alloc>
void Deallocate(Alloc* alloc, void* p, size_t n) {
static_assert(Alignment > 0, "");
assert(n && "n must be positive");
struct alignas(Alignment) M {};
using A = typename phmap::allocator_traits<Alloc>::template rebind_alloc<M>;
using AT = typename phmap::allocator_traits<Alloc>::template rebind_traits<M>;
A mem_alloc(*alloc);
AT::deallocate(mem_alloc, static_cast<M*>(p),
(n + sizeof(M) - 1) / sizeof(M));
}
namespace memory_internal {
// Constructs T into uninitialized storage pointed by `ptr` using the args
// specified in the tuple.
// ----------------------------------------------------------------------------
template <class Alloc, class T, class Tuple, size_t... I>
void ConstructFromTupleImpl(Alloc* alloc, T* ptr, Tuple&& t,
phmap::index_sequence<I...>) {
phmap::allocator_traits<Alloc>::construct(
*alloc, ptr, std::get<I>(std::forward<Tuple>(t))...);
}
template <class T, class F>
struct WithConstructedImplF {
template <class... Args>
decltype(std::declval<F>()(std::declval<T>())) operator()(
Args&&... args) const {
return std::forward<F>(f)(T(std::forward<Args>(args)...));
}
F&& f;
};
template <class T, class Tuple, size_t... Is, class F>
decltype(std::declval<F>()(std::declval<T>())) WithConstructedImpl(
Tuple&& t, phmap::index_sequence<Is...>, F&& f) {
return WithConstructedImplF<T, F>{std::forward<F>(f)}(
std::get<Is>(std::forward<Tuple>(t))...);
}
template <class T, size_t... Is>
auto TupleRefImpl(T&& t, phmap::index_sequence<Is...>)
-> decltype(std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...)) {
return std::forward_as_tuple(std::get<Is>(std::forward<T>(t))...);
}
// Returns a tuple of references to the elements of the input tuple. T must be a
// tuple.
// ----------------------------------------------------------------------------
template <class T>
auto TupleRef(T&& t) -> decltype(
TupleRefImpl(std::forward<T>(t),
phmap::make_index_sequence<
std::tuple_size<typename std::decay<T>::type>::value>())) {
return TupleRefImpl(
std::forward<T>(t),
phmap::make_index_sequence<
std::tuple_size<typename std::decay<T>::type>::value>());
}
template <class F, class K, class V>
decltype(std::declval<F>()(std::declval<const K&>(), std::piecewise_construct,
std::declval<std::tuple<K>>(), std::declval<V>()))
DecomposePairImpl(F&& f, std::pair<std::tuple<K>, V> p) {
const auto& key = std::get<0>(p.first);
return std::forward<F>(f)(key, std::piecewise_construct, std::move(p.first),
std::move(p.second));
}
} // namespace memory_internal
// Constructs T into uninitialized storage pointed by `ptr` using the args
// specified in the tuple.
@@ -3512,39 +3547,6 @@ DecomposeValue(F&& f, Arg&& arg) {
return std::forward<F>(f)(key, std::forward<Arg>(arg));
}
// Helper functions for asan and msan.
// ----------------------------------------------------------------------------
inline void SanitizerPoisonMemoryRegion(const void* m, size_t s) {
#ifdef ADDRESS_SANITIZER
ASAN_POISON_MEMORY_REGION(m, s);
#endif
#ifdef MEMORY_SANITIZER
__msan_poison(m, s);
#endif
(void)m;
(void)s;
}
inline void SanitizerUnpoisonMemoryRegion(const void* m, size_t s) {
#ifdef ADDRESS_SANITIZER
ASAN_UNPOISON_MEMORY_REGION(m, s);
#endif
#ifdef MEMORY_SANITIZER
__msan_unpoison(m, s);
#endif
(void)m;
(void)s;
}
template <typename T>
inline void SanitizerPoisonObject(const T* object) {
SanitizerPoisonMemoryRegion(object, sizeof(T));
}
template <typename T>
inline void SanitizerUnpoisonObject(const T* object) {
SanitizerUnpoisonMemoryRegion(object, sizeof(T));
}
namespace memory_internal {
+86 -56
View File
@@ -750,6 +750,91 @@ using identity_t = typename identity<T>::type;
#endif // __cpp_inline_variables
// ----------- throw_delegate
namespace phmap {
namespace base_internal {
namespace {
template <typename T>
[[noreturn]] void Throw(const T& error) {
#ifdef PHMAP_HAVE_EXCEPTIONS
throw error;
#else
PHMAP_RAW_LOG(FATAL, "%s", error.what());
std::abort();
#endif
}
} // namespace
void ThrowStdLogicError(const std::string& what_arg) {
Throw(std::logic_error(what_arg));
}
void ThrowStdLogicError(const char* what_arg) {
Throw(std::logic_error(what_arg));
}
void ThrowStdInvalidArgument(const std::string& what_arg) {
Throw(std::invalid_argument(what_arg));
}
void ThrowStdInvalidArgument(const char* what_arg) {
Throw(std::invalid_argument(what_arg));
}
void ThrowStdDomainError(const std::string& what_arg) {
Throw(std::domain_error(what_arg));
}
void ThrowStdDomainError(const char* what_arg) {
Throw(std::domain_error(what_arg));
}
void ThrowStdLengthError(const std::string& what_arg) {
Throw(std::length_error(what_arg));
}
void ThrowStdLengthError(const char* what_arg) {
Throw(std::length_error(what_arg));
}
void ThrowStdOutOfRange(const std::string& what_arg) {
Throw(std::out_of_range(what_arg));
}
void ThrowStdOutOfRange(const char* what_arg) {
Throw(std::out_of_range(what_arg));
}
void ThrowStdRuntimeError(const std::string& what_arg) {
Throw(std::runtime_error(what_arg));
}
void ThrowStdRuntimeError(const char* what_arg) {
Throw(std::runtime_error(what_arg));
}
void ThrowStdRangeError(const std::string& what_arg) {
Throw(std::range_error(what_arg));
}
void ThrowStdRangeError(const char* what_arg) {
Throw(std::range_error(what_arg));
}
void ThrowStdOverflowError(const std::string& what_arg) {
Throw(std::overflow_error(what_arg));
}
void ThrowStdOverflowError(const char* what_arg) {
Throw(std::overflow_error(what_arg));
}
void ThrowStdUnderflowError(const std::string& what_arg) {
Throw(std::underflow_error(what_arg));
}
void ThrowStdUnderflowError(const char* what_arg) {
Throw(std::underflow_error(what_arg));
}
void ThrowStdBadFunctionCall() { Throw(std::bad_function_call()); }
void ThrowStdBadAlloc() { Throw(std::bad_alloc()); }
} // namespace base_internal
} // namespace phmap
// ----------- invoke.h
@@ -2965,7 +3050,7 @@ using EnableIfMutable =
template <typename T>
bool EqualImpl(Span<T> a, Span<T> b) {
static_assert(std::is_const<T>::value, "");
return phmap::equal(a.begin(), a.end(), b.begin(), b.end());
return std::equal(a.begin(), a.end(), b.begin(), b.end());
}
template <typename T>
@@ -3735,25 +3820,6 @@ constexpr size_t Max(size_t a, size_t b, Ts... rest) {
return adl_barrier::Max(b < a ? a : b, rest...);
}
template <class T>
std::string TypeName() {
std::string out;
int status = 0;
char* demangled = nullptr;
#ifdef PHMAP_INTERNAL_HAS_CXA_DEMANGLE
demangled = abi::__cxa_demangle(typeid(T).name(), nullptr, nullptr, &status);
#endif
if (status == 0 && demangled != nullptr) { // Demangling succeeded.
phmap::StrAppend(&out, "<", demangled, ">");
free(demangled);
} else {
#if defined(__GXX_RTTI) || defined(_CPPRTTI)
phmap::StrAppend(&out, "<", typeid(T).name(), ">");
#endif
}
return out;
}
} // namespace adl_barrier
template <bool C>
@@ -4075,42 +4141,6 @@ public:
#endif
}
// Human-readable description of the memory layout. Useful for debugging.
// Slow.
//
// // char[5], 3 bytes of padding, int[3], 4 bytes of padding, followed
// // by an unknown number of doubles.
// auto x = Layout<char, int, double>::Partial(5, 3);
// assert(x.DebugString() ==
// "@0<char>(1)[5]; @8<int>(4)[3]; @24<double>(8)");
//
// Each field is in the following format: @offset<type>(sizeof)[size] (<type>
// may be missing depending on the target platform). For example,
// @8<int>(4)[3] means that at offset 8 we have an array of ints, where each
// int is 4 bytes, and we have 3 of those ints. The size of the last field may
// be missing (as in the example above). Only fields with known offsets are
// described. Type names may differ across platforms: one compiler might
// produce "unsigned*" where another produces "unsigned int *".
// ---------------------------------------------------------------------------
std::string DebugString() const {
const auto offsets = Offsets();
const size_t sizes[] = {SizeOf<ElementType<OffsetSeq>>()...};
const std::string types[] = {
adl_barrier::TypeName<ElementType<OffsetSeq>>()...};
std::string res = phmap::StrCat("@0", types[0], "(", sizes[0], ")");
for (size_t i = 0; i != NumOffsets - 1; ++i) {
phmap::StrAppend(&res, "[", size_[i], "]; @", offsets[i + 1], types[i + 1],
"(", sizes[i + 1], ")");
}
// NumSizes is a constant that may be zero. Some compilers cannot see that
// inside the if statement "size_[NumSizes - 1]" must be valid.
int last = static_cast<int>(NumSizes) - 1;
if (NumTypes == NumSizes && last >= 0) {
phmap::StrAppend(&res, "[", size_[last], "]");
}
return res;
}
private:
// Arguments of `Layout::Partial()` or `Layout::Layout()`.
size_t size_[NumSizes > 0 ? NumSizes : 1];
+180
View File
@@ -637,4 +637,184 @@
#include <tmmintrin.h>
#endif
// ----------------------------------------------------------------------
// base/macros.h
// ----------------------------------------------------------------------
// PHMAP_ARRAYSIZE()
//
// Returns the number of elements in an array as a compile-time constant, which
// can be used in defining new arrays. If you use this macro on a pointer by
// mistake, you will get a compile-time error.
#define PHMAP_ARRAYSIZE(array) \
(sizeof(::absl::macros_internal::ArraySizeHelper(array)))
namespace absl {
namespace macros_internal {
// Note: this internal template function declaration is used by PHMAP_ARRAYSIZE.
// The function doesn't need a definition, as we only use its type.
template <typename T, size_t N>
auto ArraySizeHelper(const T (&array)[N]) -> char (&)[N];
} // namespace macros_internal
} // namespace absl
// kLinkerInitialized
//
// An enum used only as a constructor argument to indicate that a variable has
// static storage duration, and that the constructor should do nothing to its
// state. Use of this macro indicates to the reader that it is legal to
// declare a static instance of the class, provided the constructor is given
// the absl::base_internal::kLinkerInitialized argument.
//
// Normally, it is unsafe to declare a static variable that has a constructor or
// a destructor because invocation order is undefined. However, if the type can
// be zero-initialized (which the loader does for static variables) into a valid
// state and the type's destructor does not affect storage, then a constructor
// for static initialization can be declared.
//
// Example:
// // Declaration
// explicit MyClass(absl::base_internal:LinkerInitialized x) {}
//
// // Invocation
// static MyClass my_global(absl::base_internal::kLinkerInitialized);
namespace absl {
namespace base_internal {
enum LinkerInitialized {
kLinkerInitialized = 0,
};
} // namespace base_internal
} // namespace absl
// PHMAP_FALLTHROUGH_INTENDED
//
// Annotates implicit fall-through between switch labels, allowing a case to
// indicate intentional fallthrough and turn off warnings about any lack of a
// `break` statement. The PHMAP_FALLTHROUGH_INTENDED macro should be followed by
// a semicolon and can be used in most places where `break` can, provided that
// no statements exist between it and the next switch label.
//
// Example:
//
// switch (x) {
// case 40:
// case 41:
// if (truth_is_out_there) {
// ++x;
// PHMAP_FALLTHROUGH_INTENDED; // Use instead of/along with annotations
// // in comments
// } else {
// return x;
// }
// case 42:
// ...
//
// Notes: when compiled with clang in C++11 mode, the PHMAP_FALLTHROUGH_INTENDED
// macro is expanded to the [[clang::fallthrough]] attribute, which is analysed
// when performing switch labels fall-through diagnostic
// (`-Wimplicit-fallthrough`). See clang documentation on language extensions
// for details:
// http://clang.llvm.org/docs/AttributeReference.html#fallthrough-clang-fallthrough
//
// When used with unsupported compilers, the PHMAP_FALLTHROUGH_INTENDED macro
// has no effect on diagnostics. In any case this macro has no effect on runtime
// behavior and performance of code.
#ifdef PHMAP_FALLTHROUGH_INTENDED
#error "PHMAP_FALLTHROUGH_INTENDED should not be defined."
#endif
// TODO(zhangxy): Use c++17 standard [[fallthrough]] macro, when supported.
#if defined(__clang__) && defined(__has_warning)
#if __has_feature(cxx_attributes) && __has_warning("-Wimplicit-fallthrough")
#define PHMAP_FALLTHROUGH_INTENDED [[clang::fallthrough]]
#endif
#elif defined(__GNUC__) && __GNUC__ >= 7
#define PHMAP_FALLTHROUGH_INTENDED [[gnu::fallthrough]]
#endif
#ifndef PHMAP_FALLTHROUGH_INTENDED
#define PHMAP_FALLTHROUGH_INTENDED \
do { } while (0)
#endif
// PHMAP_DEPRECATED()
//
// Marks a deprecated class, struct, enum, function, method and variable
// declarations. The macro argument is used as a custom diagnostic message (e.g.
// suggestion of a better alternative).
//
// Example:
//
// class PHMAP_DEPRECATED("Use Bar instead") Foo {...};
// PHMAP_DEPRECATED("Use Baz instead") void Bar() {...}
//
// Every usage of a deprecated entity will trigger a warning when compiled with
// clang's `-Wdeprecated-declarations` option. This option is turned off by
// default, but the warnings will be reported by clang-tidy.
#if defined(__clang__) && __cplusplus >= 201103L
#define PHMAP_DEPRECATED(message) __attribute__((deprecated(message)))
#endif
#ifndef PHMAP_DEPRECATED
#define PHMAP_DEPRECATED(message)
#endif
// PHMAP_BAD_CALL_IF()
//
// Used on a function overload to trap bad calls: any call that matches the
// overload will cause a compile-time error. This macro uses a clang-specific
// "enable_if" attribute, as described at
// http://clang.llvm.org/docs/AttributeReference.html#enable-if
//
// Overloads which use this macro should be bracketed by
// `#ifdef PHMAP_BAD_CALL_IF`.
//
// Example:
//
// int isdigit(int c);
// #ifdef PHMAP_BAD_CALL_IF
// int isdigit(int c)
// PHMAP_BAD_CALL_IF(c <= -1 || c > 255,
// "'c' must have the value of an unsigned char or EOF");
// #endif // PHMAP_BAD_CALL_IF
#if defined(__clang__)
#if __has_attribute(enable_if)
#define PHMAP_BAD_CALL_IF(expr, msg) \
__attribute__((enable_if(expr, "Bad call trap"), unavailable(msg)))
#endif
#endif
// PHMAP_ASSERT()
//
// In C++11, `assert` can't be used portably within constexpr functions.
// PHMAP_ASSERT functions as a runtime assert but works in C++11 constexpr
// functions. Example:
//
// constexpr double Divide(double a, double b) {
// return PHMAP_ASSERT(b != 0), a / b;
// }
//
// This macro is inspired by
// https://akrzemi1.wordpress.com/2017/05/18/asserts-in-constexpr-functions/
#if defined(NDEBUG)
#define PHMAP_ASSERT(expr) (false ? (void)(expr) : (void)0)
#else
#define PHMAP_ASSERT(expr) \
(PHMAP_PREDICT_TRUE((expr)) ? (void)0 \
: [] { assert(false && #expr); }()) // NOLINT
#endif
#ifdef PHMAP_HAVE_EXCEPTIONS
#define PHMAP_INTERNAL_TRY try
#define PHMAP_INTERNAL_CATCH_ANY catch (...)
#define PHMAP_INTERNAL_RETHROW do { throw; } while (false)
#else // PHMAP_HAVE_EXCEPTIONS
#define PHMAP_INTERNAL_TRY if (true)
#define PHMAP_INTERNAL_CATCH_ANY else if (false)
#define PHMAP_INTERNAL_RETHROW do {} while (false)
#endif // PHMAP_HAVE_EXCEPTIONS
#endif // phmap_config_h_guard_
+27 -27
View File
@@ -56,7 +56,7 @@ struct Hash
template <class T>
struct Hash<T *>
{
static size_t spp_log2 (size_t val) noexcept
static size_t phmap_log2 (size_t val) noexcept
{
size_t res = 0;
while (val > 1)
@@ -69,7 +69,7 @@ struct Hash<T *>
inline size_t operator()(const T *__v) const noexcept
{
static const size_t shift = 3; // spp_log2(1 + sizeof(T)); // T might be incomplete!
static const size_t shift = 3; // phmap_log2(1 + sizeof(T)); // T might be incomplete!
const uintptr_t i = (const uintptr_t)__v;
return static_cast<size_t>(i >> shift);
}
@@ -79,7 +79,7 @@ struct Hash<T *>
// fast and efficient for power of two table sizes where we always
// consider the last bits.
// ---------------------------------------------------------------
inline size_t spp_mix_32(uint32_t a)
inline size_t phmap_mix_32(uint32_t a)
{
a = a ^ (a >> 4);
a = (a ^ 0xdeadbeef) + (a << 5);
@@ -90,7 +90,7 @@ inline size_t spp_mix_32(uint32_t a)
// More thorough scrambling as described in
// https://gist.github.com/badboy/6267743
// ----------------------------------------
inline size_t spp_mix_64(uint64_t a)
inline size_t phmap_mix_64(uint64_t a)
{
a = (~a) + (a << 21); // a = (a << 21) - a - 1;
a = a ^ (a >> 24);
@@ -103,108 +103,108 @@ inline size_t spp_mix_64(uint64_t a)
}
template<class ArgumentType, class ResultType>
struct spp_unary_function
struct phmap_unary_function
{
typedef ArgumentType argument_type;
typedef ResultType result_type;
};
template <>
struct Hash<bool> : public spp_unary_function<bool, size_t>
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 spp_unary_function<char, size_t>
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 spp_unary_function<signed char, size_t>
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 spp_unary_function<unsigned char, size_t>
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 spp_unary_function<wchar_t, size_t>
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 spp_unary_function<int16_t, size_t>
struct Hash<int16_t> : public phmap_unary_function<int16_t, size_t>
{
inline size_t operator()(int16_t __v) const noexcept
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
struct Hash<uint16_t> : public spp_unary_function<uint16_t, size_t>
struct Hash<uint16_t> : public phmap_unary_function<uint16_t, size_t>
{
inline size_t operator()(uint16_t __v) const noexcept
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
struct Hash<int32_t> : public spp_unary_function<int32_t, size_t>
struct Hash<int32_t> : public phmap_unary_function<int32_t, size_t>
{
inline size_t operator()(int32_t __v) const noexcept
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
struct Hash<uint32_t> : public spp_unary_function<uint32_t, size_t>
struct Hash<uint32_t> : public phmap_unary_function<uint32_t, size_t>
{
inline size_t operator()(uint32_t __v) const noexcept
{ return spp_mix_32(static_cast<uint32_t>(__v)); }
{ return phmap_mix_32(static_cast<uint32_t>(__v)); }
};
template <>
struct Hash<int64_t> : public spp_unary_function<int64_t, size_t>
struct Hash<int64_t> : public phmap_unary_function<int64_t, size_t>
{
inline size_t operator()(int64_t __v) const noexcept
{ return spp_mix_64(static_cast<uint64_t>(__v)); }
{ return phmap_mix_64(static_cast<uint64_t>(__v)); }
};
template <>
struct Hash<uint64_t> : public spp_unary_function<uint64_t, size_t>
struct Hash<uint64_t> : public phmap_unary_function<uint64_t, size_t>
{
inline size_t operator()(uint64_t __v) const noexcept
{ return spp_mix_64(static_cast<uint64_t>(__v)); }
{ return phmap_mix_64(static_cast<uint64_t>(__v)); }
};
template <>
struct Hash<float> : public spp_unary_function<float, size_t>
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) : spp_mix_32(*as_int);
return (__v == 0) ? static_cast<size_t>(0) : phmap_mix_32(*as_int);
}
};
template <>
struct Hash<double> : public spp_unary_function<double, size_t>
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) : spp_mix_64(*as_int);
return (__v == 0) ? static_cast<size_t>(0) : phmap_mix_64(*as_int);
}
};
@@ -232,7 +232,7 @@ template <class T> struct Combiner<T, 8>
template <class T>
inline void hash_combine(std::size_t& seed, T const& v)
{
spp_::Hash<T> hasher;
phmap::Hash<T> hasher;
Combiner<std::size_t, sizeof(std::size_t)> combiner;
combiner(seed, hasher(v));