Use parallel_hashmap library for better performance

This drastically reduces memory usage and also gains some performance.
Since this is a drop-in replacement, there is essentially no downside in
using this.
This commit is contained in:
Maximilian Keßler 2024-02-07 19:52:02 +01:00
parent 5507f8e5dc
commit f0a496a8f0
Signed by: max
GPG key ID: BCC5A619923C0BA5
10 changed files with 16926 additions and 1 deletions

View file

@ -9,6 +9,7 @@
#include <boost/rational.hpp>
#include <unordered_map>
#include <parallel_hashmap/phmap.h>
namespace Hanabi
{
@ -23,7 +24,7 @@ namespace Hanabi
using rational_probability = boost::rational<probability_base_type>;
template<class Key, class Value>
using map_type = std::unordered_map<Key, Value>;
using map_type = phmap::parallel_flat_hash_map<Key, Value>;
/**
* Define macro

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,195 @@
#if !defined(spp_memory_h_guard)
#define spp_memory_h_guard
#include <cstdint>
#include <cstring>
#include <cstdlib>
#if defined(_WIN32) || defined( __CYGWIN__)
#define SPP_WIN
#endif
#ifdef SPP_WIN
#include <windows.h>
#include <Psapi.h>
#undef min
#undef max
#elif defined(__linux__)
#include <sys/types.h>
#include <sys/sysinfo.h>
#elif defined(__FreeBSD__)
#include <paths.h>
#include <fcntl.h>
#include <kvm.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#endif
namespace spp
{
uint64_t GetSystemMemory();
uint64_t GetTotalMemoryUsed();
uint64_t GetProcessMemoryUsed();
uint64_t GetPhysicalMemory();
uint64_t GetSystemMemory()
{
#ifdef SPP_WIN
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
return static_cast<uint64_t>(memInfo.ullTotalPageFile);
#elif defined(__linux__)
struct sysinfo memInfo;
sysinfo (&memInfo);
auto totalVirtualMem = memInfo.totalram;
totalVirtualMem += memInfo.totalswap;
totalVirtualMem *= memInfo.mem_unit;
return static_cast<uint64_t>(totalVirtualMem);
#elif defined(__FreeBSD__)
kvm_t *kd;
u_int pageCnt;
size_t pageCntLen = sizeof(pageCnt);
u_int pageSize;
struct kvm_swap kswap;
uint64_t totalVirtualMem;
pageSize = static_cast<u_int>(getpagesize());
sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0);
totalVirtualMem = pageCnt * pageSize;
kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
kvm_getswapinfo(kd, &kswap, 1, 0);
kvm_close(kd);
totalVirtualMem += kswap.ksw_total * pageSize;
return totalVirtualMem;
#else
return 0;
#endif
}
uint64_t GetTotalMemoryUsed()
{
#ifdef SPP_WIN
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
return static_cast<uint64_t>(memInfo.ullTotalPageFile - memInfo.ullAvailPageFile);
#elif defined(__linux__)
struct sysinfo memInfo;
sysinfo(&memInfo);
auto virtualMemUsed = memInfo.totalram - memInfo.freeram;
virtualMemUsed += memInfo.totalswap - memInfo.freeswap;
virtualMemUsed *= memInfo.mem_unit;
return static_cast<uint64_t>(virtualMemUsed);
#elif defined(__FreeBSD__)
kvm_t *kd;
u_int pageSize;
u_int pageCnt, freeCnt;
size_t pageCntLen = sizeof(pageCnt);
size_t freeCntLen = sizeof(freeCnt);
struct kvm_swap kswap;
uint64_t virtualMemUsed;
pageSize = static_cast<u_int>(getpagesize());
sysctlbyname("vm.stats.vm.v_page_count", &pageCnt, &pageCntLen, NULL, 0);
sysctlbyname("vm.stats.vm.v_free_count", &freeCnt, &freeCntLen, NULL, 0);
virtualMemUsed = (pageCnt - freeCnt) * pageSize;
kd = kvm_open(NULL, _PATH_DEVNULL, NULL, O_RDONLY, "kvm_open");
kvm_getswapinfo(kd, &kswap, 1, 0);
kvm_close(kd);
virtualMemUsed += kswap.ksw_used * pageSize;
return virtualMemUsed;
#else
return 0;
#endif
}
uint64_t GetProcessMemoryUsed()
{
#ifdef SPP_WIN
PROCESS_MEMORY_COUNTERS_EX pmc;
GetProcessMemoryInfo(GetCurrentProcess(), reinterpret_cast<PPROCESS_MEMORY_COUNTERS>(&pmc), sizeof(pmc));
return static_cast<uint64_t>(pmc.PrivateUsage);
#elif defined(__linux__)
auto parseLine =
[](char* line)->int
{
auto i = strlen(line);
while(*line < '0' || *line > '9')
{
line++;
}
line[i-3] = '\0';
i = atoi(line);
return i;
};
auto file = fopen("/proc/self/status", "r");
auto result = -1;
char line[128];
while(fgets(line, 128, file) != nullptr)
{
if(strncmp(line, "VmSize:", 7) == 0)
{
result = parseLine(line);
break;
}
}
fclose(file);
return static_cast<uint64_t>(result) * 1024;
#elif defined(__FreeBSD__)
struct kinfo_proc info;
size_t infoLen = sizeof(info);
int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PID, getpid() };
sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &infoLen, NULL, 0);
return static_cast<uint64_t>(info.ki_rssize * getpagesize());
#else
return 0;
#endif
}
uint64_t GetPhysicalMemory()
{
#ifdef SPP_WIN
MEMORYSTATUSEX memInfo;
memInfo.dwLength = sizeof(MEMORYSTATUSEX);
GlobalMemoryStatusEx(&memInfo);
return static_cast<uint64_t>(memInfo.ullTotalPhys);
#elif defined(__linux__)
struct sysinfo memInfo;
sysinfo(&memInfo);
auto totalPhysMem = memInfo.totalram;
totalPhysMem *= memInfo.mem_unit;
return static_cast<uint64_t>(totalPhysMem);
#elif defined(__FreeBSD__)
u_long physMem;
size_t physMemLen = sizeof(physMem);
int mib[] = { CTL_HW, HW_PHYSMEM };
sysctl(mib, sizeof(mib) / sizeof(*mib), &physMem, &physMemLen, NULL, 0);
return physMem;
#else
return 0;
#endif
}
}
#endif // spp_memory_h_guard

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,664 @@
#if !defined(phmap_bits_h_guard_)
#define phmap_bits_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
// with modifications.
//
// Copyright 2018 The Abseil Authors.
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------------------------------------------------------------------
// The following guarantees declaration of the byte swap functions
#ifdef _MSC_VER
#include <stdlib.h> // NOLINT(build/include)
#elif defined(__APPLE__)
// Mac OS X / Darwin features
#include <libkern/OSByteOrder.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__GLIBC__)
#include <byteswap.h> // IWYU pragma: export
#endif
#include <string.h>
#include <cstdint>
#include "phmap_config.h"
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4514) // unreferenced inline function has been removed
#endif
// -----------------------------------------------------------------------------
// unaligned APIs
// -----------------------------------------------------------------------------
// Portable handling of unaligned loads, stores, and copies.
// On some platforms, like ARM, the copy functions can be more efficient
// then a load and a store.
// -----------------------------------------------------------------------------
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) ||\
defined(MEMORY_SANITIZER)
#include <stdint.h>
extern "C" {
uint16_t __sanitizer_unaligned_load16(const void *p);
uint32_t __sanitizer_unaligned_load32(const void *p);
uint64_t __sanitizer_unaligned_load64(const void *p);
void __sanitizer_unaligned_store16(void *p, uint16_t v);
void __sanitizer_unaligned_store32(void *p, uint32_t v);
void __sanitizer_unaligned_store64(void *p, uint64_t v);
} // extern "C"
namespace phmap {
namespace bits {
inline uint16_t UnalignedLoad16(const void *p) {
return __sanitizer_unaligned_load16(p);
}
inline uint32_t UnalignedLoad32(const void *p) {
return __sanitizer_unaligned_load32(p);
}
inline uint64_t UnalignedLoad64(const void *p) {
return __sanitizer_unaligned_load64(p);
}
inline void UnalignedStore16(void *p, uint16_t v) {
__sanitizer_unaligned_store16(p, v);
}
inline void UnalignedStore32(void *p, uint32_t v) {
__sanitizer_unaligned_store32(p, v);
}
inline void UnalignedStore64(void *p, uint64_t v) {
__sanitizer_unaligned_store64(p, v);
}
} // namespace bits
} // namespace phmap
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
#else
namespace phmap {
namespace bits {
inline uint16_t UnalignedLoad16(const void *p) {
uint16_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint32_t UnalignedLoad32(const void *p) {
uint32_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline uint64_t UnalignedLoad64(const void *p) {
uint64_t t;
memcpy(&t, p, sizeof t);
return t;
}
inline void UnalignedStore16(void *p, uint16_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore32(void *p, uint32_t v) { memcpy(p, &v, sizeof v); }
inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
} // namespace bits
} // namespace phmap
#define PHMAP_INTERNAL_UNALIGNED_LOAD16(_p) (phmap::bits::UnalignedLoad16(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD32(_p) (phmap::bits::UnalignedLoad32(_p))
#define PHMAP_INTERNAL_UNALIGNED_LOAD64(_p) (phmap::bits::UnalignedLoad64(_p))
#define PHMAP_INTERNAL_UNALIGNED_STORE16(_p, _val) (phmap::bits::UnalignedStore16(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE32(_p, _val) (phmap::bits::UnalignedStore32(_p, _val))
#define PHMAP_INTERNAL_UNALIGNED_STORE64(_p, _val) (phmap::bits::UnalignedStore64(_p, _val))
#endif
// -----------------------------------------------------------------------------
// File: optimization.h
// -----------------------------------------------------------------------------
#if defined(__pnacl__)
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
#elif defined(__clang__)
// Clang will not tail call given inline volatile assembly.
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(__GNUC__)
// GCC will not tail call given inline volatile assembly.
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __asm__ __volatile__("")
#elif defined(_MSC_VER)
#include <intrin.h>
// The __nop() intrinsic blocks the optimisation.
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() __nop()
#else
#define PHMAP_BLOCK_TAIL_CALL_OPTIMIZATION() if (volatile int x = 0) { (void)x; }
#endif
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
#ifdef PHMAP_HAVE_INTRINSIC_INT128
__extension__ typedef unsigned __int128 phmap_uint128;
inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high)
{
auto result = static_cast<phmap_uint128>(a) * static_cast<phmap_uint128>(b);
*high = static_cast<uint64_t>(result >> 64);
return static_cast<uint64_t>(result);
}
#define PHMAP_HAS_UMUL128 1
#elif (defined(_MSC_VER))
#if defined(_M_X64)
#pragma intrinsic(_umul128)
inline uint64_t umul128(uint64_t a, uint64_t b, uint64_t* high)
{
return _umul128(a, b, high);
}
#define PHMAP_HAS_UMUL128 1
#endif
#endif
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#if defined(__GNUC__)
// Cache line alignment
#if defined(__i386__) || defined(__x86_64__)
#define PHMAP_CACHELINE_SIZE 64
#elif defined(__powerpc64__)
#define PHMAP_CACHELINE_SIZE 128
#elif defined(__aarch64__)
// We would need to read special register ctr_el0 to find out L1 dcache size.
// This value is a good estimate based on a real aarch64 machine.
#define PHMAP_CACHELINE_SIZE 64
#elif defined(__arm__)
// Cache line sizes for ARM: These values are not strictly correct since
// cache line sizes depend on implementations, not architectures. There
// are even implementations with cache line sizes configurable at boot
// time.
#if defined(__ARM_ARCH_5T__)
#define PHMAP_CACHELINE_SIZE 32
#elif defined(__ARM_ARCH_7A__)
#define PHMAP_CACHELINE_SIZE 64
#endif
#endif
#ifndef PHMAP_CACHELINE_SIZE
// A reasonable default guess. Note that overestimates tend to waste more
// space, while underestimates tend to waste more time.
#define PHMAP_CACHELINE_SIZE 64
#endif
#define PHMAP_CACHELINE_ALIGNED __attribute__((aligned(PHMAP_CACHELINE_SIZE)))
#elif defined(_MSC_VER)
#define PHMAP_CACHELINE_SIZE 64
#define PHMAP_CACHELINE_ALIGNED __declspec(align(PHMAP_CACHELINE_SIZE))
#else
#define PHMAP_CACHELINE_SIZE 64
#define PHMAP_CACHELINE_ALIGNED
#endif
#if PHMAP_HAVE_BUILTIN(__builtin_expect) || \
(defined(__GNUC__) && !defined(__clang__))
#define PHMAP_PREDICT_FALSE(x) (__builtin_expect(x, 0))
#define PHMAP_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1))
#else
#define PHMAP_PREDICT_FALSE(x) (x)
#define PHMAP_PREDICT_TRUE(x) (x)
#endif
// -----------------------------------------------------------------------------
// File: bits.h
// -----------------------------------------------------------------------------
#if defined(_MSC_VER)
// We can achieve something similar to attribute((always_inline)) with MSVC by
// using the __forceinline keyword, however this is not perfect. MSVC is
// much less aggressive about inlining, and even with the __forceinline keyword.
#define PHMAP_BASE_INTERNAL_FORCEINLINE __forceinline
#else
// Use default attribute inline.
#define PHMAP_BASE_INTERNAL_FORCEINLINE inline PHMAP_ATTRIBUTE_ALWAYS_INLINE
#endif
namespace phmap {
namespace base_internal {
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64Slow(uint64_t n) {
int zeroes = 60;
if (n >> 32) zeroes -= 32, n >>= 32;
if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4;
return (uint32_t)("\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes);
}
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64)
// MSVC does not have __buitin_clzll. Use _BitScanReverse64.
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse64(&result, n)) {
return (uint32_t)(63 - result);
}
return 64;
#elif defined(_MSC_VER) && !defined(__clang__)
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
unsigned long result = 0; // NOLINT(runtime/int)
if ((n >> 32) && _BitScanReverse(&result, (unsigned long)(n >> 32))) {
return (uint32_t)(31 - result);
}
if (_BitScanReverse(&result, (unsigned long)n)) {
return (uint32_t)(63 - result);
}
return 64;
#elif defined(__GNUC__) || defined(__clang__)
// Use __builtin_clzll, which uses the following instructions:
// x86: bsr
// ARM64: clz
// PPC: cntlzd
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
"__builtin_clzll does not take 64-bit arg");
// Handle 0 as a special case because __builtin_clzll(0) is undefined.
if (n == 0) {
return 64;
}
return (uint32_t)__builtin_clzll(n);
#else
return CountLeadingZeros64Slow(n);
#endif
}
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros32Slow(uint64_t n) {
uint32_t zeroes = 28;
if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4;
return "\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes;
}
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros32(uint32_t n) {
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse(&result, n)) {
return (uint32_t)(31 - result);
}
return 32;
#elif defined(__GNUC__) || defined(__clang__)
// Use __builtin_clz, which uses the following instructions:
// x86: bsr
// ARM64: clz
// PPC: cntlzd
static_assert(sizeof(int) == sizeof(n),
"__builtin_clz does not take 32-bit arg");
// Handle 0 as a special case because __builtin_clz(0) is undefined.
if (n == 0) {
return 32;
}
return __builtin_clz(n);
#else
return CountLeadingZeros32Slow(n);
#endif
}
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero64Slow(uint64_t n) {
uint32_t c = 63;
n &= ~n + 1;
if (n & 0x00000000FFFFFFFF) c -= 32;
if (n & 0x0000FFFF0000FFFF) c -= 16;
if (n & 0x00FF00FF00FF00FF) c -= 8;
if (n & 0x0F0F0F0F0F0F0F0F) c -= 4;
if (n & 0x3333333333333333) c -= 2;
if (n & 0x5555555555555555) c -= 1;
return c;
}
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero64(uint64_t n) {
#if defined(_MSC_VER) && !defined(__clang__) && defined(_M_X64)
unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward64(&result, n);
return (uint32_t)result;
#elif defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int)
if (static_cast<uint32_t>(n) == 0) {
_BitScanForward(&result, (unsigned long)(n >> 32));
return result + 32;
}
_BitScanForward(&result, (unsigned long)n);
return result;
#elif defined(__GNUC__) || defined(__clang__)
static_assert(sizeof(unsigned long long) == sizeof(n), // NOLINT(runtime/int)
"__builtin_ctzll does not take 64-bit arg");
return __builtin_ctzll(n);
#else
return CountTrailingZerosNonZero64Slow(n);
#endif
}
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero32Slow(uint32_t n) {
uint32_t c = 31;
n &= ~n + 1;
if (n & 0x0000FFFF) c -= 16;
if (n & 0x00FF00FF) c -= 8;
if (n & 0x0F0F0F0F) c -= 4;
if (n & 0x33333333) c -= 2;
if (n & 0x55555555) c -= 1;
return c;
}
PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountTrailingZerosNonZero32(uint32_t n) {
#if defined(_MSC_VER) && !defined(__clang__)
unsigned long result = 0; // NOLINT(runtime/int)
_BitScanForward(&result, n);
return (uint32_t)result;
#elif defined(__GNUC__) || defined(__clang__)
static_assert(sizeof(int) == sizeof(n),
"__builtin_ctz does not take 32-bit arg");
return __builtin_ctz(n);
#else
return CountTrailingZerosNonZero32Slow(n);
#endif
}
#undef PHMAP_BASE_INTERNAL_FORCEINLINE
} // namespace base_internal
} // namespace phmap
// -----------------------------------------------------------------------------
// File: endian.h
// -----------------------------------------------------------------------------
namespace phmap {
// Use compiler byte-swapping intrinsics if they are available. 32-bit
// and 64-bit versions are available in Clang and GCC as of GCC 4.3.0.
// The 16-bit version is available in Clang and GCC only as of GCC 4.8.0.
// For simplicity, we enable them all only for GCC 4.8.0 or later.
#if defined(__clang__) || \
(defined(__GNUC__) && \
((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ >= 5))
inline uint64_t gbswap_64(uint64_t host_int) {
return __builtin_bswap64(host_int);
}
inline uint32_t gbswap_32(uint32_t host_int) {
return __builtin_bswap32(host_int);
}
inline uint16_t gbswap_16(uint16_t host_int) {
return __builtin_bswap16(host_int);
}
#elif defined(_MSC_VER)
inline uint64_t gbswap_64(uint64_t host_int) {
return _byteswap_uint64(host_int);
}
inline uint32_t gbswap_32(uint32_t host_int) {
return _byteswap_ulong(host_int);
}
inline uint16_t gbswap_16(uint16_t host_int) {
return _byteswap_ushort(host_int);
}
#elif defined(__APPLE__)
inline uint64_t gbswap_64(uint64_t host_int) { return OSSwapInt16(host_int); }
inline uint32_t gbswap_32(uint32_t host_int) { return OSSwapInt32(host_int); }
inline uint16_t gbswap_16(uint16_t host_int) { return OSSwapInt64(host_int); }
#else
inline uint64_t gbswap_64(uint64_t host_int) {
#if defined(__GNUC__) && defined(__x86_64__) && !defined(__APPLE__)
// Adapted from /usr/include/byteswap.h. Not available on Mac.
if (__builtin_constant_p(host_int)) {
return __bswap_constant_64(host_int);
} else {
uint64_t result;
__asm__("bswap %0" : "=r"(result) : "0"(host_int));
return result;
}
#elif defined(__GLIBC__)
return bswap_64(host_int);
#else
return (((host_int & uint64_t{0xFF}) << 56) |
((host_int & uint64_t{0xFF00}) << 40) |
((host_int & uint64_t{0xFF0000}) << 24) |
((host_int & uint64_t{0xFF000000}) << 8) |
((host_int & uint64_t{0xFF00000000}) >> 8) |
((host_int & uint64_t{0xFF0000000000}) >> 24) |
((host_int & uint64_t{0xFF000000000000}) >> 40) |
((host_int & uint64_t{0xFF00000000000000}) >> 56));
#endif // bswap_64
}
inline uint32_t gbswap_32(uint32_t host_int) {
#if defined(__GLIBC__)
return bswap_32(host_int);
#else
return (((host_int & uint32_t{0xFF}) << 24) |
((host_int & uint32_t{0xFF00}) << 8) |
((host_int & uint32_t{0xFF0000}) >> 8) |
((host_int & uint32_t{0xFF000000}) >> 24));
#endif
}
inline uint16_t gbswap_16(uint16_t host_int) {
#if defined(__GLIBC__)
return bswap_16(host_int);
#else
return (((host_int & uint16_t{0xFF}) << 8) |
((host_int & uint16_t{0xFF00}) >> 8));
#endif
}
#endif // intrinics available
#ifdef PHMAP_IS_LITTLE_ENDIAN
// Definitions for ntohl etc. that don't require us to include
// netinet/in.h. We wrap gbswap_32 and gbswap_16 in functions rather
// than just #defining them because in debug mode, gcc doesn't
// correctly handle the (rather involved) definitions of bswap_32.
// gcc guarantees that inline functions are as fast as macros, so
// this isn't a performance hit.
inline uint16_t ghtons(uint16_t x) { return gbswap_16(x); }
inline uint32_t ghtonl(uint32_t x) { return gbswap_32(x); }
inline uint64_t ghtonll(uint64_t x) { return gbswap_64(x); }
#elif defined PHMAP_IS_BIG_ENDIAN
// These definitions are simpler on big-endian machines
// These are functions instead of macros to avoid self-assignment warnings
// on calls such as "i = ghtnol(i);". This also provides type checking.
inline uint16_t ghtons(uint16_t x) { return x; }
inline uint32_t ghtonl(uint32_t x) { return x; }
inline uint64_t ghtonll(uint64_t x) { return x; }
#else
#error \
"Unsupported byte order: Either PHMAP_IS_BIG_ENDIAN or " \
"PHMAP_IS_LITTLE_ENDIAN must be defined"
#endif // byte order
inline uint16_t gntohs(uint16_t x) { return ghtons(x); }
inline uint32_t gntohl(uint32_t x) { return ghtonl(x); }
inline uint64_t gntohll(uint64_t x) { return ghtonll(x); }
// Utilities to convert numbers between the current hosts's native byte
// order and little-endian byte order
//
// Load/Store methods are alignment safe
namespace little_endian {
// Conversion functions.
#ifdef PHMAP_IS_LITTLE_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return x; }
inline uint16_t ToHost16(uint16_t x) { return x; }
inline uint32_t FromHost32(uint32_t x) { return x; }
inline uint32_t ToHost32(uint32_t x) { return x; }
inline uint64_t FromHost64(uint64_t x) { return x; }
inline uint64_t ToHost64(uint64_t x) { return x; }
inline constexpr bool IsLittleEndian() { return true; }
#elif defined PHMAP_IS_BIG_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */
// Functions to do unaligned loads and stores in little-endian order.
// ------------------------------------------------------------------
inline uint16_t Load16(const void *p) {
return ToHost16(PHMAP_INTERNAL_UNALIGNED_LOAD16(p));
}
inline void Store16(void *p, uint16_t v) {
PHMAP_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
inline uint32_t Load32(const void *p) {
return ToHost32(PHMAP_INTERNAL_UNALIGNED_LOAD32(p));
}
inline void Store32(void *p, uint32_t v) {
PHMAP_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
inline uint64_t Load64(const void *p) {
return ToHost64(PHMAP_INTERNAL_UNALIGNED_LOAD64(p));
}
inline void Store64(void *p, uint64_t v) {
PHMAP_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
} // namespace little_endian
// Utilities to convert numbers between the current hosts's native byte
// order and big-endian byte order (same as network byte order)
//
// Load/Store methods are alignment safe
namespace big_endian {
#ifdef PHMAP_IS_LITTLE_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return gbswap_16(x); }
inline uint16_t ToHost16(uint16_t x) { return gbswap_16(x); }
inline uint32_t FromHost32(uint32_t x) { return gbswap_32(x); }
inline uint32_t ToHost32(uint32_t x) { return gbswap_32(x); }
inline uint64_t FromHost64(uint64_t x) { return gbswap_64(x); }
inline uint64_t ToHost64(uint64_t x) { return gbswap_64(x); }
inline constexpr bool IsLittleEndian() { return true; }
#elif defined PHMAP_IS_BIG_ENDIAN
inline uint16_t FromHost16(uint16_t x) { return x; }
inline uint16_t ToHost16(uint16_t x) { return x; }
inline uint32_t FromHost32(uint32_t x) { return x; }
inline uint32_t ToHost32(uint32_t x) { return x; }
inline uint64_t FromHost64(uint64_t x) { return x; }
inline uint64_t ToHost64(uint64_t x) { return x; }
inline constexpr bool IsLittleEndian() { return false; }
#endif /* ENDIAN */
// Functions to do unaligned loads and stores in big-endian order.
inline uint16_t Load16(const void *p) {
return ToHost16(PHMAP_INTERNAL_UNALIGNED_LOAD16(p));
}
inline void Store16(void *p, uint16_t v) {
PHMAP_INTERNAL_UNALIGNED_STORE16(p, FromHost16(v));
}
inline uint32_t Load32(const void *p) {
return ToHost32(PHMAP_INTERNAL_UNALIGNED_LOAD32(p));
}
inline void Store32(void *p, uint32_t v) {
PHMAP_INTERNAL_UNALIGNED_STORE32(p, FromHost32(v));
}
inline uint64_t Load64(const void *p) {
return ToHost64(PHMAP_INTERNAL_UNALIGNED_LOAD64(p));
}
inline void Store64(void *p, uint64_t v) {
PHMAP_INTERNAL_UNALIGNED_STORE64(p, FromHost64(v));
}
} // namespace big_endian
} // namespace phmap
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // phmap_bits_h_guard_

View file

@ -0,0 +1,767 @@
#if !defined(phmap_config_h_guard_)
#define phmap_config_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// Includes work from abseil-cpp (https://github.com/abseil/abseil-cpp)
// with modifications.
//
// Copyright 2018 The Abseil Authors.
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------------------------------------------------------------------
#define PHMAP_VERSION_MAJOR 1
#define PHMAP_VERSION_MINOR 3
#define PHMAP_VERSION_PATCH 12
// Included for the __GLIBC__ macro (or similar macros on other systems).
#include <limits.h>
#ifdef __cplusplus
// Included for __GLIBCXX__, _LIBCPP_VERSION
#include <cstddef>
#endif // __cplusplus
#if defined(__APPLE__)
// Included for TARGET_OS_IPHONE, __IPHONE_OS_VERSION_MIN_REQUIRED,
// __IPHONE_8_0.
#include <Availability.h>
#include <TargetConditionals.h>
#endif
#define PHMAP_XSTR(x) PHMAP_STR(x)
#define PHMAP_STR(x) #x
#define PHMAP_VAR_NAME_VALUE(var) #var "=" PHMAP_STR(var)
// -----------------------------------------------------------------------------
// Some sanity checks
// -----------------------------------------------------------------------------
//#if defined(__CYGWIN__)
// #error "Cygwin is not supported."
//#endif
#if defined(_MSC_FULL_VER) && _MSC_FULL_VER < 190023918 && !defined(__clang__)
#error "phmap requires Visual Studio 2015 Update 2 or higher."
#endif
// We support gcc 4.7 and later.
#if defined(__GNUC__) && !defined(__clang__)
#if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
#error "phmap requires gcc 4.7 or higher."
#endif
#endif
// We support Apple Xcode clang 4.2.1 (version 421.11.65) and later.
// This corresponds to Apple Xcode version 4.5.
#if defined(__apple_build_version__) && __apple_build_version__ < 4211165
#error "phmap requires __apple_build_version__ of 4211165 or higher."
#endif
// Enforce C++11 as the minimum.
#if defined(__cplusplus) && !defined(_MSC_VER)
#if __cplusplus < 201103L
#error "C++ versions less than C++11 are not supported."
#endif
#endif
// We have chosen glibc 2.12 as the minimum
#if defined(__GLIBC__) && defined(__GLIBC_PREREQ)
#if !__GLIBC_PREREQ(2, 12)
#error "Minimum required version of glibc is 2.12."
#endif
#endif
#if defined(_STLPORT_VERSION)
#error "STLPort is not supported."
#endif
#if CHAR_BIT != 8
#warning "phmap assumes CHAR_BIT == 8."
#endif
// phmap currently assumes that an int is 4 bytes.
#if INT_MAX < 2147483647
#error "phmap assumes that int is at least 4 bytes. "
#endif
// -----------------------------------------------------------------------------
// Compiler Feature Checks
// -----------------------------------------------------------------------------
#ifdef __has_builtin
#define PHMAP_HAVE_BUILTIN(x) __has_builtin(x)
#else
#define PHMAP_HAVE_BUILTIN(x) 0
#endif
#if (!defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5) && \
((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
#define PHMAP_HAVE_CC17 1
#else
#define PHMAP_HAVE_CC17 0
#endif
#define PHMAP_BRANCHLESS 1
#ifdef __has_feature
#define PHMAP_HAVE_FEATURE(f) __has_feature(f)
#else
#define PHMAP_HAVE_FEATURE(f) 0
#endif
// Portable check for GCC minimum version:
// https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html
#if defined(__GNUC__) && defined(__GNUC_MINOR__)
#define PHMAP_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) (__GNUC__ > (x) || __GNUC__ == (x) && __GNUC_MINOR__ >= (y))
#else
#define PHMAP_INTERNAL_HAVE_MIN_GNUC_VERSION(x, y) 0
#endif
#if defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__)
#define PHMAP_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) (__clang_major__ > (x) || __clang_major__ == (x) && __clang_minor__ >= (y))
#else
#define PHMAP_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0
#endif
// -------------------------------------------------------------------
// Checks whether C++11's `thread_local` storage duration specifier is
// supported.
// -------------------------------------------------------------------
#ifdef PHMAP_HAVE_THREAD_LOCAL
#error PHMAP_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__) && defined(__clang__)
#if __has_feature(cxx_thread_local) && \
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define PHMAP_HAVE_THREAD_LOCAL 1
#endif
#else // !defined(__APPLE__)
#define PHMAP_HAVE_THREAD_LOCAL 1
#endif
#if defined(__ANDROID__) && defined(__clang__)
#if __has_include(<android/ndk-version.h>)
#include <android/ndk-version.h>
#endif // __has_include(<android/ndk-version.h>)
#if defined(__ANDROID__) && defined(__clang__) && defined(__NDK_MAJOR__) && \
defined(__NDK_MINOR__) && \
((__NDK_MAJOR__ < 12) || ((__NDK_MAJOR__ == 12) && (__NDK_MINOR__ < 1)))
#undef PHMAP_HAVE_TLS
#undef PHMAP_HAVE_THREAD_LOCAL
#endif
#endif
// ------------------------------------------------------------
// Checks whether the __int128 compiler extension for a 128-bit
// integral type is supported.
// ------------------------------------------------------------
#ifdef PHMAP_HAVE_INTRINSIC_INT128
#error PHMAP_HAVE_INTRINSIC_INT128 cannot be directly set
#elif defined(__SIZEOF_INT128__)
#if (defined(__clang__) && !defined(_WIN32) && !defined(__aarch64__)) || \
(defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
#define PHMAP_HAVE_INTRINSIC_INT128 1
#elif defined(__CUDACC__)
#if __CUDACC_VER__ >= 70000
#define PHMAP_HAVE_INTRINSIC_INT128 1
#endif // __CUDACC_VER__ >= 70000
#endif // defined(__CUDACC__)
#endif
// ------------------------------------------------------------------
// Checks whether the compiler both supports and enables exceptions.
// ------------------------------------------------------------------
#ifdef PHMAP_HAVE_EXCEPTIONS
#error PHMAP_HAVE_EXCEPTIONS cannot be directly set.
#elif defined(__clang__)
#if defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
#define PHMAP_HAVE_EXCEPTIONS 1
#endif // defined(__EXCEPTIONS) && __has_feature(cxx_exceptions)
#elif !(defined(__GNUC__) && (__GNUC__ < 5) && !defined(__EXCEPTIONS)) && \
!(defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__cpp_exceptions)) && \
!(defined(_MSC_VER) && !defined(_CPPUNWIND))
#define PHMAP_HAVE_EXCEPTIONS 1
#endif
// -----------------------------------------------------------------------
// Checks whether the platform has an mmap(2) implementation as defined in
// POSIX.1-2001.
// -----------------------------------------------------------------------
#ifdef PHMAP_HAVE_MMAP
#error PHMAP_HAVE_MMAP cannot be directly set
#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD__) || \
defined(__ros__) || defined(__native_client__) || defined(__asmjs__) || \
defined(__wasm__) || defined(__Fuchsia__) || defined(__sun) || \
defined(__ASYLO__)
#define PHMAP_HAVE_MMAP 1
#endif
// -----------------------------------------------------------------------
// Checks the endianness of the platform.
// -----------------------------------------------------------------------
#if defined(PHMAP_IS_BIG_ENDIAN)
#error "PHMAP_IS_BIG_ENDIAN cannot be directly set."
#endif
#if defined(PHMAP_IS_LITTLE_ENDIAN)
#error "PHMAP_IS_LITTLE_ENDIAN cannot be directly set."
#endif
#if (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
#define PHMAP_IS_LITTLE_ENDIAN 1
#elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \
__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define PHMAP_IS_BIG_ENDIAN 1
#elif defined(_WIN32)
#define PHMAP_IS_LITTLE_ENDIAN 1
#else
#error "phmap endian detection needs to be set up for your compiler"
#endif
#if defined(__APPLE__) && defined(_LIBCPP_VERSION) && \
defined(__MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 101400
#define PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 1
#else
#define PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE 0
#endif
// ---------------------------------------------------------------------------
// Checks whether C++17 std::any is available by checking whether <any> exists.
// ---------------------------------------------------------------------------
#ifdef PHMAP_HAVE_STD_ANY
#error "PHMAP_HAVE_STD_ANY cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<any>) && __cplusplus >= 201703L && \
!PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define PHMAP_HAVE_STD_ANY 1
#endif
#endif
#ifdef PHMAP_HAVE_STD_OPTIONAL
#error "PHMAP_HAVE_STD_OPTIONAL cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<optional>) && __cplusplus >= 201703L && \
!PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define PHMAP_HAVE_STD_OPTIONAL 1
#endif
#endif
#ifdef PHMAP_HAVE_STD_VARIANT
#error "PHMAP_HAVE_STD_VARIANT cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<variant>) && __cplusplus >= 201703L && \
!PHMAP_INTERNAL_MACOS_CXX17_TYPES_UNAVAILABLE
#define PHMAP_HAVE_STD_VARIANT 1
#endif
#endif
#ifdef PHMAP_HAVE_STD_STRING_VIEW
#error "PHMAP_HAVE_STD_STRING_VIEW cannot be directly set."
#endif
#ifdef __has_include
#if __has_include(<string_view>) && __cplusplus >= 201703L && \
(!defined(_MSC_VER) || _MSC_VER >= 1920) // vs2019
#define PHMAP_HAVE_STD_STRING_VIEW 1
#endif
#endif
// #pragma message(PHMAP_VAR_NAME_VALUE(_MSVC_LANG))
#if defined(_MSC_VER) && _MSC_VER >= 1910 && PHMAP_HAVE_CC17
// #define PHMAP_HAVE_STD_ANY 1
#define PHMAP_HAVE_STD_OPTIONAL 1
#define PHMAP_HAVE_STD_VARIANT 1
#if !defined(PHMAP_HAVE_STD_STRING_VIEW) && _MSC_VER >= 1920
#define PHMAP_HAVE_STD_STRING_VIEW 1
#endif
#endif
#if PHMAP_HAVE_CC17
#ifdef __has_include
#if __has_include(<shared_mutex>)
#define PHMAP_HAVE_SHARED_MUTEX 1
#endif
#endif
#endif
#ifndef PHMAP_HAVE_STD_STRING_VIEW
#define PHMAP_HAVE_STD_STRING_VIEW 0
#endif
// In debug mode, MSVC 2017's std::variant throws a EXCEPTION_ACCESS_VIOLATION
// SEH exception from emplace for variant<SomeStruct> when constructing the
// struct can throw. This defeats some of variant_test and
// variant_exception_safety_test.
#if defined(_MSC_VER) && _MSC_VER >= 1700 && defined(_DEBUG)
#define PHMAP_INTERNAL_MSVC_2017_DBG_MODE
#endif
// ---------------------------------------------------------------------------
// Checks whether wchar_t is treated as a native type
// (MSVC: /Zc:wchar_t- treats wchar_t as unsigned short)
// ---------------------------------------------------------------------------
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
#define PHMAP_HAS_NATIVE_WCHAR_T
#endif
// -----------------------------------------------------------------------------
// Sanitizer Attributes
// -----------------------------------------------------------------------------
//
// Sanitizer-related attributes are not "defined" in this file (and indeed
// are not defined as such in any file). To utilize the following
// sanitizer-related attributes within your builds, define the following macros
// within your build using a `-D` flag, along with the given value for
// `-fsanitize`:
//
// * `ADDRESS_SANITIZER` + `-fsanitize=address` (Clang, GCC 4.8)
// * `MEMORY_SANITIZER` + `-fsanitize=memory` (Clang-only)
// * `THREAD_SANITIZER + `-fsanitize=thread` (Clang, GCC 4.8+)
// * `UNDEFINED_BEHAVIOR_SANITIZER` + `-fsanitize=undefined` (Clang, GCC 4.9+)
// * `CONTROL_FLOW_INTEGRITY` + -fsanitize=cfi (Clang-only)
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------
// A function-like feature checking macro that is a wrapper around
// `__has_attribute`, which is defined by GCC 5+ and Clang and evaluates to a
// nonzero constant integer if the attribute is supported or 0 if not.
//
// It evaluates to zero if `__has_attribute` is not defined by the compiler.
// -----------------------------------------------------------------------------
#ifdef __has_attribute
#define PHMAP_HAVE_ATTRIBUTE(x) __has_attribute(x)
#else
#define PHMAP_HAVE_ATTRIBUTE(x) 0
#endif
// -----------------------------------------------------------------------------
// A function-like feature checking macro that accepts C++11 style attributes.
// It's a wrapper around `__has_cpp_attribute`, defined by ISO C++ SD-6
// (https://en.cppreference.com/w/cpp/experimental/feature_test). If we don't
// find `__has_cpp_attribute`, will evaluate to 0.
// -----------------------------------------------------------------------------
#if defined(__cplusplus) && defined(__has_cpp_attribute)
#define PHMAP_HAVE_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
#define PHMAP_HAVE_CPP_ATTRIBUTE(x) 0
#endif
// -----------------------------------------------------------------------------
// Function Attributes
// -----------------------------------------------------------------------------
#if PHMAP_HAVE_ATTRIBUTE(format) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_PRINTF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__printf__, string_index, first_to_check)))
#define PHMAP_SCANF_ATTRIBUTE(string_index, first_to_check) \
__attribute__((__format__(__scanf__, string_index, first_to_check)))
#else
#define PHMAP_PRINTF_ATTRIBUTE(string_index, first_to_check)
#define PHMAP_SCANF_ATTRIBUTE(string_index, first_to_check)
#endif
#if PHMAP_HAVE_ATTRIBUTE(always_inline) || \
(defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_ALWAYS_INLINE __attribute__((always_inline))
#define PHMAP_HAVE_ATTRIBUTE_ALWAYS_INLINE 1
#else
#define PHMAP_ATTRIBUTE_ALWAYS_INLINE
#endif
#if !defined(__INTEL_COMPILER) && (PHMAP_HAVE_ATTRIBUTE(noinline) || (defined(__GNUC__) && !defined(__clang__)))
#define PHMAP_ATTRIBUTE_NOINLINE __attribute__((noinline))
#define PHMAP_HAVE_ATTRIBUTE_NOINLINE 1
#else
#define PHMAP_ATTRIBUTE_NOINLINE
#endif
#if PHMAP_HAVE_ATTRIBUTE(disable_tail_calls)
#define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define PHMAP_ATTRIBUTE_NO_TAIL_CALL __attribute__((disable_tail_calls))
#elif defined(__GNUC__) && !defined(__clang__)
#define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 1
#define PHMAP_ATTRIBUTE_NO_TAIL_CALL \
__attribute__((optimize("no-optimize-sibling-calls")))
#else
#define PHMAP_ATTRIBUTE_NO_TAIL_CALL
#define PHMAP_HAVE_ATTRIBUTE_NO_TAIL_CALL 0
#endif
#if (PHMAP_HAVE_ATTRIBUTE(weak) || \
(defined(__GNUC__) && !defined(__clang__))) && \
!(defined(__llvm__) && defined(_WIN32))
#undef PHMAP_ATTRIBUTE_WEAK
#define PHMAP_ATTRIBUTE_WEAK __attribute__((weak))
#define PHMAP_HAVE_ATTRIBUTE_WEAK 1
#else
#define PHMAP_ATTRIBUTE_WEAK
#define PHMAP_HAVE_ATTRIBUTE_WEAK 0
#endif
#if PHMAP_HAVE_ATTRIBUTE(nonnull) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_NONNULL(arg_index) __attribute__((nonnull(arg_index)))
#else
#define PHMAP_ATTRIBUTE_NONNULL(...)
#endif
#if PHMAP_HAVE_ATTRIBUTE(noreturn) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_NORETURN __attribute__((noreturn))
#elif defined(_MSC_VER)
#define PHMAP_ATTRIBUTE_NORETURN __declspec(noreturn)
#else
#define PHMAP_ATTRIBUTE_NORETURN
#endif
#if defined(__GNUC__) && defined(ADDRESS_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_ADDRESS
#endif
#if defined(__GNUC__) && defined(MEMORY_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_MEMORY __attribute__((no_sanitize_memory))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_MEMORY
#endif
#if defined(__GNUC__) && defined(THREAD_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_THREAD __attribute__((no_sanitize_thread))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_THREAD
#endif
#if defined(__GNUC__) && \
(defined(UNDEFINED_BEHAVIOR_SANITIZER) || defined(ADDRESS_SANITIZER))
#define PHMAP_ATTRIBUTE_NO_SANITIZE_UNDEFINED \
__attribute__((no_sanitize("undefined")))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_UNDEFINED
#endif
#if defined(__GNUC__) && defined(CONTROL_FLOW_INTEGRITY)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_CFI __attribute__((no_sanitize("cfi")))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_CFI
#endif
#if defined(__GNUC__) && defined(SAFESTACK_SANITIZER)
#define PHMAP_ATTRIBUTE_NO_SANITIZE_SAFESTACK \
__attribute__((no_sanitize("safe-stack")))
#else
#define PHMAP_ATTRIBUTE_NO_SANITIZE_SAFESTACK
#endif
#if PHMAP_HAVE_ATTRIBUTE(returns_nonnull) || \
(defined(__GNUC__) && \
(__GNUC__ > 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) && \
!defined(__clang__))
#define PHMAP_ATTRIBUTE_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#define PHMAP_ATTRIBUTE_RETURNS_NONNULL
#endif
#ifdef PHMAP_HAVE_ATTRIBUTE_SECTION
#error PHMAP_HAVE_ATTRIBUTE_SECTION cannot be directly set
#elif (PHMAP_HAVE_ATTRIBUTE(section) || \
(defined(__GNUC__) && !defined(__clang__))) && \
!defined(__APPLE__) && PHMAP_HAVE_ATTRIBUTE_WEAK
#define PHMAP_HAVE_ATTRIBUTE_SECTION 1
#ifndef PHMAP_ATTRIBUTE_SECTION
#define PHMAP_ATTRIBUTE_SECTION(name) \
__attribute__((section(#name))) __attribute__((noinline))
#endif
#ifndef PHMAP_ATTRIBUTE_SECTION_VARIABLE
#define PHMAP_ATTRIBUTE_SECTION_VARIABLE(name) __attribute__((section(#name)))
#endif
#ifndef PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS
#define PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS(name) \
extern char __start_##name[] PHMAP_ATTRIBUTE_WEAK; \
extern char __stop_##name[] PHMAP_ATTRIBUTE_WEAK
#endif
#ifndef PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS
#define PHMAP_INIT_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#endif
#define PHMAP_ATTRIBUTE_SECTION_START(name) \
(reinterpret_cast<void *>(__start_##name))
#define PHMAP_ATTRIBUTE_SECTION_STOP(name) \
(reinterpret_cast<void *>(__stop_##name))
#else // !PHMAP_HAVE_ATTRIBUTE_SECTION
#define PHMAP_HAVE_ATTRIBUTE_SECTION 0
#define PHMAP_ATTRIBUTE_SECTION(name)
#define PHMAP_ATTRIBUTE_SECTION_VARIABLE(name)
#define PHMAP_INIT_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_DEFINE_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_DECLARE_ATTRIBUTE_SECTION_VARS(name)
#define PHMAP_ATTRIBUTE_SECTION_START(name) (reinterpret_cast<void *>(0))
#define PHMAP_ATTRIBUTE_SECTION_STOP(name) (reinterpret_cast<void *>(0))
#endif // PHMAP_ATTRIBUTE_SECTION
#if PHMAP_HAVE_ATTRIBUTE(force_align_arg_pointer) || \
(defined(__GNUC__) && !defined(__clang__))
#if defined(__i386__)
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC \
__attribute__((force_align_arg_pointer))
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#elif defined(__x86_64__)
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (1)
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#else // !__i386__ && !__x86_64
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#endif // __i386__
#else
#define PHMAP_ATTRIBUTE_STACK_ALIGN_FOR_OLD_LIBC
#define PHMAP_REQUIRE_STACK_ALIGN_TRAMPOLINE (0)
#endif
#if PHMAP_HAVE_ATTRIBUTE(nodiscard)
#define PHMAP_MUST_USE_RESULT [[nodiscard]]
#elif defined(__clang__) && PHMAP_HAVE_ATTRIBUTE(warn_unused_result)
#define PHMAP_MUST_USE_RESULT __attribute__((warn_unused_result))
#else
#define PHMAP_MUST_USE_RESULT
#endif
#if PHMAP_HAVE_ATTRIBUTE(hot) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_HOT __attribute__((hot))
#else
#define PHMAP_ATTRIBUTE_HOT
#endif
#if PHMAP_HAVE_ATTRIBUTE(cold) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_COLD __attribute__((cold))
#else
#define PHMAP_ATTRIBUTE_COLD
#endif
#if defined(__clang__)
#if PHMAP_HAVE_CPP_ATTRIBUTE(clang::reinitializes)
#define PHMAP_ATTRIBUTE_REINITIALIZES [[clang::reinitializes]]
#else
#define PHMAP_ATTRIBUTE_REINITIALIZES
#endif
#else
#define PHMAP_ATTRIBUTE_REINITIALIZES
#endif
#if PHMAP_HAVE_ATTRIBUTE(unused) || (defined(__GNUC__) && !defined(__clang__))
#undef PHMAP_ATTRIBUTE_UNUSED
#define PHMAP_ATTRIBUTE_UNUSED __attribute__((__unused__))
#else
#define PHMAP_ATTRIBUTE_UNUSED
#endif
#if PHMAP_HAVE_ATTRIBUTE(tls_model) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_INITIAL_EXEC __attribute__((tls_model("initial-exec")))
#else
#define PHMAP_ATTRIBUTE_INITIAL_EXEC
#endif
#if PHMAP_HAVE_ATTRIBUTE(packed) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_PACKED __attribute__((__packed__))
#else
#define PHMAP_ATTRIBUTE_PACKED
#endif
#if PHMAP_HAVE_ATTRIBUTE(aligned) || (defined(__GNUC__) && !defined(__clang__))
#define PHMAP_ATTRIBUTE_FUNC_ALIGN(bytes) __attribute__((aligned(bytes)))
#else
#define PHMAP_ATTRIBUTE_FUNC_ALIGN(bytes)
#endif
// ----------------------------------------------------------------------
// Figure out SSE support
// ----------------------------------------------------------------------
#ifndef PHMAP_HAVE_SSE2
#if defined(__SSE2__) || \
(defined(_MSC_VER) && \
(defined(_M_X64) || (defined(_M_IX86) && _M_IX86_FP >= 2)))
#define PHMAP_HAVE_SSE2 1
#else
#define PHMAP_HAVE_SSE2 0
#endif
#endif
#ifndef PHMAP_HAVE_SSSE3
#if defined(__SSSE3__) || defined(__AVX2__)
#define PHMAP_HAVE_SSSE3 1
#else
#define PHMAP_HAVE_SSSE3 0
#endif
#endif
#if PHMAP_HAVE_SSSE3 && !PHMAP_HAVE_SSE2
#error "Bad configuration!"
#endif
#if PHMAP_HAVE_SSE2
#include <emmintrin.h>
#endif
#if PHMAP_HAVE_SSSE3
#include <tmmintrin.h>
#endif
// ----------------------------------------------------------------------
// constexpr if
// ----------------------------------------------------------------------
#if PHMAP_HAVE_CC17
#define PHMAP_IF_CONSTEXPR(expr) if constexpr ((expr))
#else
#define PHMAP_IF_CONSTEXPR(expr) if ((expr))
#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(::phmap::macros_internal::ArraySizeHelper(array)))
namespace phmap {
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 phmap
// 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_

View file

@ -0,0 +1,312 @@
#if !defined(phmap_dump_h_guard_)
#define phmap_dump_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// providing dump/load/mmap_load
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------------------------------------------------------------------
#include <iostream>
#include <fstream>
#include <sstream>
#include "phmap.h"
namespace phmap
{
namespace type_traits_internal {
#if defined(__GLIBCXX__) && __GLIBCXX__ < 20150801
template<typename T> struct IsTriviallyCopyable : public std::integral_constant<bool, __has_trivial_copy(T)> {};
#else
template<typename T> struct IsTriviallyCopyable : public std::is_trivially_copyable<T> {};
#endif
template <class T1, class T2>
struct IsTriviallyCopyable<std::pair<T1, T2>> {
static constexpr bool value = IsTriviallyCopyable<T1>::value && IsTriviallyCopyable<T2>::value;
};
}
namespace priv {
#if !defined(PHMAP_NON_DETERMINISTIC) && !defined(PHMAP_DISABLE_DUMP)
static constexpr size_t s_version_base = std::numeric_limits<size_t>::max() - 10;
static constexpr size_t s_version = s_version_base;
// ------------------------------------------------------------------------
// dump/load for raw_hash_set
// ------------------------------------------------------------------------
template <class Policy, class Hash, class Eq, class Alloc>
template<typename OutputArchive>
bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_dump(OutputArchive& ar) const {
static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
"value_type should be trivially copyable");
ar.saveBinary(&s_version, sizeof(size_t));
ar.saveBinary(&size_, sizeof(size_t));
ar.saveBinary(&capacity_, sizeof(size_t));
if (size_ == 0)
return true;
ar.saveBinary(ctrl_, sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1));
ar.saveBinary(slots_, sizeof(slot_type) * capacity_);
ar.saveBinary(&growth_left(), sizeof(size_t));
return true;
}
template <class Policy, class Hash, class Eq, class Alloc>
template<typename InputArchive>
bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_load(InputArchive& ar) {
static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
"value_type should be trivially copyable");
raw_hash_set<Policy, Hash, Eq, Alloc>().swap(*this); // clear any existing content
size_t version = 0;
ar.loadBinary(&version, sizeof(size_t));
if (version < s_version_base) {
// we didn't store the version, version actually contains the size
size_ = version;
} else {
ar.loadBinary(&size_, sizeof(size_t));
}
ar.loadBinary(&capacity_, sizeof(size_t));
if (capacity_) {
// allocate memory for ctrl_ and slots_
initialize_slots(capacity_);
}
if (size_ == 0)
return true;
ar.loadBinary(ctrl_, sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1));
ar.loadBinary(slots_, sizeof(slot_type) * capacity_);
if (version >= s_version_base) {
// growth_left should be restored after calling initialize_slots() which resets it.
ar.loadBinary(&growth_left(), sizeof(size_t));
}
return true;
}
// ------------------------------------------------------------------------
// dump/load for parallel_hash_set
// ------------------------------------------------------------------------
template <size_t N,
template <class, class, class, class> class RefSet,
class Mtx_,
class Policy, class Hash, class Eq, class Alloc>
template<typename OutputArchive>
bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::phmap_dump(OutputArchive& ar) const {
static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
"value_type should be trivially copyable");
size_t submap_count = subcnt();
ar.saveBinary(&submap_count, sizeof(size_t));
for (size_t i = 0; i < sets_.size(); ++i) {
auto& inner = sets_[i];
typename Lockable::UniqueLock m(const_cast<Inner&>(inner));
if (!inner.set_.phmap_dump(ar)) {
std::cerr << "Failed to dump submap " << i << std::endl;
return false;
}
}
return true;
}
template <size_t N,
template <class, class, class, class> class RefSet,
class Mtx_,
class Policy, class Hash, class Eq, class Alloc>
template<typename InputArchive>
bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::phmap_load(InputArchive& ar) {
static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
"value_type should be trivially copyable");
size_t submap_count = 0;
ar.loadBinary(&submap_count, sizeof(size_t));
if (submap_count != subcnt()) {
std::cerr << "submap count(" << submap_count << ") != N(" << N << ")" << std::endl;
return false;
}
for (size_t i = 0; i < submap_count; ++i) {
auto& inner = sets_[i];
typename Lockable::UniqueLock m(const_cast<Inner&>(inner));
if (!inner.set_.phmap_load(ar)) {
std::cerr << "Failed to load submap " << i << std::endl;
return false;
}
}
return true;
}
#endif // !defined(PHMAP_NON_DETERMINISTIC) && !defined(PHMAP_DISABLE_DUMP)
} // namespace priv
// ------------------------------------------------------------------------
// BinaryArchive
// File is closed when archive object is destroyed
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
// ------------------------------------------------------------------------
class BinaryOutputArchive {
public:
BinaryOutputArchive(const char *file_path) {
ofs_.open(file_path, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
}
~BinaryOutputArchive() = default;
BinaryOutputArchive(const BinaryOutputArchive&) = delete;
BinaryOutputArchive& operator=(const BinaryOutputArchive&) = delete;
bool saveBinary(const void *p, size_t sz) {
ofs_.write(reinterpret_cast<const char*>(p), (std::streamsize)sz);
return true;
}
template<typename V>
typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
saveBinary(const V& v) {
ofs_.write(reinterpret_cast<const char *>(&v), sizeof(V));
return true;
}
template<typename Map>
auto saveBinary(const Map& v) -> decltype(v.phmap_dump(*this), bool())
{
return v.phmap_dump(*this);
}
private:
std::ofstream ofs_;
};
class BinaryInputArchive {
public:
BinaryInputArchive(const char * file_path) {
ifs_.open(file_path, std::ofstream::in | std::ofstream::binary);
}
~BinaryInputArchive() = default;
BinaryInputArchive(const BinaryInputArchive&) = delete;
BinaryInputArchive& operator=(const BinaryInputArchive&) = delete;
bool loadBinary(void* p, size_t sz) {
ifs_.read(reinterpret_cast<char*>(p), (std::streamsize)sz);
return true;
}
template<typename V>
typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
loadBinary(V* v) {
ifs_.read(reinterpret_cast<char *>(v), sizeof(V));
return true;
}
template<typename Map>
auto loadBinary(Map* v) -> decltype(v->phmap_load(*this), bool())
{
return v->phmap_load(*this);
}
private:
std::ifstream ifs_;
};
} // namespace phmap
#ifdef CEREAL_SIZE_TYPE
template <class T>
using PhmapTrivCopyable = typename phmap::type_traits_internal::IsTriviallyCopyable<T>;
namespace cereal
{
// Overload Cereal serialization code for phmap::flat_hash_map
// -----------------------------------------------------------
template <class K, class V, class Hash, class Eq, class A>
void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar,
phmap::flat_hash_map<K, V, Hash, Eq, A> const &hmap)
{
hmap.phmap_dump(ar);
}
template <class K, class V, class Hash, class Eq, class A>
void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar,
phmap::flat_hash_map<K, V, Hash, Eq, A> &hmap)
{
hmap.phmap_load(ar);
}
// Overload Cereal serialization code for phmap::parallel_flat_hash_map
// --------------------------------------------------------------------
template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_>
void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar,
phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_> const &hmap)
{
hmap.phmap_dump(ar);
}
template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_>
void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar,
phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_> &hmap)
{
hmap.phmap_load(ar);
}
// Overload Cereal serialization code for phmap::flat_hash_set
// -----------------------------------------------------------
template <class K, class Hash, class Eq, class A>
void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar,
phmap::flat_hash_set<K, Hash, Eq, A> const &hset)
{
hset.phmap_dump(ar);
}
template <class K, class Hash, class Eq, class A>
void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar,
phmap::flat_hash_set<K, Hash, Eq, A> &hset)
{
hset.phmap_load(ar);
}
// Overload Cereal serialization code for phmap::parallel_flat_hash_set
// --------------------------------------------------------------------
template <class K, class Hash, class Eq, class A, size_t N, class Mtx_>
void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar,
phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_> const &hset)
{
hset.phmap_dump(ar);
}
template <class K, class Hash, class Eq, class A, size_t N, class Mtx_>
void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar,
phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_> &hset)
{
hset.phmap_load(ar);
}
}
#endif
#endif // phmap_dump_h_guard_

