mirror of
https://github.com/greg7mdp/parallel-hashmap.git
synced 2026-08-31 01:20:40 +08:00
building on linux
This commit is contained in:
Vendored
+133
-131
@@ -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 {
|
||||
|
||||
|
||||
Vendored
+86
-56
@@ -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];
|
||||
|
||||
Vendored
+180
@@ -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_
|
||||
|
||||
Vendored
+27
-27
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user