Coverage Report

Created: 2024-07-27 06:04

/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
506
bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_dump(OutputArchive& ar) const {
55
506
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
56
506
                    "value_type should be trivially copyable");
57
58
506
    ar.saveBinary(&s_version, sizeof(size_t));
59
506
    ar.saveBinary(&size_, sizeof(size_t));
60
506
    ar.saveBinary(&capacity_, sizeof(size_t));
61
506
    if (size_ == 0)
62
36
        return true;
63
470
    ar.saveBinary(ctrl_,  sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1));
64
470
    ar.saveBinary(slots_, sizeof(slot_type) * capacity_);
65
470
    ar.saveBinary(&growth_left(), sizeof(size_t));
66
470
    return true;
67
506
}
68
69
template <class Policy, class Hash, class Eq, class Alloc>
70
template<typename InputArchive>
71
506
bool raw_hash_set<Policy, Hash, Eq, Alloc>::phmap_load(InputArchive& ar) {
72
506
    static_assert(type_traits_internal::IsTriviallyCopyable<value_type>::value,
73
506
                    "value_type should be trivially copyable");
74
506
    raw_hash_set<Policy, Hash, Eq, Alloc>().swap(*this); // clear any existing content
75
76
506
    size_t version = 0;
77
506
    ar.loadBinary(&version, sizeof(size_t));
78
506
    if (version < s_version_base) {
79
        // we didn't store the version, version actually contains the size
80
369
        size_ = version;
81
369
    } else {
82
137
        ar.loadBinary(&size_, sizeof(size_t));
83
137
    }
84
506
    ar.loadBinary(&capacity_, sizeof(size_t));
85
86
506
    if (capacity_) {
87
        // allocate memory for ctrl_ and slots_
88
137
        initialize_slots(capacity_);
89
137
    }
90
506
    if (size_ == 0)
91
369
        return true;
92
137
    ar.loadBinary(ctrl_,  sizeof(ctrl_t) * (capacity_ + Group::kWidth + 1));
93
137
    ar.loadBinary(slots_, sizeof(slot_type) * capacity_);
94
137
    if (version >= s_version_base) {
95
        // growth_left should be restored after calling initialize_slots() which resets it.
96
137
        ar.loadBinary(&growth_left(), sizeof(size_t));
97
137
    }
98
137
    return true;
99
506
}
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
506
    BinaryOutputArchive(const char *file_path) {
169
506
        ofs_.open(file_path, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
170
506
    }
171
172
506
    ~BinaryOutputArchive() = default;
173
    BinaryOutputArchive(const BinaryOutputArchive&) = delete;
174
    BinaryOutputArchive& operator=(const BinaryOutputArchive&) = delete;
175
176
2.92k
    bool saveBinary(const void *p, size_t sz) {
177
2.92k
        ofs_.write(reinterpret_cast<const char*>(p), (std::streamsize)sz);
178
2.92k
        return true;
179
2.92k
    }
180
181
    template<typename V>
182
    typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
183
    saveBinary(const V& v) {
184
        ofs_.write(reinterpret_cast<const char *>(&v), sizeof(V));
185
        return true;
186
    }
187
188
    template<typename Map>
189
    auto saveBinary(const Map& v) -> decltype(v.phmap_dump(*this), bool())
190
    {
191
        return v.phmap_dump(*this);
192
    }
193
194
private:
195
    std::ofstream ofs_;
196
};
197
198
199
class BinaryInputArchive {
200
public:
201
506
    BinaryInputArchive(const char * file_path) {
202
506
        ifs_.open(file_path, std::ofstream::in | std::ofstream::binary);
203
506
    }
204
    
205
506
    ~BinaryInputArchive() = default;
206
    BinaryInputArchive(const BinaryInputArchive&) = delete;
207
    BinaryInputArchive& operator=(const BinaryInputArchive&) = delete;
208
209
1.56k
    bool loadBinary(void* p, size_t sz) {
210
1.56k
        ifs_.read(reinterpret_cast<char*>(p),  (std::streamsize)sz);
211
1.56k
        return true;
212
1.56k
    }
213
214
    template<typename V>
215
    typename std::enable_if<type_traits_internal::IsTriviallyCopyable<V>::value, bool>::type
216
    loadBinary(V* v) {
217
        ifs_.read(reinterpret_cast<char *>(v), sizeof(V));
218
        return true;
219
    }
220
221
    template<typename Map>
222
    auto loadBinary(Map* v) -> decltype(v->phmap_load(*this), bool())
223
    {
224
        return v->phmap_load(*this);
225
    }
226
    
227
private:
228
    std::ifstream ifs_;
229
};
230
231
} // namespace phmap
232
233
234
#ifdef CEREAL_SIZE_TYPE
235
236
template <class T>
237
using PhmapTrivCopyable = typename phmap::type_traits_internal::IsTriviallyCopyable<T>;
238
    
239
namespace cereal
240
{
241
    // Overload Cereal serialization code for phmap::flat_hash_map
242
    // -----------------------------------------------------------
243
    template <class K, class V, class Hash, class Eq, class A>
244
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar,
245
              phmap::flat_hash_map<K, V, Hash, Eq, A> const &hmap)
246
    {
247
        hmap.phmap_dump(ar);
248
    }
249
250
    template <class K, class V, class Hash, class Eq, class A>
251
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar, 
252
              phmap::flat_hash_map<K, V, Hash, Eq, A>  &hmap)
253
    {
254
        hmap.phmap_load(ar);
255
    }
256
257
258
    // Overload Cereal serialization code for phmap::parallel_flat_hash_map
259
    // --------------------------------------------------------------------
260
    template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_>
261
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryOutputArchive>::type &ar,
262
              phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_> const &hmap)
263
    {
264
        hmap.phmap_dump(ar);
265
    }
266
267
    template <class K, class V, class Hash, class Eq, class A, size_t N, class Mtx_>
268
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value && PhmapTrivCopyable<V>::value, typename cereal::BinaryInputArchive>::type &ar, 
269
              phmap::parallel_flat_hash_map<K, V, Hash, Eq, A, N, Mtx_>  &hmap)
270
    {
271
        hmap.phmap_load(ar);
272
    }
273
274
    // Overload Cereal serialization code for phmap::flat_hash_set
275
    // -----------------------------------------------------------
276
    template <class K, class Hash, class Eq, class A>
277
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar,
278
              phmap::flat_hash_set<K, Hash, Eq, A> const &hset)
279
    {
280
        hset.phmap_dump(ar);
281
    }
282
283
    template <class K, class Hash, class Eq, class A>
284
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar, 
285
              phmap::flat_hash_set<K, Hash, Eq, A>  &hset)
286
    {
287
        hset.phmap_load(ar);
288
    }
289
290
    // Overload Cereal serialization code for phmap::parallel_flat_hash_set
291
    // --------------------------------------------------------------------
292
    template <class K, class Hash, class Eq, class A, size_t N, class Mtx_>
293
    void save(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryOutputArchive>::type &ar,
294
              phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_> const &hset)
295
    {
296
        hset.phmap_dump(ar);
297
    }
298
299
    template <class K, class Hash, class Eq, class A, size_t N, class Mtx_>
300
    void load(typename std::enable_if<PhmapTrivCopyable<K>::value, typename cereal::BinaryInputArchive>::type &ar, 
301
              phmap::parallel_flat_hash_set<K, Hash, Eq, A, N, Mtx_>  &hset)
302
    {
303
        hset.phmap_load(ar);
304
    }
305
}
306
307
#endif
308
309
310
311
312
#endif // phmap_dump_h_guard_