View file

@ -0,0 +1,186 @@
#if !defined(phmap_fwd_decl_h_guard_)
#define phmap_fwd_decl_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
// ---------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4514) // unreferenced inline function has been removed
#pragma warning(disable : 4710) // function not inlined
#pragma warning(disable : 4711) // selected for automatic inline expansion
#endif
#include <memory>
#include <utility>
#include <mutex>
#if defined(PHMAP_USE_ABSL_HASH) && !defined(ABSL_HASH_HASH_H_)
namespace absl { template <class T> struct Hash; };
#endif
namespace phmap {
#if defined(PHMAP_USE_ABSL_HASH)
template <class T> using Hash = ::absl::Hash<T>;
#else
template <class T> struct Hash;
#endif
template <class T> struct EqualTo;
template <class T> struct Less;
template <class T> using Allocator = typename std::allocator<T>;
template<class T1, class T2> using Pair = typename std::pair<T1, T2>;
class NullMutex;
namespace priv {
// The hash of an object of type T is computed by using phmap::Hash.
template <class T, class E = void>
struct HashEq
{
using Hash = phmap::Hash<T>;
using Eq = phmap::EqualTo<T>;
};
template <class T>
using hash_default_hash = typename priv::HashEq<T>::Hash;
template <class T>
using hash_default_eq = typename priv::HashEq<T>::Eq;
// type alias for std::allocator so we can forward declare without including other headers
template <class T>
using Allocator = typename phmap::Allocator<T>;
// type alias for std::pair so we can forward declare without including other headers
template<class T1, class T2>
using Pair = typename phmap::Pair<T1, T2>;
} // namespace priv
// ------------- forward declarations for hash containers ----------------------------------
template <class T,
class Hash = phmap::priv::hash_default_hash<T>,
class Eq = phmap::priv::hash_default_eq<T>,
class Alloc = phmap::priv::Allocator<T>> // alias for std::allocator
class flat_hash_set;
template <class K, class V,
class Hash = phmap::priv::hash_default_hash<K>,
class Eq = phmap::priv::hash_default_eq<K>,
class Alloc = phmap::priv::Allocator<
phmap::priv::Pair<const K, V>>> // alias for std::allocator
class flat_hash_map;
template <class T,
class Hash = phmap::priv::hash_default_hash<T>,
class Eq = phmap::priv::hash_default_eq<T>,
class Alloc = phmap::priv::Allocator<T>> // alias for std::allocator
class node_hash_set;
template <class Key, class Value,
class Hash = phmap::priv::hash_default_hash<Key>,
class Eq = phmap::priv::hash_default_eq<Key>,
class Alloc = phmap::priv::Allocator<
phmap::priv::Pair<const Key, Value>>> // alias for std::allocator
class node_hash_map;
template <class T,
class Hash = phmap::priv::hash_default_hash<T>,
class Eq = phmap::priv::hash_default_eq<T>,
class Alloc = phmap::priv::Allocator<T>, // alias for std::allocator
size_t N = 4, // 2**N submaps
class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks
class parallel_flat_hash_set;
template <class K, class V,
class Hash = phmap::priv::hash_default_hash<K>,
class Eq = phmap::priv::hash_default_eq<K>,
class Alloc = phmap::priv::Allocator<
phmap::priv::Pair<const K, V>>, // alias for std::allocator
size_t N = 4, // 2**N submaps
class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks
class parallel_flat_hash_map;
template <class T,
class Hash = phmap::priv::hash_default_hash<T>,
class Eq = phmap::priv::hash_default_eq<T>,
class Alloc = phmap::priv::Allocator<T>, // alias for std::allocator
size_t N = 4, // 2**N submaps
class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks
class parallel_node_hash_set;
template <class Key, class Value,
class Hash = phmap::priv::hash_default_hash<Key>,
class Eq = phmap::priv::hash_default_eq<Key>,
class Alloc = phmap::priv::Allocator<
phmap::priv::Pair<const Key, Value>>, // alias for std::allocator
size_t N = 4, // 2**N submaps
class Mutex = phmap::NullMutex> // use std::mutex to enable internal locks
class parallel_node_hash_map;
// -----------------------------------------------------------------------------
// phmap::parallel_*_hash_* using std::mutex by default
// -----------------------------------------------------------------------------
template <class T,
class Hash = phmap::priv::hash_default_hash<T>,
class Eq = phmap::priv::hash_default_eq<T>,
class Alloc = phmap::priv::Allocator<T>,
size_t N = 4>
using parallel_flat_hash_set_m = parallel_flat_hash_set<T, Hash, Eq, Alloc, N, std::mutex>;
template <class K, class V,
class Hash = phmap::priv::hash_default_hash<K>,
class Eq = phmap::priv::hash_default_eq<K>,
class Alloc = phmap::priv::Allocator<phmap::priv::Pair<const K, V>>,
size_t N = 4>
using parallel_flat_hash_map_m = parallel_flat_hash_map<K, V, Hash, Eq, Alloc, N, std::mutex>;
template <class T,
class Hash = phmap::priv::hash_default_hash<T>,
class Eq = phmap::priv::hash_default_eq<T>,
class Alloc = phmap::priv::Allocator<T>,
size_t N = 4>
using parallel_node_hash_set_m = parallel_node_hash_set<T, Hash, Eq, Alloc, N, std::mutex>;
template <class K, class V,
class Hash = phmap::priv::hash_default_hash<K>,
class Eq = phmap::priv::hash_default_eq<K>,
class Alloc = phmap::priv::Allocator<phmap::priv::Pair<const K, V>>,
size_t N = 4>
using parallel_node_hash_map_m = parallel_node_hash_map<K, V, Hash, Eq, Alloc, N, std::mutex>;
// ------------- forward declarations for btree containers ----------------------------------
template <typename Key, typename Compare = phmap::Less<Key>,
typename Alloc = phmap::Allocator<Key>>
class btree_set;
template <typename Key, typename Compare = phmap::Less<Key>,
typename Alloc = phmap::Allocator<Key>>
class btree_multiset;
template <typename Key, typename Value, typename Compare = phmap::Less<Key>,
typename Alloc = phmap::Allocator<phmap::priv::Pair<const Key, Value>>>
class btree_map;
template <typename Key, typename Value, typename Compare = phmap::Less<Key>,
typename Alloc = phmap::Allocator<phmap::priv::Pair<const Key, Value>>>
class btree_multimap;
} // namespace phmap
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // phmap_fwd_decl_h_guard_

