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:
parent
5507f8e5dc
commit
f0a496a8f0
10 changed files with 16926 additions and 1 deletions
|
@ -9,6 +9,7 @@
|
||||||
#include <boost/rational.hpp>
|
#include <boost/rational.hpp>
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <parallel_hashmap/phmap.h>
|
||||||
|
|
||||||
namespace Hanabi
|
namespace Hanabi
|
||||||
{
|
{
|
||||||
|
@ -23,7 +24,7 @@ namespace Hanabi
|
||||||
using rational_probability = boost::rational<probability_base_type>;
|
using rational_probability = boost::rational<probability_base_type>;
|
||||||
|
|
||||||
template<class Key, class Value>
|
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
|
* Define macro
|
||||||
|
|
4076
include/parallel_hashmap/btree.h
Normal file
4076
include/parallel_hashmap/btree.h
Normal file
File diff suppressed because it is too large
Load diff
195
include/parallel_hashmap/meminfo.h
Normal file
195
include/parallel_hashmap/meminfo.h
Normal 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
|
5205
include/parallel_hashmap/phmap.h
Normal file
5205
include/parallel_hashmap/phmap.h
Normal file
File diff suppressed because it is too large
Load diff
5112
include/parallel_hashmap/phmap_base.h
Normal file
5112
include/parallel_hashmap/phmap_base.h
Normal file
File diff suppressed because it is too large
Load diff
664
include/parallel_hashmap/phmap_bits.h
Normal file
664
include/parallel_hashmap/phmap_bits.h
Normal 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_
|
767
include/parallel_hashmap/phmap_config.h
Normal file
767
include/parallel_hashmap/phmap_config.h
Normal 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_
|
312
include/parallel_hashmap/phmap_dump.h
Normal file
312
include/parallel_hashmap/phmap_dump.h
Normal 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_
|
186
include/parallel_hashmap/phmap_fwd_decl.h
Normal file
186
include/parallel_hashmap/phmap_fwd_decl.h
Normal 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_
|
407
include/parallel_hashmap/phmap_utils.h
Normal file
407
include/parallel_hashmap/phmap_utils.h
Normal 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_
|
Loading…
Reference in a new issue