| #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 <functional> |
| #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 type_traits_internal |
| |
| 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)); |
| } else { |
| drop_deletes_without_resize(); |
| } |
| 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) { |
| os_ = new std::ofstream(file_path, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); |
| destruct_ = [this]() { delete os_; }; |
| } |
| |
| BinaryOutputArchive(std::ostream &os) : os_(&os) {} |
| |
| ~BinaryOutputArchive() { |
| if (destruct_) { |
| destruct_(); |
| } |
| } |
| |
| BinaryOutputArchive(const BinaryOutputArchive &) = delete; |
| BinaryOutputArchive &operator=(const BinaryOutputArchive &) = delete; |
| |
| bool saveBinary(const void *p, size_t sz) { |
| os_->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) { |
| os_->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::ostream *os_; |
| std::function<void()> destruct_; |
| }; |
| |
| class BinaryInputArchive { |
| public: |
| BinaryInputArchive(const char *file_path) { |
| is_ = new std::ifstream(file_path, std::ifstream::in | std::ifstream::binary); |
| destruct_ = [this]() { delete is_; }; |
| } |
| |
| BinaryInputArchive(std::istream &is) : is_(&is) {} |
| |
| ~BinaryInputArchive() { |
| if (destruct_) { |
| destruct_(); |
| } |
| } |
| |
| BinaryInputArchive(const BinaryInputArchive &) = delete; |
| BinaryInputArchive &operator=(const BinaryInputArchive &) = delete; |
| |
| bool loadBinary(void *p, size_t sz) { |
| is_->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) { |
| is_->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::istream *is_; |
| std::function<void()> destruct_; |
| }; |
| |
| } // 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); |
| } |
| } // namespace cereal |
| |
| #endif |
| |
| #endif // phmap_dump_h_guard_ |