View file

@ -0,0 +1,407 @@
#if !defined(phmap_utils_h_guard_)
#define phmap_utils_h_guard_
// ---------------------------------------------------------------------------
// Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com
//
// minimal header providing phmap::HashState
//
// use as: phmap::HashState().combine(0, _first_name, _last_name, _age);
//
// 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
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ---------------------------------------------------------------------------
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4514) // unreferenced inline function has been removed
#pragma warning(disable : 4710) // function not inlined
#pragma warning(disable : 4711) // selected for automatic inline expansion
#endif
#include <cstdint>
#include <functional>
#include <tuple>
#include "phmap_bits.h"
// ---------------------------------------------------------------
// Absl forward declaration requires global scope.
// ---------------------------------------------------------------
#if defined(PHMAP_USE_ABSL_HASH) && !defined(phmap_fwd_decl_h_guard_) && !defined(ABSL_HASH_HASH_H_)
namespace absl { template <class T> struct Hash; };
#endif
namespace phmap
{
// ---------------------------------------------------------------
// ---------------------------------------------------------------
template<int n>
struct phmap_mix
{
inline size_t operator()(size_t) const;
};
template<>
struct phmap_mix<4>
{
inline size_t operator()(size_t a) const
{
static constexpr uint64_t kmul = 0xcc9e2d51UL;
uint64_t l = a * kmul;
return static_cast<size_t>(l ^ (l >> 32));
}
};
#if defined(PHMAP_HAS_UMUL128)
template<>
struct phmap_mix<8>
{
// Very fast mixing (similar to Abseil)
inline size_t operator()(size_t a) const
{
static constexpr uint64_t k = 0xde5fb9d2630458e9ULL;
uint64_t h;
uint64_t l = umul128(a, k, &h);
return static_cast<size_t>(h + l);
}
};
#else
template<>
struct phmap_mix<8>
{
inline size_t operator()(size_t a) const
{
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);
}
};
#endif
// --------------------------------------------
template<int n>
struct fold_if_needed
{
inline size_t operator()(uint64_t) const;
};
template<>
struct fold_if_needed<4>
{
inline size_t operator()(uint64_t a) const
{
return static_cast<size_t>(a ^ (a >> 32));
}
};
template<>
struct fold_if_needed<8>
{
inline size_t operator()(uint64_t a) const
{
return static_cast<size_t>(a);
}
};
// ---------------------------------------------------------------
// see if class T has a hash_value() friend method
// ---------------------------------------------------------------
template<typename T>
struct has_hash_value
{
private:
typedef std::true_type yes;
typedef std::false_type no;
template<typename U> static auto test(int) -> decltype(hash_value(std::declval<const U&>()) == 1, yes());
template<typename> static no test(...);
public:
static constexpr bool value = std::is_same<decltype(test<T>(0)), yes>::value;
};
#if defined(PHMAP_USE_ABSL_HASH) && !defined(phmap_fwd_decl_h_guard_)
template <class T> using Hash = ::absl::Hash<T>;
#elif !defined(PHMAP_USE_ABSL_HASH)
// ---------------------------------------------------------------
// phmap::Hash
// ---------------------------------------------------------------
template <class T>
struct Hash
{
template <class U, typename std::enable_if<has_hash_value<U>::value, int>::type = 0>
size_t _hash(const T& val) const
{
return hash_value(val);
}
template <class U, typename std::enable_if<!has_hash_value<U>::value, int>::type = 0>
size_t _hash(const T& val) const
{
return std::hash<T>()(val);
}
inline size_t operator()(const T& val) const
{
return _hash<T>(val);
}
};
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 val) const noexcept
{ return static_cast<size_t>(val); }
};
template <>
struct Hash<char> : public phmap_unary_function<char, size_t>
{
inline size_t operator()(char val) const noexcept
{ return static_cast<size_t>(val); }
};
template <>
struct Hash<signed char> : public phmap_unary_function<signed char, size_t>
{
inline size_t operator()(signed char val) const noexcept
{ return static_cast<size_t>(val); }
};
template <>
struct Hash<unsigned char> : public phmap_unary_function<unsigned char, size_t>
{
inline size_t operator()(unsigned char val) const noexcept
{ return static_cast<size_t>(val); }
};
#ifdef PHMAP_HAS_NATIVE_WCHAR_T
template <>
struct Hash<wchar_t> : public phmap_unary_function<wchar_t, size_t>
{
inline size_t operator()(wchar_t val) const noexcept
{ return static_cast<size_t>(val); }
};
#endif
template <>
struct Hash<int16_t> : public phmap_unary_function<int16_t, size_t>
{
inline size_t operator()(int16_t val) const noexcept
{ return static_cast<size_t>(val); }
};
template <>
struct Hash<uint16_t> : public phmap_unary_function<uint16_t, size_t>
{
inline size_t operator()(uint16_t val) const noexcept
{ return static_cast<size_t>(val); }
};
template <>
struct Hash<int32_t> : public phmap_unary_function<int32_t, size_t>
{
inline size_t operator()(int32_t val) const noexcept
{ return static_cast<size_t>(val); }
};
template <>
struct Hash<uint32_t> : public phmap_unary_function<uint32_t, size_t>
{
inline size_t operator()(uint32_t val) const noexcept
{ return static_cast<size_t>(val); }
};
template <>
struct Hash<int64_t> : public phmap_unary_function<int64_t, size_t>
{
inline size_t operator()(int64_t val) const noexcept
{ return fold_if_needed<sizeof(size_t)>()(static_cast<uint64_t>(val)); }
};
template <>
struct Hash<uint64_t> : public phmap_unary_function<uint64_t, size_t>
{
inline size_t operator()(uint64_t val) const noexcept
{ return fold_if_needed<sizeof(size_t)>()(val); }
};
template <>
struct Hash<float> : public phmap_unary_function<float, size_t>
{
inline size_t operator()(float val) const noexcept
{
// -0.0 and 0.0 should return same hash
uint32_t *as_int = reinterpret_cast<uint32_t *>(&val);
return (val == 0) ? static_cast<size_t>(0) :
static_cast<size_t>(*as_int);
}
};
template <>
struct Hash<double> : public phmap_unary_function<double, size_t>
{
inline size_t operator()(double val) const noexcept
{
// -0.0 and 0.0 should return same hash
uint64_t *as_int = reinterpret_cast<uint64_t *>(&val);
return (val == 0) ? static_cast<size_t>(0) :
fold_if_needed<sizeof(size_t)>()(*as_int);
}
};
#endif
#if defined(_MSC_VER)
# define PHMAP_HASH_ROTL32(x, r) _rotl(x,r)
#else
# define PHMAP_HASH_ROTL32(x, r) (x << r) | (x >> (32 - r))
#endif
template <class H, int sz> struct Combiner
{
H operator()(H seed, size_t value);
};
template <class H> struct Combiner<H, 4>
{
H operator()(H h1, size_t k1)
{
// Copyright 2005-2014 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
const uint32_t c1 = 0xcc9e2d51;
const uint32_t c2 = 0x1b873593;
k1 *= c1;
k1 = PHMAP_HASH_ROTL32(k1,15);
k1 *= c2;
h1 ^= k1;
h1 = PHMAP_HASH_ROTL32(h1,13);
h1 = h1*5+0xe6546b64;
return h1;
}
};
template <class H> struct Combiner<H, 8>
{
H operator()(H h, size_t k)
{
// Copyright 2005-2014 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
const uint64_t m = (uint64_t(0xc6a4a793) << 32) + 0x5bd1e995;
const int r = 47;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
// Completely arbitrary number, to prevent 0's
// from hashing to 0.
h += 0xe6546b64;
return h;
}
};
// define HashState to combine member hashes... see example below
// -----------------------------------------------------------------------------
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)
{
return HashStateBase<H>::combine(Combiner<H, sizeof(H)>()(
seed, phmap::Hash<T>()(v)),
vs...);
}
using HashState = HashStateBase<size_t>;
// -----------------------------------------------------------------------------
#if !defined(PHMAP_USE_ABSL_HASH)
// define Hash for std::pair
// -------------------------
template<class T1, class T2>
struct Hash<std::pair<T1, T2>> {
size_t operator()(std::pair<T1, T2> const& p) const noexcept {
return phmap::HashState().combine(phmap::Hash<T1>()(p.first), p.second);
}
};
// define Hash for std::tuple
// --------------------------
template<class... T>
struct Hash<std::tuple<T...>> {
size_t operator()(std::tuple<T...> const& t) const noexcept {
size_t seed = 0;
return _hash_helper(seed, t);
}
private:
template<size_t I = 0, class TUP>
typename std::enable_if<I == std::tuple_size<TUP>::value, size_t>::type
_hash_helper(size_t seed, const TUP &) const noexcept { return seed; }
template<size_t I = 0, class TUP>
typename std::enable_if<I < std::tuple_size<TUP>::value, size_t>::type
_hash_helper(size_t seed, const TUP &t) const noexcept {
const auto &el = std::get<I>(t);
using el_type = typename std::remove_cv<typename std::remove_reference<decltype(el)>::type>::type;
seed = Combiner<size_t, sizeof(size_t)>()(seed, phmap::Hash<el_type>()(el));
return _hash_helper<I + 1>(seed, t);
}
};
#endif
} // namespace phmap
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#endif // phmap_utils_h_guard_