Coverage Report

Created: 2025-07-11 07:01

/src/parallel-hashmap/parallel_hashmap/phmap_dump.h
Line
Count
Source (jump to first uncovered line)
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 <functional>
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
483
bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_dump(OutputArchive& ar) const {
55
483
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
56
483
                    "value_type should be trivially copyable");
57
58
483
    ar.saveBinary(&s_version, sizeof(size_t));
59
483
    ar.saveBinary(&size_, sizeof(size_t));
60
483
    ar.saveBinary(&capacity_, sizeof(size_t));
61
483
    if (size_ == 0)
62
32
        return true;
63
451
    ar.saveBinary(ctrl_,  sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1));
64
451
    ar.saveBinary(slots_, sizeof(slot_type) * capacity_);
65
451
    ar.saveBinary(&growth_left(), sizeof(size_t));
66
451
    return true;
67
483
}
68
69
template <class Policy, class Hash, class Eq, class Alloc>
70
template<typename InputArchive>
71
483
bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_load(InputArchive& ar) {
72
483
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
73
483
                    "value_type should be trivially copyable");
74
483
    raw_hash_set<Policy, Hash, Eq, Alloc>().swap(*this); // clear any existing content
75
76
483
    size_t version = 0;
77
483
    ar.loadBinary(&version, sizeof(size_t));
78
483
    if (version < s_version_base) {
79
        // we didn't store the version, version actually contains the size
80
360
        size_ = version;
81
360
    } else {
82
123
        ar.loadBinary(&size_, sizeof(size_t));
83
123
    }
84
483
    ar.loadBinary(&capacity_, sizeof(size_t));
85
86
483
    if (capacity_) {
87
        // allocate memory for ctrl_ and slots_
88
123
        initialize_slots(capacity_);
89
123
    }
90
483
    if (size_ == 0)
91
360
        return true;
92
123
    ar.loadBinary(ctrl_,  sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1));
93
123
    ar.loadBinary(slots_, sizeof(slot_type) * capacity_);
94
123
    if (version >= s_version_base) {
95
        // growth_left should be restored after calling initialize_slots() which resets it.
96
123
        ar.loadBinary(&growth_left(), sizeof(size_t));
97
123
    } else {
98
0
       drop_deletes_without_resize();
99
0
    }
100
123
    return true;
101
483
}
102
103
// ------------------------------------------------------------------------
104
// dump/load for parallel_hash_set
105
// ------------------------------------------------------------------------
106
template <size_t N,
107
          template <class, class, class, class> class RefSet,
108
          class Mtx_,
109
          class Policy, class Hash, class Eq, class Alloc>
110
template<typename OutputArchive>
111
bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::phmap_dump(OutputArchive& ar) const {
112
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
113
                  "value_type should be trivially copyable");
114
115
    size_t submap_count = subcnt();
116
    ar.saveBinary(&submap_count, sizeof(size_t));
117
    for (size_t i = 0; i < sets_.size(); ++i) {
118
        auto& inner = sets_[i];
119
        typename Lockable::UniqueLock m(const_cast<Inner&>(inner));
120
        if (!inner.set_.phmap_dump(ar)) {
121
            std::cerr << "Failed to dump submap " << i << std::endl;
122
            return false;
123
        }
124
    }
125
    return true;
126
}
127
128
template <size_t N,
129
          template <class, class, class, class> class RefSet,
130
          class Mtx_,
131
          class Policy, class Hash, class Eq, class Alloc>
132
template<typename InputArchive>
133
bool parallel_hash_set<N, RefSet, Mtx_, Policy, Hash, Eq, Alloc>::phmap_load(InputArchive& ar) {
134
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
135
                  "value_type should be trivially copyable");
136
137
    size_t submap_count = 0;
138
    ar.loadBinary(&submap_count, sizeof(size_t));
139
    if (submap_count != subcnt()) {
140
        std::cerr << "submap count(" << submap_count << ") != N(" << N << ")" << std::endl;
141
        return false;
142
    }
143
144
    for (size_t i = 0; i < submap_count; ++i) {            
145
        auto& inner = sets_[i];
146
        typename Lockable::UniqueLock m(const_cast<Inner&>(inner));
147
        if (!inner.set_.phmap_load(ar)) {
148
            std::cerr << "Failed to load submap " << i << std::endl;
149
            return false;
150
        }
151
    }
152
    return true;
153
}
154
155
#endif // !defined(PHMAP_NON_DETERMINISTIC) && !defined(PHMAP_DISABLE_DUMP)
156
157
} // namespace priv
158
159
160
161
// ------------------------------------------------------------------------
162
// BinaryArchive
163
//       File is closed when archive object is destroyed
164
// ------------------------------------------------------------------------
165
166
// ------------------------------------------------------------------------
167
// ------------------------------------------------------------------------
168
class BinaryOutputArchive {
169
public:
170
483
    BinaryOutputArchive(const char *file_path) {
171
483
      os_ = new std::ofstream(file_path, std::ofstream::out |
172
483
                                             std::ofstream::trunc |
173
483
                                             std::ofstream::binary);
174
483
      destruct_ = [this]() { delete os_; };
175
483
    }
176
177
0
    BinaryOutputArchive(std::ostream &os) : os_(&os) {}
178
179
483
    ~BinaryOutputArchive() {
180
483
        if (destruct_) {
181
483
            destruct_();
182
483
        }
183
483
    }
184
    
185
    BinaryOutputArchive(const BinaryOutputArchive&) = delete;
186
    BinaryOutputArchive& operator=(const BinaryOutputArchive&) = delete;
187
188
2.80k
    bool saveBinary(const void *p, size_t sz) {
189
2.80k
        os_->write(reinterpret_cast<const char*>(p), (std::streamsize)sz);
190
2.80k
        return true;
191
2.80k
    }
192
193
    template<typename V>
194
    typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
195
    saveBinary(const V& v) {
196
        os_->write(reinterpret_cast<const char *>(&v), sizeof(V));
197
        return true;
198
    }
199
200
    template<typename Map>
201
    auto saveBinary(const Map& v) -> decltype(v.phmap_dump(*this), bool())
202
    {
203
        return v.phmap_dump(*this);
204
    }
205
206
private:
207
    std::ostream* os_;
208
    std::function<void()> destruct_;
209
};
210
211
212
class BinaryInputArchive {
213
public:
214
483
    BinaryInputArchive(const char * file_path) {
215
483
      is_ = new std::ifstream(file_path,
216
483
                              std::ifstream::in | std::ifstream::binary);
217
483
      destruct_ = [this]() { delete is_; };
218
483
    }
219
220
0
    BinaryInputArchive(std::istream& is) : is_(&is) {}
221
    
222
483
    ~BinaryInputArchive() {
223
483
        if (destruct_) {
224
483
            destruct_();
225
483
        }
226
483
    }
227
228
    BinaryInputArchive(const BinaryInputArchive&) = delete;
229
    BinaryInputArchive& operator=(const BinaryInputArchive&) = delete;
230
231
1.45k
    bool loadBinary(void* p, size_t sz) {
232
1.45k
        is_->read(reinterpret_cast<char*>(p),  (std::streamsize)sz);
233
1.45k
        return true;
234
1.45k
    }
235
236
    template<typename V>
237
    typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
238
    loadBinary(V* v) {
239
        is_->read(reinterpret_cast<char *>(v), sizeof(V));
240
        return true;
241
    }
242
243
    template<typename Map>
244
    auto loadBinary(Map* v) -> decltype(v->phmap_load(*this), bool())
245
    {
246
        return v->phmap_load(*this);
247
    }
248
    
249
private:
250
    std::istream* is_;
251
    std::function<void()> destruct_;
252
};
253
254
} // namespace phmap
255
256
257
#ifdef CEREAL_SIZE_TYPE
258
259
template <class T>
260
using PhmapTrivCopyable = typename phmap::type_traits_internal::IsTriviallyCopyable<T>;
261
    
262
namespace cereal
263
{
264
    // Overload Cereal serialization code for phmap::flat_hash_map
265
    // -----------------------------------------------------------
266
    template <class K, class V, class Hash, class Eq, class A>
267
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar,
268
              phmap::flat_hash_map<K, V, Hash, Eq, A> const &hmap)
269
    {
270
        hmap.phmap_dump(ar);
271
    }
272
273
    template <class K, class V, class Hash, class Eq, class A>
274
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar, 
275
              phmap::flat_hash_map<K, V, Hash, Eq, A>  &hmap)
276
    {
277
        hmap.phmap_load(ar);
278
    }
279
280
281
    // Overload Cereal serialization code for phmap::parallel_flat_hash_map
282
    // --------------------------------------------------------------------
283
    template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_>
284
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar,
285
              phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_> const &hmap)
286
    {
287
        hmap.phmap_dump(ar);
288
    }
289
290
    template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_>
291
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar, 
292
              phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_>  &hmap)
293
    {
294
        hmap.phmap_load(ar);
295
    }
296
297
    // Overload Cereal serialization code for phmap::flat_hash_set
298
    // -----------------------------------------------------------
299
    template <class K, class Hash, class Eq, class A>
300
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar,
301
              phmap::flat_hash_set<K, Hash, Eq, A> const &hset)
302
    {
303
        hset.phmap_dump(ar);
304
    }
305
306
    template <class K, class Hash, class Eq, class A>
307
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar, 
308
              phmap::flat_hash_set<K, Hash, Eq, A>  &hset)
309
    {
310
        hset.phmap_load(ar);
311
    }
312
313
    // Overload Cereal serialization code for phmap::parallel_flat_hash_set
314
    // --------------------------------------------------------------------
315
    template <class K, class Hash, class Eq, class A, size_t N, class Mtx_>
316
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar,
317
              phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_> const &hset)
318
    {
319
        hset.phmap_dump(ar);
320
    }
321
322
    template <class K, class Hash, class Eq, class A, size_t N, class Mtx_>
323
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar, 
324
              phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_>  &hset)
325
    {
326
        hset.phmap_load(ar);
327
    }
328
}
329
330
#endif
331
332
333
334
335
#endif // phmap_dump_h_guard_