Commit 19fd8251 authored by limm's avatar limm
Browse files

support v0.6.16

parent 9ccee9c0
...@@ -7,6 +7,9 @@ configure_file( ...@@ -7,6 +7,9 @@ configure_file(
${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt ${CMAKE_BINARY_DIR}/googletest-download/CMakeLists.txt
) )
set(PHMAP_SAVE_CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
set(PHMAP_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
# Configure and build the downloaded googletest source # Configure and build the downloaded googletest source
execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" . execute_process(COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
RESULT_VARIABLE result RESULT_VARIABLE result
...@@ -24,6 +27,9 @@ if(result) ...@@ -24,6 +27,9 @@ if(result)
message(FATAL_ERROR "Build step for googletest failed: ${result}") message(FATAL_ERROR "Build step for googletest failed: ${result}")
endif() endif()
set(CMAKE_CXX_FLAGS ${PHMAP_SAVE_CMAKE_CXX_FLAGS})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PHMAP_SAVE_CMAKE_RUNTIME_OUTPUT_DIRECTORY})
# Prevent overriding the parent project's compiler/linker settings on Windows # Prevent overriding the parent project's compiler/linker settings on Windows
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
......
...@@ -15,8 +15,7 @@ function(phmap_cc_test) ...@@ -15,8 +15,7 @@ function(phmap_cc_test)
) )
set(_NAME "test_${PHMAP_CC_TEST_NAME}") set(_NAME "test_${PHMAP_CC_TEST_NAME}")
add_executable(${_NAME} "") add_executable(${_NAME} ${PHMAP_CC_TEST_SRCS})
target_sources(${_NAME} PRIVATE ${PHMAP_CC_TEST_SRCS})
target_include_directories(${_NAME} target_include_directories(${_NAME}
PUBLIC ${PHMAP_COMMON_INCLUDE_DIRS} PUBLIC ${PHMAP_COMMON_INCLUDE_DIRS}
PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS} PRIVATE ${GMOCK_INCLUDE_DIRS} ${GTEST_INCLUDE_DIRS}
......
- update version in phmap_config.h
- update version in comment on top of CMakeLists.txt
- git commit
- git push
- create the new release on github (tag `v1.3.8` - use semantic versioning)
- download the tar.gz from github, and use `sha256sum parallel-hashmap-1.3.8.tar.gz` on linux to get the sha256
## conan
- fork and clone [conan-center repo](https://github.com/conan-io/conan-center-index)
(or sync + git pull)
- git checkout master
- git checkout -b phmap_1.3.8
- update: `recipes/parallel-hashmap/all/conandata.yml` and `recipes/parallel-hashmap/config.yml`
- sudo pip install conan -U
- cd recipes/parallel-hashmap/all
- conan create conanfile.py parallel-hashmap/1.3.8@ -pr:b=default -pr:h=default
- git diff
- git commit -am "[parallel-hashmap] Bump version to 1.3.8"
- git push origin phmap_1.3.8
- create PR like [this](https://github.com/conan-io/conan-center-index/pull/13161)
## vcpkg
- fork and clone [vcpkg repo](https://github.com/microsoft/vcpkg)
(or sync + git pull)
- git checkout -b phmap_1.3.8
- update ports/parallel-hashmap/portfile.cmake and ports/parallel-hashmap/vcpkg.json
in windows, non-cygwin console
- set VCPKG_ROOT=
- vcpkg install parallel-hashmap --triplet x64-windows
- # update sha in portfile.cmake - run `sha512sum parallel-hashmap-1.3.8.tar.gz` on linux
- git diff
- git commit -am "[parallel-hashmap] Bump version to 1.3.8"
- vcpkg x-add-version --all --overwrite-version ## (or ./vcpkg.exe --no-dry-run upgrade )
- git diff -am "[parallel-hashmap] run x-add-version"
- git commit ...
- git push origin phmap_1.3.8
...@@ -18,11 +18,11 @@ public: ...@@ -18,11 +18,11 @@ public:
{ {
phmap::BinaryOutputArchive ar_out (filename.c_str()); phmap::BinaryOutputArchive ar_out (filename.c_str());
ar_out.dump(this->size()); ar_out.saveBinary(this->size());
for (auto& [k, v] : *this) for (auto& [k, v] : *this)
{ {
ar_out.dump(k); ar_out.saveBinary(k);
v.dump(ar_out); ar_out.saveBinary(v);
} }
} }
...@@ -31,7 +31,7 @@ public: ...@@ -31,7 +31,7 @@ public:
phmap::BinaryInputArchive ar_in(filename.c_str()); phmap::BinaryInputArchive ar_in(filename.c_str());
size_t size; size_t size;
ar_in.load(&size); ar_in.loadBinary(&size);
this->reserve(size); this->reserve(size);
while (size--) while (size--)
...@@ -39,8 +39,8 @@ public: ...@@ -39,8 +39,8 @@ public:
K k; K k;
Set v; Set v;
ar_in.load(&k); ar_in.loadBinary(&k);
v.load(ar_in); ar_in.loadBinary(&v);
this->insert_or_assign(std::move(k), std::move(v)); this->insert_or_assign(std::move(k), std::move(v));
} }
......
#include <parallel_hashmap/phmap_utils.h> // minimal header providing phmap::HashState()
#include <string>
#include <utility>
#include <tuple>
#include <vector>
#include <array>
#if PHMAP_HAVE_STD_STRING_VIEW
#include <string_view>
#endif
#include <iostream>
using std::string;
using std::tuple;
using std::pair;
using groupid_t = std::array<uint16_t, 4>;
namespace std
{
template<> struct hash<groupid_t>
{
#if PHMAP_HAVE_STD_STRING_VIEW
std::size_t operator()(groupid_t const &g) const
{
const std::string_view bv{reinterpret_cast<const char*>(g.data()), sizeof(g)};
return std::hash<std::string_view>()(bv);
}
#else
std::size_t operator()(groupid_t const &g) const
{
return phmap::Hash<decltype(std::tuple_cat(g))>()(std::tuple_cat(g));
}
#endif
};
}
int main()
{
std::vector<groupid_t> groups = {
{17, 75, 82, 66},
{22, 88, 54, 42},
{11, 55, 77, 99} };
for (const auto &g : groups)
std::cout << std::hash<groupid_t>()(g) << '\n';
return 0;
}
#include <iostream>
#include <string>
#include <array>
#include <cstdint>
#include <limits>
#include <random>
#include <utility>
#define PHMAP_ALLOCATOR_NOTHROW 1
#include <parallel_hashmap/phmap.h>
// this is probably the fastest high quality 64bit random number generator that exists.
// Implements Small Fast Counting v4 RNG from PractRand.
class sfc64 {
public:
using result_type = uint64_t;
// no copy ctors so we don't accidentally get the same random again
sfc64(sfc64 const&) = delete;
sfc64& operator=(sfc64 const&) = delete;
sfc64(sfc64&&) = default;
sfc64& operator=(sfc64&&) = default;
sfc64(std::array<uint64_t, 4> const& _state)
: m_a(_state[0])
, m_b(_state[1])
, m_c(_state[2])
, m_counter(_state[3]) {}
static constexpr uint64_t(min)() {
return (std::numeric_limits<uint64_t>::min)();
}
static constexpr uint64_t(max)() {
return (std::numeric_limits<uint64_t>::max)();
}
sfc64()
: sfc64(UINT64_C(0x853c49e6748fea9b)) {}
sfc64(uint64_t _seed)
: m_a(_seed)
, m_b(_seed)
, m_c(_seed)
, m_counter(1) {
for (int i = 0; i < 12; ++i) {
operator()();
}
}
void seed() {
*this = sfc64{std::random_device{}()};
}
uint64_t operator()() noexcept {
auto const tmp = m_a + m_b + m_counter++;
m_a = m_b ^ (m_b >> right_shift);
m_b = m_c + (m_c << left_shift);
m_c = rotl(m_c, rotation) + tmp;
return tmp;
}
std::array<uint64_t, 4> state() const {
return {{m_a, m_b, m_c, m_counter}};
}
void state(std::array<uint64_t, 4> const& s) {
m_a = s[0];
m_b = s[1];
m_c = s[2];
m_counter = s[3];
}
private:
template <typename T>
T rotl(T const x, int k) {
return (x << k) | (x >> (8 * sizeof(T) - k));
}
static constexpr int rotation = 24;
static constexpr int right_shift = 11;
static constexpr int left_shift = 3;
uint64_t m_a;
uint64_t m_b;
uint64_t m_c;
uint64_t m_counter;
};
static inline std::string to_str(uint64_t x) {
std::string res(4, '1');
x = (x >> 48) ^ (x >> 32) ^ (x >> 16) ^ x; // combine 64 bits > 16 lsb
for (size_t i=0; i<4; ++i) {
res[i] = 'a' + (x & 0xF);
x >>= 4;
}
return res;
}
int main()
{
using Map = phmap::flat_hash_map<std::string, uint32_t>;
Map map;
map.reserve((size_t)(65536 * 1.1)); // we will create a maximun of 65536 different strings
sfc64 rng(123);
constexpr size_t const n = 50000000;
for (size_t i = 0; i < n; ++i) {
auto s = to_str(rng());
map[s]++;
map[s]++;
map[s]++;
map[s]++;
map[s]++;
map[s]++;
map[s]++;
map[s]++;
map[s]++;
map[s]++;
}
uint64_t cnt = 0;
for (const auto& s : map) {
if (++cnt == 6) break;
std::cout << s.first << ": " << s.second << '\n';
}
return 0;
}
...@@ -8,18 +8,9 @@ ...@@ -8,18 +8,9 @@
#include <vector> #include <vector>
#include <ppl.h> #include <ppl.h>
class srwlock {
SRWLOCK _lock;
public:
srwlock() { InitializeSRWLock(&_lock); }
void lock() { AcquireSRWLockExclusive(&_lock); }
void unlock() { ReleaseSRWLockExclusive(&_lock); }
};
using Map = phmap::parallel_flat_hash_map<std::string, int, phmap::priv::hash_default_hash<std::string>, using Map = phmap::parallel_flat_hash_map<std::string, int, phmap::priv::hash_default_hash<std::string>,
phmap::priv::hash_default_eq<std::string>, phmap::priv::hash_default_eq<std::string>,
std::allocator<std::pair<const std::string, int>>, 8, srwlock>; std::allocator<std::pair<const std::string, int>>, 8, phmap::srwlock>;
class Dict class Dict
{ {
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include <cstdlib> #include <cstdlib>
#include <cstdio> #include <cstdio>
#include <cmath> #include <cmath>
#include <utility>
#include <vector> #include <vector>
#include <random> #include <random>
#include <parallel_hashmap/phmap.h> #include <parallel_hashmap/phmap.h>
...@@ -14,7 +15,7 @@ ...@@ -14,7 +15,7 @@
class Timer class Timer
{ {
public: public:
Timer(std::string name) : _name(name), _start(std::chrono::high_resolution_clock::now()) {} Timer(std::string name) : _name(std::move(name)), _start(std::chrono::high_resolution_clock::now()) {}
~Timer() ~Timer()
{ {
...@@ -63,7 +64,7 @@ using Perturb = std::function<void (std::vector<uint64_t> &)>; ...@@ -63,7 +64,7 @@ using Perturb = std::function<void (std::vector<uint64_t> &)>;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
template<class Set, size_t N> template<class Set, size_t N>
void test(const char *name, Perturb perturb1, Perturb /* perturb2 */) void test(const char *name, const Perturb &perturb1, const Perturb& /* perturb2 */)
{ {
//phmap::btree_set<uint64_t> s; //phmap::btree_set<uint64_t> s;
Set s; Set s;
......
#include <iostream>
#include <fstream>
#include <sstream>
#include <parallel_hashmap/phmap.h>
#include <parallel_hashmap/btree.h>
#include <thread>
#include <array>
#include <vector>
#include <algorithm>
#include <cstdlib>
/*
* count the number of occurrences of each word in a large text file using multiple threads
*/
int main() {
// download Jane Austin "Pride and Prejudice"
// ------------------------------------------
if (system("curl https://www.gutenberg.org/files/1342/1342-0.txt -o 1342-0.txt") != 0) {
std::cout << "Error: could not retrieve test file https://www.gutenberg.org/files/1342/1342-0.txt\n";
return 1;
}
const std::string filename = "1342-0.txt";
constexpr int num_threads = 4;
std::vector<std::thread> threads;
std::array<std::vector<std::string>, num_threads> lines_array;
{
// populate 4 vectors with lines from the book
std::ifstream file(filename);
if (!file.is_open()) {
std::cout << "Error: could not open file " << filename << std::endl;
return 1;
}
int line_idx = 0;
std::string line;
while (std::getline(file, line)) {
lines_array[line_idx % num_threads].push_back(std::move(line));
++line_idx;
}
}
using Map = phmap::parallel_flat_hash_map_m<std::string, int>; // parallel_flat_hash_map_m has default internal mutex
Map word_counts;
// run 4 threads, each thread processing lines from one of the vectors
// -------------------------------------------------------------------
threads.reserve(num_threads);
for (int i = 0; i < num_threads; ++i) {
threads.emplace_back(
[&word_counts](std::vector<std::string>&& lines) {
for (auto& line : lines) {
std::replace_if(line.begin(), line.end(), [](char c) -> bool { return !std::isalnum(c); }, ' ');
std::istringstream iss(line);
std::string word;
while (iss >> word) {
// use lazy_emplace to modify the map while the mutex is locked
word_counts.lazy_emplace_l(word,
[&](Map::value_type& p) { ++p.second; }, // called only when key was already present
[&](const Map::constructor& ctor) // construct value_type in place when key not present
{ ctor(std::move(word), 1); } );
}
}
},
std::move(lines_array[i]));
}
for (auto& thread : threads)
thread.join();
// print one word used at each frequency
// -------------------------------------
phmap::btree_map<int, std::string> result;
for (const auto& pair : word_counts)
result[pair.second] = pair.first;
for (const auto& p : result)
std::cout << p.first << ": " << p.second << std::endl;
return 0;
}
// example graciously provided @samuelpmish
// ----------------------------------------
//
// Getting rid of the mutexes for read access
//
// This example demonstrated how to populate a parallel_flat_hash_map from multiple
// concurrent threads (The map is protected by internal mutexes), but then doing a
// swap to get rid of the mutexes (and all locking) for accessing the same hash_map
// in `read` only mode, again concurrently from multiple threads.
// --------------------------------------------------------------------------------
#include <random>
#include <iostream>
#include <unordered_map>
#include <unordered_set>
#include "parallel_hashmap/phmap.h"
///////////////////////////////////////////////////////////////////////////////
#include <chrono>
class timer {
typedef std::chrono::high_resolution_clock::time_point time_point;
typedef std::chrono::duration<double> duration_type;
public:
void start() { then = std::chrono::high_resolution_clock::now(); }
void stop() { now = std::chrono::high_resolution_clock::now(); }
double elapsed() { return std::chrono::duration_cast<duration_type>(now - then).count(); }
private:
time_point then, now;
};
///////////////////////////////////////////////////////////////////////////////
#include <thread>
struct threadpool {
std::vector< uint64_t > partition(uint64_t n) {
uint64_t quotient = n / num_threads;
uint64_t remainder = n % num_threads;
std::vector< uint64_t > blocks(num_threads + 1);
blocks[0] = 0;
for (int i = 1; i < num_threads + 1; i++) {
if (remainder > 0) {
blocks[i] = blocks[i-1] + quotient + 1;
remainder--;
} else {
blocks[i] = blocks[i-1] + quotient;
}
}
return blocks;
}
threadpool(int n) : num_threads(n) {}
template < typename lambda >
void parallel_for(uint64_t n, const lambda & f) {
std::vector< uint64_t > blocks = partition(n);
for (int tid = 0; tid < num_threads; tid++) {
threads.push_back(std::thread([&](uint64_t i0) {
for (uint64_t i = blocks[i0]; i < blocks[i0+1]; i++) {
f(i);
}
}, tid));
}
for (int i = 0; i < num_threads; i++) {
threads[i].join();
}
threads.clear();
}
int num_threads;
std::vector< std::thread > threads;
};
///////////////////////////////////////////////////////////////////////////////
template < int n >
using pmap = phmap::parallel_flat_hash_map<
uint64_t,
uint64_t,
std::hash<uint64_t>,
std::equal_to<uint64_t>,
std::allocator<std::pair<const uint64_t, uint64_t>>,
n,
std::mutex >;
template < int n >
using pmap_nullmutex = phmap::parallel_flat_hash_map<
uint64_t,
uint64_t,
std::hash<uint64_t>,
std::equal_to<uint64_t>,
std::allocator<std::pair<const uint64_t, uint64_t>>,
n,
phmap::NullMutex >;
template < typename Map, typename Map_nomutex >
void renumber(const std::vector< uint64_t > & vertex_ids,
std::vector< std::array< uint64_t, 4 > > elements,
int num_threads) {
bool supports_parallel_insertion =
!std::is_same< Map, std::unordered_map<uint64_t, uint64_t> >::value;
Map new_ids;
std::atomic< uint64_t > new_id{ 0 };
timer stopwatch;
threadpool pool((supports_parallel_insertion) ? num_threads : 1);
stopwatch.start();
new_ids.reserve(vertex_ids.size() * 110 / 100);
pool.parallel_for(vertex_ids.size(), [&](uint64_t i){
auto id = new_id++;
new_ids[vertex_ids[i]] = id;
});
stopwatch.stop();
std::cout << stopwatch.elapsed() * 1000 << "ms ";
pool.num_threads = num_threads;
stopwatch.start();
Map_nomutex new_ids_nc;
new_ids_nc.swap(new_ids);
pool.parallel_for(elements.size(), [&](uint64_t i) {
auto & elem = elements[i];
elem = { new_ids_nc.at(elem[0]),
new_ids_nc.at(elem[1]),
new_ids_nc.at(elem[2]),
new_ids_nc.at(elem[3]) };
});
stopwatch.stop();
std::cout << stopwatch.elapsed() * 1000 << "ms" << std::endl;
}
int main() {
uint64_t nvertices = 5000000;
uint64_t nelements = 25000000;
std::random_device rd; // a seed source for the random number engine
std::mt19937 gen(rd()); // mersenne_twister_engine seeded with rd()
std::uniform_int_distribution<uint64_t> vertex_id_dist(0, uint64_t(1) << 35);
std::uniform_int_distribution<uint64_t> elem_id_dist(0, nvertices-1);
std::cout << "generating dataset ." << std::flush;
std::vector< uint64_t > vertex_ids(nvertices);
for (uint64_t i = 0; i < nvertices; i++) {
vertex_ids[i] = vertex_id_dist(gen);
}
std::cout << "." << std::flush;
std::vector< std::array<uint64_t, 4> > elements(nelements);
for (uint64_t i = 0; i < nelements; i++) {
elements[i] = {
vertex_ids[elem_id_dist(gen)],
vertex_ids[elem_id_dist(gen)],
vertex_ids[elem_id_dist(gen)],
vertex_ids[elem_id_dist(gen)]
};
}
std::cout << " done" << std::endl;
using stdmap = std::unordered_map<uint64_t, uint64_t>;
std::cout << "std::unordered_map, 1 thread: ";
renumber< stdmap, stdmap >(vertex_ids, elements, 1);
std::cout << "std::unordered_map, 32 thread (single threaded insertion): ";
renumber< stdmap, stdmap >(vertex_ids, elements, 32);
std::cout << "pmap4, 1 thread: ";
renumber< pmap<4>, pmap_nullmutex<4> >(vertex_ids, elements, 1);
std::cout << "pmap4, 32 threads: ";
renumber< pmap<4>, pmap_nullmutex<4> >(vertex_ids, elements, 32);
std::cout << "pmap6, 1 thread: ";
renumber< pmap<6>, pmap_nullmutex<6> >(vertex_ids, elements, 1);
std::cout << "pmap6, 32 threads: ";
renumber< pmap<6>, pmap_nullmutex<6> >(vertex_ids, elements, 32);
}
\ No newline at end of file
...@@ -16,7 +16,7 @@ struct MyStruct ...@@ -16,7 +16,7 @@ struct MyStruct
{ {
template<typename Key, typename Value> template<typename Key, typename Value>
using ParallelFlatHashMap = phmap::parallel_flat_hash_map<Key, Value, std::hash<Key>, std::equal_to<Key>, using ParallelFlatHashMap = phmap::parallel_flat_hash_map<Key, Value, std::hash<Key>, std::equal_to<Key>,
std::pmr::polymorphic_allocator<std::pair<const Key, Value>>>; std::pmr::polymorphic_allocator<std::pair<const Key, Value>>>;
ParallelFlatHashMap<uint32_t, uint32_t> hashMap; ParallelFlatHashMap<uint32_t, uint32_t> hashMap;
......
...@@ -55,7 +55,7 @@ public: ...@@ -55,7 +55,7 @@ public:
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
void showtime(const char *name, std::function<void ()> doit) void showtime(const char *name, const std::function<void ()>& doit)
{ {
auto t1 = std::chrono::high_resolution_clock::now(); auto t1 = std::chrono::high_resolution_clock::now();
doit(); doit();
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
#include <cstring> #include <cstring>
#include <limits> #include <limits>
#include <new> #include <new>
#include <type_traits>
#include "phmap_fwd_decl.h" #include "phmap_fwd_decl.h"
#include "phmap_base.h" #include "phmap_base.h"
...@@ -76,14 +77,6 @@ ...@@ -76,14 +77,6 @@
namespace phmap { namespace phmap {
// Defined and documented later on in this file.
template <typename T>
struct is_trivially_destructible;
// Defined and documented later on in this file.
template <typename T>
struct is_trivially_move_assignable;
namespace type_traits_internal { namespace type_traits_internal {
// Silence MSVC warnings about the destructor being defined as deleted. // Silence MSVC warnings about the destructor being defined as deleted.
...@@ -107,26 +100,26 @@ namespace phmap { ...@@ -107,26 +100,26 @@ namespace phmap {
: std::integral_constant< : std::integral_constant<
bool, std::is_move_constructible< bool, std::is_move_constructible<
type_traits_internal::SingleMemberUnion<T>>::value && type_traits_internal::SingleMemberUnion<T>>::value &&
phmap::is_trivially_destructible<T>::value> {}; std::is_trivially_destructible<T>::value> {};
template <class T> template <class T>
struct IsTriviallyCopyConstructibleObject struct IsTriviallyCopyConstructibleObject
: std::integral_constant< : std::integral_constant<
bool, std::is_copy_constructible< bool, std::is_copy_constructible<
type_traits_internal::SingleMemberUnion<T>>::value && type_traits_internal::SingleMemberUnion<T>>::value &&
phmap::is_trivially_destructible<T>::value> {}; std::is_trivially_destructible<T>::value> {};
#if 0
template <class T> template <class T>
struct IsTriviallyMoveAssignableReference : std::false_type {}; struct IsTriviallyMoveAssignableReference : std::false_type {};
template <class T> template <class T>
struct IsTriviallyMoveAssignableReference<T&> struct IsTriviallyMoveAssignableReference<T&>
: phmap::is_trivially_move_assignable<T>::type {}; : std::is_trivially_move_assignable<T>::type {};
template <class T> template <class T>
struct IsTriviallyMoveAssignableReference<T&&> struct IsTriviallyMoveAssignableReference<T&&>
: phmap::is_trivially_move_assignable<T>::type {}; : std::is_trivially_move_assignable<T>::type {};
#endif
} // namespace type_traits_internal } // namespace type_traits_internal
...@@ -155,10 +148,10 @@ namespace phmap { ...@@ -155,10 +148,10 @@ namespace phmap {
public: public:
static constexpr bool kValue = static constexpr bool kValue =
(__has_trivial_copy(ExtentsRemoved) || !kIsCopyOrMoveConstructible) && (phmap::is_trivially_copyable<ExtentsRemoved>::value || !kIsCopyOrMoveConstructible) &&
(__has_trivial_assign(ExtentsRemoved) || !kIsCopyOrMoveAssignable) && (phmap::is_trivially_copy_assignable<ExtentsRemoved>::value || !kIsCopyOrMoveAssignable) &&
(kIsCopyOrMoveConstructible || kIsCopyOrMoveAssignable) && (kIsCopyOrMoveConstructible || kIsCopyOrMoveAssignable) &&
is_trivially_destructible<ExtentsRemoved>::value && std::is_trivially_destructible<ExtentsRemoved>::value &&
// We need to check for this explicitly because otherwise we'll say // We need to check for this explicitly because otherwise we'll say
// references are trivial copyable when compiled by MSVC. // references are trivial copyable when compiled by MSVC.
!std::is_reference<ExtentsRemoved>::value; !std::is_reference<ExtentsRemoved>::value;
...@@ -744,13 +737,13 @@ namespace priv { ...@@ -744,13 +737,13 @@ namespace priv {
StringBtreeDefaultLess(std::less<std::string_view>) {} // NOLINT StringBtreeDefaultLess(std::less<std::string_view>) {} // NOLINT
StringBtreeDefaultLess(phmap::Less<std::string_view>) {} // NOLINT StringBtreeDefaultLess(phmap::Less<std::string_view>) {} // NOLINT
phmap::weak_ordering operator()(std::string_view lhs, phmap::weak_ordering operator()(const std::string_view &lhs,
std::string_view rhs) const { const std::string_view &rhs) const {
return compare_internal::compare_result_as_ordering(lhs.compare(rhs)); return compare_internal::compare_result_as_ordering(lhs.compare(rhs));
} }
#else #else
phmap::weak_ordering operator()(std::string lhs, phmap::weak_ordering operator()(const std::string &lhs,
std::string rhs) const { const std::string &rhs) const {
return compare_internal::compare_result_as_ordering(lhs.compare(rhs)); return compare_internal::compare_result_as_ordering(lhs.compare(rhs));
} }
#endif #endif
...@@ -770,8 +763,8 @@ namespace priv { ...@@ -770,8 +763,8 @@ namespace priv {
return compare_internal::compare_result_as_ordering(rhs.compare(lhs)); return compare_internal::compare_result_as_ordering(rhs.compare(lhs));
} }
#else #else
phmap::weak_ordering operator()(std::string lhs, phmap::weak_ordering operator()(const std::string &lhs,
std::string rhs) const { const std::string &rhs) const {
return compare_internal::compare_result_as_ordering(rhs.compare(lhs)); return compare_internal::compare_result_as_ordering(rhs.compare(lhs));
} }
#endif #endif
...@@ -1210,6 +1203,10 @@ namespace priv { ...@@ -1210,6 +1203,10 @@ namespace priv {
reference value(size_type i) { return params_type::element(slot(i)); } reference value(size_type i) { return params_type::element(slot(i)); }
const_reference value(size_type i) const { return params_type::element(slot(i)); } const_reference value(size_type i) const { return params_type::element(slot(i)); }
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warray-bounds"
#endif
// Getters/setter for the child at position i in the node. // Getters/setter for the child at position i in the node.
btree_node *child(size_type i) const { return GetField<3>()[i]; } btree_node *child(size_type i) const { return GetField<3>()[i]; }
btree_node *&mutable_child(size_type i) { return GetField<3>()[i]; } btree_node *&mutable_child(size_type i) { return GetField<3>()[i]; }
...@@ -1221,6 +1218,9 @@ namespace priv { ...@@ -1221,6 +1218,9 @@ namespace priv {
mutable_child(i) = c; mutable_child(i) = c;
c->set_position((field_type)i); c->set_position((field_type)i);
} }
#if defined(__GNUC__) || defined(__clang__)
#pragma GCC diagnostic pop
#endif
void init_child(int i, btree_node *c) { void init_child(int i, btree_node *c) {
set_child(i, c); set_child(i, c);
c->set_parent(this); c->set_parent(this);
...@@ -1861,7 +1861,7 @@ namespace priv { ...@@ -1861,7 +1861,7 @@ namespace priv {
void swap(btree &x); void swap(btree &x);
const key_compare &key_comp() const noexcept { const key_compare &key_comp() const noexcept {
return root_.template get<0>(); return std::get<0>(root_);
} }
template <typename K, typename LK> template <typename K, typename LK>
bool compare_keys(const K &x, const LK &y) const { bool compare_keys(const K &x, const LK &y) const {
...@@ -1954,10 +1954,10 @@ namespace priv { ...@@ -1954,10 +1954,10 @@ namespace priv {
private: private:
// Internal accessor routines. // Internal accessor routines.
node_type *root() { return root_.template get<2>(); } node_type *root() { return std::get<2>(root_); }
const node_type *root() const { return root_.template get<2>(); } const node_type *root() const { return std::get<2>(root_); }
node_type *&mutable_root() noexcept { return root_.template get<2>(); } node_type *&mutable_root() noexcept { return std::get<2>(root_); }
key_compare *mutable_key_comp() noexcept { return &root_.template get<0>(); } key_compare *mutable_key_comp() noexcept { return &std::get<0>(root_); }
// The leftmost node is stored as the parent of the root node. // The leftmost node is stored as the parent of the root node.
node_type *leftmost() { return root()->parent(); } node_type *leftmost() { return root()->parent(); }
...@@ -1965,10 +1965,10 @@ namespace priv { ...@@ -1965,10 +1965,10 @@ namespace priv {
// Allocator routines. // Allocator routines.
allocator_type *mutable_allocator() noexcept { allocator_type *mutable_allocator() noexcept {
return &root_.template get<1>(); return &std::get<1>(root_);
} }
const allocator_type &allocator() const noexcept { const allocator_type &allocator() const noexcept {
return root_.template get<1>(); return std::get<1>(root_);
} }
// Allocates a correctly aligned node of at least size bytes using the // Allocates a correctly aligned node of at least size bytes using the
...@@ -2085,8 +2085,8 @@ namespace priv { ...@@ -2085,8 +2085,8 @@ namespace priv {
void internal_clear(node_type *node); void internal_clear(node_type *node);
// Verifies the tree structure of node. // Verifies the tree structure of node.
int internal_verify(const node_type *node, size_type internal_verify(const node_type *node,
const key_type *lo, const key_type *hi) const; const key_type *lo, const key_type *hi) const;
node_stats internal_stats(const node_type *node) const { node_stats internal_stats(const node_type *node) const {
// The root can be a static empty node. // The root can be a static empty node.
...@@ -2110,11 +2110,7 @@ namespace priv { ...@@ -2110,11 +2110,7 @@ namespace priv {
} }
private: private:
// We use compressed tuple in order to save space because key_compare and std::tuple<key_compare, allocator_type, node_type *> root_;
// allocator_type are usually empty.
phmap::priv::CompressedTuple<key_compare, allocator_type,
node_type *>
root_;
// A pointer to the rightmost node. Note that the leftmost node is stored as // A pointer to the rightmost node. Note that the leftmost node is stored as
// the root's parent. // the root's parent.
...@@ -3234,7 +3230,7 @@ namespace priv { ...@@ -3234,7 +3230,7 @@ namespace priv {
} }
template <typename P> template <typename P>
int btree<P>::internal_verify( typename btree<P>::size_type btree<P>::internal_verify(
const node_type *node, const key_type *lo, const key_type *hi) const { const node_type *node, const key_type *lo, const key_type *hi) const {
assert(node->count() > 0); assert(node->count() > 0);
assert(node->count() <= node->max_count()); assert(node->count() <= node->max_count());
...@@ -3247,7 +3243,7 @@ namespace priv { ...@@ -3247,7 +3243,7 @@ namespace priv {
for (int i = 1; i < node->count(); ++i) { for (int i = 1; i < node->count(); ++i) {
assert(!compare_keys(node->key(i), node->key(i - 1))); assert(!compare_keys(node->key(i), node->key(i - 1)));
} }
int count = node->count(); size_type count = node->count();
if (!node->leaf()) { if (!node->leaf()) {
for (int i = 0; i <= node->count(); ++i) { for (int i = 0; i <= node->count(); ++i) {
assert(node->child(i) != nullptr); assert(node->child(i) != nullptr);
...@@ -3325,8 +3321,8 @@ namespace priv { ...@@ -3325,8 +3321,8 @@ namespace priv {
// ---------------- // ----------------
template <typename K = key_type> template <typename K = key_type>
size_type count(const key_arg<K> &key) const { size_type count(const key_arg<K> &key) const {
auto equal_range = this->equal_range(key); auto er = this->equal_range(key);
return std::distance(equal_range.first, equal_range.second); return std::distance(er.first, er.second);
} }
template <typename K = key_type> template <typename K = key_type>
iterator find(const key_arg<K> &key) { iterator find(const key_arg<K> &key) {
...@@ -3366,8 +3362,8 @@ namespace priv { ...@@ -3366,8 +3362,8 @@ namespace priv {
} }
template <typename K = key_type> template <typename K = key_type>
size_type erase(const key_arg<K> &key) { size_type erase(const key_arg<K> &key) {
auto equal_range = this->equal_range(key); auto er = this->equal_range(key);
return tree_.erase_range(equal_range.first, equal_range.second).first; return tree_.erase_range(er.first, er.second).first;
} }
node_type extract(iterator position) { node_type extract(iterator position) {
// Use Move instead of Transfer, because the rebalancing code expects to // Use Move instead of Transfer, because the rebalancing code expects to
......
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from conans import ConanFile, tools
import os
class SparseppConan(ConanFile):
name = "parallel_hashmap"
version = "1.34"
description = "A header-only, very fast and memory-friendly hash map"
url = "https://github.com/greg7mdp/parallel-hashmap/blob/master/parallel_hashmap/conanfile.py"
# Indicates License type of the packaged library
license = "https://github.com/greg7mdp/parallel-hashmap/blob/master/LICENSE"
# Packages the license for the conanfile.py
exports = ["LICENSE"]
# Custom attributes for Bincrafters recipe conventions
source_subfolder = "source_subfolder"
def source(self):
source_url = "https://github.com/greg7mdp/parallel-hashmap"
tools.get("{0}/archive/{1}.tar.gz".format(source_url, self.version))
extracted_dir = self.name + "-" + self.version
#Rename to "source_folder" is a convention to simplify later steps
os.rename(extracted_dir, self.source_subfolder)
def package(self):
include_folder = os.path.join(self.source_subfolder, "parallel_hashmap")
self.copy(pattern="LICENSE")
self.copy(pattern="*", dst="include/parallel_hashmap", src=include_folder)
def package_id(self):
self.info.header_only()
...@@ -270,31 +270,31 @@ inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } ...@@ -270,31 +270,31 @@ inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
namespace phmap { namespace phmap {
namespace base_internal { namespace base_internal {
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) { PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64Slow(uint64_t n) {
int zeroes = 60; int zeroes = 60;
if (n >> 32) zeroes -= 32, n >>= 32; if (n >> 32) zeroes -= 32, n >>= 32;
if (n >> 16) zeroes -= 16, n >>= 16; if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8; if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4; 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; return (uint32_t)("\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes);
} }
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) { PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64) #if defined(_MSC_VER) && defined(_M_X64)
// MSVC does not have __buitin_clzll. Use _BitScanReverse64. // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse64(&result, n)) { if (_BitScanReverse64(&result, n)) {
return (int)(63 - result); return (uint32_t)(63 - result);
} }
return 64; return 64;
#elif defined(_MSC_VER) && !defined(__clang__) #elif defined(_MSC_VER) && !defined(__clang__)
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if ((n >> 32) && _BitScanReverse(&result, (unsigned long)(n >> 32))) { if ((n >> 32) && _BitScanReverse(&result, (unsigned long)(n >> 32))) {
return 31 - result; return (uint32_t)(31 - result);
} }
if (_BitScanReverse(&result, (unsigned long)n)) { if (_BitScanReverse(&result, (unsigned long)n)) {
return 63 - result; return (uint32_t)(63 - result);
} }
return 64; return 64;
#elif defined(__GNUC__) || defined(__clang__) #elif defined(__GNUC__) || defined(__clang__)
...@@ -309,7 +309,7 @@ PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) { ...@@ -309,7 +309,7 @@ PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
if (n == 0) { if (n == 0) {
return 64; return 64;
} }
return __builtin_clzll(n); return (uint32_t)__builtin_clzll(n);
#else #else
return CountLeadingZeros64Slow(n); return CountLeadingZeros64Slow(n);
#endif #endif
......
...@@ -272,31 +272,31 @@ inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); } ...@@ -272,31 +272,31 @@ inline void UnalignedStore64(void *p, uint64_t v) { memcpy(p, &v, sizeof v); }
namespace phmap { namespace phmap {
namespace base_internal { namespace base_internal {
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64Slow(uint64_t n) { PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64Slow(uint64_t n) {
int zeroes = 60; int zeroes = 60;
if (n >> 32) zeroes -= 32, n >>= 32; if (n >> 32) zeroes -= 32, n >>= 32;
if (n >> 16) zeroes -= 16, n >>= 16; if (n >> 16) zeroes -= 16, n >>= 16;
if (n >> 8) zeroes -= 8, n >>= 8; if (n >> 8) zeroes -= 8, n >>= 8;
if (n >> 4) zeroes -= 4, n >>= 4; 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; return (uint32_t)("\4\3\2\2\1\1\1\1\0\0\0\0\0\0\0"[n] + zeroes);
} }
PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) { PHMAP_BASE_INTERNAL_FORCEINLINE uint32_t CountLeadingZeros64(uint64_t n) {
#if defined(_MSC_VER) && defined(_M_X64) #if defined(_MSC_VER) && defined(_M_X64)
// MSVC does not have __buitin_clzll. Use _BitScanReverse64. // MSVC does not have __buitin_clzll. Use _BitScanReverse64.
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if (_BitScanReverse64(&result, n)) { if (_BitScanReverse64(&result, n)) {
return (int)(63 - result); return (uint32_t)(63 - result);
} }
return 64; return 64;
#elif defined(_MSC_VER) && !defined(__clang__) #elif defined(_MSC_VER) && !defined(__clang__)
// MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse // MSVC does not have __buitin_clzll. Compose two calls to _BitScanReverse
unsigned long result = 0; // NOLINT(runtime/int) unsigned long result = 0; // NOLINT(runtime/int)
if ((n >> 32) && _BitScanReverse(&result, (unsigned long)(n >> 32))) { if ((n >> 32) && _BitScanReverse(&result, (unsigned long)(n >> 32))) {
return 31 - result; return (uint32_t)(31 - result);
} }
if (_BitScanReverse(&result, (unsigned long)n)) { if (_BitScanReverse(&result, (unsigned long)n)) {
return 63 - result; return (uint32_t)(63 - result);
} }
return 64; return 64;
#elif defined(__GNUC__) || defined(__clang__) #elif defined(__GNUC__) || defined(__clang__)
...@@ -311,7 +311,7 @@ PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) { ...@@ -311,7 +311,7 @@ PHMAP_BASE_INTERNAL_FORCEINLINE int CountLeadingZeros64(uint64_t n) {
if (n == 0) { if (n == 0) {
return 64; return 64;
} }
return __builtin_clzll(n); return (uint32_t)__builtin_clzll(n);
#else #else
return CountLeadingZeros64Slow(n); return CountLeadingZeros64Slow(n);
#endif #endif
......
...@@ -35,8 +35,8 @@ ...@@ -35,8 +35,8 @@
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
#define PHMAP_VERSION_MAJOR 1 #define PHMAP_VERSION_MAJOR 1
#define PHMAP_VERSION_MINOR 0 #define PHMAP_VERSION_MINOR 3
#define PHMAP_VERSION_PATCH 0 #define PHMAP_VERSION_PATCH 12
// Included for the __GLIBC__ macro (or similar macros on other systems). // Included for the __GLIBC__ macro (or similar macros on other systems).
#include <limits.h> #include <limits.h>
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
#endif #endif
#if CHAR_BIT != 8 #if CHAR_BIT != 8
#error "phmap assumes CHAR_BIT == 8." #warning "phmap assumes CHAR_BIT == 8."
#endif #endif
// phmap currently assumes that an int is 4 bytes. // phmap currently assumes that an int is 4 bytes.
...@@ -120,7 +120,8 @@ ...@@ -120,7 +120,8 @@
#define PHMAP_HAVE_BUILTIN(x) 0 #define PHMAP_HAVE_BUILTIN(x) 0
#endif #endif
#if (defined(_MSVC_LANG) && _MSVC_LANG >= 201703) || __cplusplus >= 201703 #if (!defined(__GNUC__) || defined(__clang__) || __GNUC__ >= 5) && \
((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L)
#define PHMAP_HAVE_CC17 1 #define PHMAP_HAVE_CC17 1
#else #else
#define PHMAP_HAVE_CC17 0 #define PHMAP_HAVE_CC17 0
...@@ -148,40 +149,13 @@ ...@@ -148,40 +149,13 @@
#define PHMAP_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0 #define PHMAP_INTERNAL_HAVE_MIN_CLANG_VERSION(x, y) 0
#endif #endif
// ----------------------------------------------------------------
// Checks whether `std::is_trivially_destructible<T>` is supported.
// ----------------------------------------------------------------
#ifdef PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE
#error PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE cannot be directly set
#elif defined(_LIBCPP_VERSION) || defined(_MSC_VER) || \
(!defined(__clang__) && defined(__GNUC__) && defined(__GLIBCXX__) && PHMAP_INTERNAL_HAVE_MIN_GNUC_VERSION(4, 8))
#define PHMAP_HAVE_STD_IS_TRIVIALLY_DESTRUCTIBLE 1
#endif
// --------------------------------------------------------------
// Checks whether `std::is_trivially_default_constructible<T>` is
// supported.
// --------------------------------------------------------------
#if defined(PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE)
#error PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE cannot be directly set
#elif defined(PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE)
#error PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE cannot directly set
#elif (defined(__clang__) && defined(_LIBCPP_VERSION)) || \
(!defined(__clang__) && defined(__GNUC__) && \
PHMAP_INTERNAL_HAVE_MIN_GNUC_VERSION(5, 1) && \
(defined(_LIBCPP_VERSION) || defined(__GLIBCXX__))) || \
(defined(_MSC_VER) && !defined(__NVCC__))
#define PHMAP_HAVE_STD_IS_TRIVIALLY_CONSTRUCTIBLE 1
#define PHMAP_HAVE_STD_IS_TRIVIALLY_ASSIGNABLE 1
#endif
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Checks whether C++11's `thread_local` storage duration specifier is // Checks whether C++11's `thread_local` storage duration specifier is
// supported. // supported.
// ------------------------------------------------------------------- // -------------------------------------------------------------------
#ifdef PHMAP_HAVE_THREAD_LOCAL #ifdef PHMAP_HAVE_THREAD_LOCAL
#error PHMAP_HAVE_THREAD_LOCAL cannot be directly set #error PHMAP_HAVE_THREAD_LOCAL cannot be directly set
#elif defined(__APPLE__) #elif defined(__APPLE__) && defined(__clang__)
#if __has_feature(cxx_thread_local) && \ #if __has_feature(cxx_thread_local) && \
!(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0) !(TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_9_0)
#define PHMAP_HAVE_THREAD_LOCAL 1 #define PHMAP_HAVE_THREAD_LOCAL 1
...@@ -341,7 +315,11 @@ ...@@ -341,7 +315,11 @@
#endif #endif
#if PHMAP_HAVE_CC17 #if PHMAP_HAVE_CC17
#define PHMAP_HAVE_SHARED_MUTEX 1 #ifdef __has_include
#if __has_include(<shared_mutex>)
#define PHMAP_HAVE_SHARED_MUTEX 1
#endif
#endif
#endif #endif
#ifndef PHMAP_HAVE_STD_STRING_VIEW #ifndef PHMAP_HAVE_STD_STRING_VIEW
...@@ -672,6 +650,15 @@ ...@@ -672,6 +650,15 @@
#define PHMAP_IF_CONSTEXPR(expr) if ((expr)) #define PHMAP_IF_CONSTEXPR(expr) if ((expr))
#endif #endif
// ----------------------------------------------------------------------
// builtin unreachable
// ----------------------------------------------------------------------
#if PHMAP_HAVE_BUILTIN(__builtin_unreachable)
#define PHMAP_BUILTIN_UNREACHABLE() __builtin_unreachable()
#else
#define PHMAP_BUILTIN_UNREACHABLE() (void)0
#endif
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
// base/macros.h // base/macros.h
// ---------------------------------------------------------------------- // ----------------------------------------------------------------------
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment