/src/parallel-hashmap/parallel_hashmap/phmap_dump.h
Line | Count | Source |
1 | | #if !defined(phmap_dump_h_guard_) |
2 | | #define phmap_dump_h_guard_ |
3 | | |
4 | | // --------------------------------------------------------------------------- |
5 | | // Copyright (c) 2019, Gregory Popovitch - greg7mdp@gmail.com |
6 | | // |
7 | | // providing dump/load/mmap_load |
8 | | // |
9 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
10 | | // you may not use this file except in compliance with the License. |
11 | | // You may obtain a copy of the License at |
12 | | // |
13 | | // https://www.apache.org/licenses/LICENSE-2.0 |
14 | | // |
15 | | // Unless required by applicable law or agreed to in writing, software |
16 | | // distributed under the License is distributed on an "AS IS" BASIS, |
17 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
18 | | // See the License for the specific language governing permissions and |
19 | | // limitations under the License. |
20 | | // --------------------------------------------------------------------------- |
21 | | |
22 | | #include <iostream> |
23 | | #include <fstream> |
24 | | #include <sstream> |
25 | | #include "phmap.h" |
26 | | namespace phmap |
27 | | { |
28 | | |
29 | | namespace type_traits_internal { |
30 | | |
31 | | #if defined(__GLIBCXX__) && __GLIBCXX__ < 20150801 |
32 | | template<typename T> struct IsTriviallyCopyable : public std::integral_constant<bool, __has_trivial_copy(T)> {}; |
33 | | #else |
34 | | template<typename T> struct IsTriviallyCopyable : public std::is_trivially_copyable<T> {}; |
35 | | #endif |
36 | | |
37 | | template <class T1, class T2> |
38 | | struct IsTriviallyCopyable<std::pair<T1, T2>> { |
39 | | static constexpr bool value = IsTriviallyCopyable<T1>::value && IsTriviallyCopyable<T2>::value; |
40 | | }; |
41 | | } |
42 | | |
43 | | namespace priv { |
44 | | |
45 | | #if !defined(PHMAP_NON_DETERMINISTIC) && !defined(PHMAP_DISABLE_DUMP) |
46 | | |
47 | | static constexpr size_t s_version_base = std::numeric_limits<size_t>::max() - 10; |
48 | | static constexpr size_t s_version = s_version_base; |
49 | | // ------------------------------------------------------------------------ |
50 | | // dump/load for raw_hash_set |
51 | | // ------------------------------------------------------------------------ |
52 | | template <class Policy, class Hash, class Eq, class Alloc> |
53 | | template<typename OutputArchive> |
54 | 485 | bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_dump(OutputArchive& ar) const { |
55 | 485 | static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value, |
56 | 485 | "value_type should be trivially copyable"); |
57 | | |
58 | 485 | ar.saveBinary(&s_version, sizeof(size_t)); |
59 | 485 | ar.saveBinary(&size_, sizeof(size_t)); |
60 | 485 | ar.saveBinary(&capacity_, sizeof(size_t)); |
61 | 485 | if (size_ == 0) |
62 | 35 | return true; |
63 | 450 | ar.saveBinary(ctrl_, sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1)); |
64 | 450 | ar.saveBinary(slots_, sizeof(slot_type) * capacity_); |
65 | 450 | ar.saveBinary(&growth_left(), sizeof(size_t)); |
66 | 450 | return true; |
67 | 485 | } |
68 | | |
69 | | template <class Policy, class Hash, class Eq, class Alloc> |
70 | | template<typename InputArchive> |
71 | 485 | bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_load(InputArchive& ar) { |
72 | 485 | static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value, |
73 | 485 | "value_type should be trivially copyable"); |
74 | 485 | raw_hash_set<Policy, Hash, Eq, Alloc>().swap(*this); // clear any existing content |
75 | | |
76 | 485 | size_t version = 0; |
77 | 485 | ar.loadBinary(&version, sizeof(size_t)); |
78 | 485 | if (version < s_version_base) { |
79 | | // we didn't store the version, version actually contains the size |
80 | 361 | size_ = version; |
81 | 361 | } else { |
82 | 124 | ar.loadBinary(&size_, sizeof(size_t)); |
83 | 124 | } |
84 | 485 | ar.loadBinary(&capacity_, sizeof(size_t)); |
85 | | |
86 | 485 | if (capacity_) { |
87 | | // allocate memory for ctrl_ and slots_ |
88 | 124 | initialize_slots(capacity_); |
89 | 124 | } |
90 | 485 | if (size_ == 0) |
91 | 361 | return true; |
92 | 124 | ar.loadBinary(ctrl_, sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1)); |
93 | 124 | ar.loadBinary(slots_, sizeof(slot_type) * capacity_); |
94 | 124 | if (version >= s_version_base) { |
95 | | // growth_left should be restored after calling initialize_slots() which resets it. |
96 | 124 | ar.loadBinary(&growth_left(), sizeof(size_t)); |
97 | 124 | } |
98 | 124 | return true; |
99 | 485 | } |
100 | | |
101 | | // ------------------------------------------------------------------------ |
102 | | // dump/load for parallel_hash_set |
103 | | // ------------------------------------------------------------------------ |
104 | | template <size_t N, |
105 | | template <class, class, class, class> class RefSet, |
106 | | class Mtx_, |
107 | | class Policy, class Hash, class Eq, class Alloc> |
108 | | template<typename OutputArchive> |
109 | | bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::phmap_dump(OutputArchive& ar) const { |
110 | | static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value, |
111 | | "value_type should be trivially copyable"); |
112 | | |
113 | | size_t submap_count = subcnt(); |
114 | | ar.saveBinary(&submap_count, sizeof(size_t)); |
115 | | for (size_t i = 0; i < sets_.size(); ++i) { |
116 | | auto& inner = sets_[i]; |
117 | | typename Lockable::UniqueLock m(const_cast<Inner&>(inner)); |
118 | | if (!inner.set_.phmap_dump(ar)) { |
119 | | std::cerr << "Failed to dump submap " << i << std::endl; |
120 | | return false; |
121 | | } |
122 | | } |
123 | | return true; |
124 | | } |
125 | | |
126 | | template <size_t N, |
127 | | template <class, class, class, class> class RefSet, |
128 | | class Mtx_, |
129 | | class Policy, class Hash, class Eq, class Alloc> |
130 | | template<typename InputArchive> |
131 | | bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::phmap_load(InputArchive& ar) { |
132 | | static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value, |
133 | | "value_type should be trivially copyable"); |
134 | | |
135 | | size_t submap_count = 0; |
136 | | ar.loadBinary(&submap_count, sizeof(size_t)); |
137 | | if (submap_count != subcnt()) { |
138 | | std::cerr << "submap count(" << submap_count << ") != N(" << N << ")" << std::endl; |
139 | | return false; |
140 | | } |
141 | | |
142 | | for (size_t i = 0; i < submap_count; ++i) { |
143 | | auto& inner = sets_[i]; |
144 | | typename Lockable::UniqueLock m(const_cast<Inner&>(inner)); |
145 | | if (!inner.set_.phmap_load(ar)) { |
146 | | std::cerr << "Failed to load submap " << i << std::endl; |
147 | | return false; |
148 | | } |
149 | | } |
150 | | return true; |
151 | | } |
152 | | |
153 | | #endif // !defined(PHMAP_NON_DETERMINISTIC) && !defined(PHMAP_DISABLE_DUMP) |
154 | | |
155 | | } // namespace priv |
156 | | |
157 | | |
158 | | |
159 | | // ------------------------------------------------------------------------ |
160 | | // BinaryArchive |
161 | | // File is closed when archive object is destroyed |
162 | | // ------------------------------------------------------------------------ |
163 | | |
164 | | // ------------------------------------------------------------------------ |
165 | | // ------------------------------------------------------------------------ |
166 | | class BinaryOutputArchive { |
167 | | public: |
168 | 485 | BinaryOutputArchive(const char *file_path) { |
169 | 485 | ofs_.open(file_path, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary); |
170 | 485 | } |
171 | | |
172 | 2.80k | bool saveBinary(const void *p, size_t sz) { |
173 | 2.80k | ofs_.write(reinterpret_cast<const char*>(p), sz); |
174 | 2.80k | return true; |
175 | 2.80k | } |
176 | | |
177 | | template<typename V> |
178 | | typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type |
179 | | saveBinary(const V& v) { |
180 | | ofs_.write(reinterpret_cast<const char *>(&v), sizeof(V)); |
181 | | return true; |
182 | | } |
183 | | |
184 | | template<typename Map> |
185 | | auto saveBinary(const Map& v) -> decltype(v.phmap_dump(*this), bool()) |
186 | | { |
187 | | return v.phmap_dump(*this); |
188 | | } |
189 | | |
190 | | private: |
191 | | std::ofstream ofs_; |
192 | | }; |
193 | | |
194 | | |
195 | | class BinaryInputArchive { |
196 | | public: |
197 | 485 | BinaryInputArchive(const char * file_path) { |
198 | 485 | ifs_.open(file_path, std::ofstream::in | std::ofstream::binary); |
199 | 485 | } |
200 | | |
201 | 1.46k | bool loadBinary(void* p, size_t sz) { |
202 | 1.46k | ifs_.read(reinterpret_cast<char*>(p), sz); |
203 | 1.46k | return true; |
204 | 1.46k | } |
205 | | |
206 | | template<typename V> |
207 | | typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type |
208 | | loadBinary(V* v) { |
209 | | ifs_.read(reinterpret_cast<char *>(v), sizeof(V)); |
210 | | return true; |
211 | | } |
212 | | |
213 | | template<typename Map> |
214 | | auto loadBinary(Map* v) -> decltype(v->phmap_load(*this), bool()) |
215 | | { |
216 | | return v->phmap_load(*this); |
217 | | } |
218 | | |
219 | | private: |
220 | | std::ifstream ifs_; |
221 | | }; |
222 | | |
223 | | } // namespace phmap |
224 | | |
225 | | |
226 | | #ifdef CEREAL_SIZE_TYPE |
227 | | |
228 | | template <class T> |
229 | | using PhmapTrivCopyable = typename phmap::type_traits_internal::IsTriviallyCopyable<T>; |
230 | | |
231 | | namespace cereal |
232 | | { |
233 | | // Overload Cereal serialization code for phmap::flat_hash_map |
234 | | // ----------------------------------------------------------- |
235 | | template <class K, class V, class Hash, class Eq, class A> |
236 | | void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar, |
237 | | phmap::flat_hash_map<K, V, Hash, Eq, A> const &hmap) |
238 | | { |
239 | | hmap.phmap_dump(ar); |
240 | | } |
241 | | |
242 | | template <class K, class V, class Hash, class Eq, class A> |
243 | | void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar, |
244 | | phmap::flat_hash_map<K, V, Hash, Eq, A> &hmap) |
245 | | { |
246 | | hmap.phmap_load(ar); |
247 | | } |
248 | | |
249 | | |
250 | | // Overload Cereal serialization code for phmap::parallel_flat_hash_map |
251 | | // -------------------------------------------------------------------- |
252 | | template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_> |
253 | | void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar, |
254 | | phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_> const &hmap) |
255 | | { |
256 | | hmap.phmap_dump(ar); |
257 | | } |
258 | | |
259 | | template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_> |
260 | | void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar, |
261 | | phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_> &hmap) |
262 | | { |
263 | | hmap.phmap_load(ar); |
264 | | } |
265 | | |
266 | | // Overload Cereal serialization code for phmap::flat_hash_set |
267 | | // ----------------------------------------------------------- |
268 | | template <class K, class Hash, class Eq, class A> |
269 | | void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar, |
270 | | phmap::flat_hash_set<K, Hash, Eq, A> const &hset) |
271 | | { |
272 | | hset.phmap_dump(ar); |
273 | | } |
274 | | |
275 | | template <class K, class Hash, class Eq, class A> |
276 | | void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar, |
277 | | phmap::flat_hash_set<K, Hash, Eq, A> &hset) |
278 | | { |
279 | | hset.phmap_load(ar); |
280 | | } |
281 | | |
282 | | // Overload Cereal serialization code for phmap::parallel_flat_hash_set |
283 | | // -------------------------------------------------------------------- |
284 | | template <class K, class Hash, class Eq, class A, size_t N, class Mtx_> |
285 | | void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar, |
286 | | phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_> const &hset) |
287 | | { |
288 | | hset.phmap_dump(ar); |
289 | | } |
290 | | |
291 | | template <class K, class Hash, class Eq, class A, size_t N, class Mtx_> |
292 | | void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar, |
293 | | phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_> &hset) |
294 | | { |
295 | | hset.phmap_load(ar); |
296 | | } |
297 | | } |
298 | | |
299 | | #endif |
300 | | |
301 | | |
302 | | |
303 | | |
304 | | #endif // phmap_dump_h_guard_ |