rippled
Loading...
Searching...
No Matches
partitioned_unordered_map.h
1#ifndef XRPL_BASICS_PARTITIONED_UNORDERED_MAP_H
2#define XRPL_BASICS_PARTITIONED_UNORDERED_MAP_H
3
4#include <xrpl/beast/hash/uhash.h>
5#include <xrpl/beast/utility/instrumentation.h>
6
7#include <functional>
8#include <optional>
9#include <string>
10#include <thread>
11#include <unordered_map>
12#include <utility>
13#include <vector>
14
15namespace ripple {
16
17template <typename Key>
18static std::size_t
19extract(Key const& key)
20{
21 return key;
22}
23
24template <>
25inline std::size_t
27{
28 return ::beast::uhash<>{}(key);
29}
30
31template <
32 typename Key,
33 typename Value,
34 typename Hash,
35 typename Pred = std::equal_to<Key>,
38{
40
41public:
42 using key_type = Key;
43 using mapped_type = Value;
47 using hasher = Hash;
48 using key_equal = Pred;
49 using allocator_type = Alloc;
53 using const_pointer = value_type const*;
57
58 struct iterator
59 {
62 typename partition_map_type::iterator ait_;
63 typename map_type::iterator mit_;
64
65 iterator() = default;
66
70
72 operator*() const
73 {
74 return *mit_;
75 }
76
78 operator->() const
79 {
80 return &(*mit_);
81 }
82
83 void
85 {
86 ++mit_;
87 while (mit_ == ait_->end())
88 {
89 ++ait_;
90 if (ait_ == map_->end())
91 return;
92 mit_ = ait_->begin();
93 }
94 }
95
96 // ++it
99 {
100 inc();
101 return *this;
102 }
103
104 // it++
107 {
108 iterator tmp(*this);
109 inc();
110 return tmp;
111 }
112
113 friend bool
114 operator==(iterator const& lhs, iterator const& rhs)
115 {
116 return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
117 lhs.mit_ == rhs.mit_;
118 }
119
120 friend bool
121 operator!=(iterator const& lhs, iterator const& rhs)
122 {
123 return !(lhs == rhs);
124 }
125 };
126
128 {
130
132 typename partition_map_type::iterator ait_;
133 typename map_type::iterator mit_;
134
135 const_iterator() = default;
136
140
142 {
143 map_ = orig.map_;
144 ait_ = orig.ait_;
145 mit_ = orig.mit_;
146 }
147
149 operator*() const
150 {
151 return *mit_;
152 }
153
156 {
157 return &(*mit_);
158 }
159
160 void
162 {
163 ++mit_;
164 while (mit_ == ait_->end())
165 {
166 ++ait_;
167 if (ait_ == map_->end())
168 return;
169 mit_ = ait_->begin();
170 }
171 }
172
173 // ++it
176 {
177 inc();
178 return *this;
179 }
180
181 // it++
184 {
185 const_iterator tmp(*this);
186 inc();
187 return tmp;
188 }
189
190 friend bool
192 {
193 return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
194 lhs.mit_ == rhs.mit_;
195 }
196
197 friend bool
199 {
200 return !(lhs == rhs);
201 }
202 };
203
204private:
206 partitioner(Key const& key) const
207 {
208 return extract(key) % partitions_;
209 }
210
211 template <class T>
212 static void
213 end(T& it)
214 {
215 it.ait_ = it.map_->end();
216 it.mit_ = it.map_->back().end();
217 }
218
219 template <class T>
220 static void
221 begin(T& it)
222 {
223 for (it.ait_ = it.map_->begin(); it.ait_ != it.map_->end(); ++it.ait_)
224 {
225 if (it.ait_->begin() == it.ait_->end())
226 continue;
227 it.mit_ = it.ait_->begin();
228 return;
229 }
230 end(it);
231 }
232
233public:
236 {
237 // Set partitions to the number of hardware threads if the parameter
238 // is either empty or set to 0.
240 ? *partitions
243 XRPL_ASSERT(
245 "ripple::partitioned_unordered_map::partitioned_unordered_map : "
246 "nonzero partitions");
247 }
248
251 {
252 return partitions_;
253 }
254
257 {
258 return map_;
259 }
260
261 iterator
263 {
264 iterator it(&map_);
265 begin(it);
266 return it;
267 }
268
270 cbegin() const
271 {
272 const_iterator it(&map_);
273 begin(it);
274 return it;
275 }
276
278 begin() const
279 {
280 return cbegin();
281 }
282
283 iterator
285 {
286 iterator it(&map_);
287 end(it);
288 return it;
289 }
290
292 cend() const
293 {
294 const_iterator it(&map_);
295 end(it);
296 return it;
297 }
298
300 end() const
301 {
302 return cend();
303 }
304
305private:
306 template <class T>
307 void
308 find(key_type const& key, T& it) const
309 {
310 it.ait_ = it.map_->begin() + partitioner(key);
311 it.mit_ = it.ait_->find(key);
312 if (it.mit_ == it.ait_->end())
313 end(it);
314 }
315
316public:
317 iterator
318 find(key_type const& key)
319 {
320 iterator it(&map_);
321 find(key, it);
322 return it;
323 }
324
326 find(key_type const& key) const
327 {
328 const_iterator it(&map_);
329 find(key, it);
330 return it;
331 }
332
333 template <class T, class U>
335 emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple)
336 {
337 auto const& key = std::get<0>(keyTuple);
338 iterator it(&map_);
339 it.ait_ = it.map_->begin() + partitioner(key);
340 auto [eit, inserted] = it.ait_->emplace(
342 std::forward<T>(keyTuple),
343 std::forward<U>(valueTuple));
344 it.mit_ = eit;
345 return {it, inserted};
346 }
347
348 template <class T, class U>
350 emplace(T&& key, U&& val)
351 {
352 iterator it(&map_);
353 it.ait_ = it.map_->begin() + partitioner(key);
354 auto [eit, inserted] =
355 it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
356 it.mit_ = eit;
357 return {it, inserted};
358 }
359
360 void
362 {
363 for (auto& p : map_)
364 p.clear();
365 }
366
367 iterator
369 {
370 iterator it(&map_);
371 it.ait_ = position.ait_;
372 it.mit_ = position.ait_->erase(position.mit_);
373
374 while (it.mit_ == it.ait_->end())
375 {
376 ++it.ait_;
377 if (it.ait_ == it.map_->end())
378 break;
379 it.mit_ = it.ait_->begin();
380 }
381
382 return it;
383 }
384
386 size() const
387 {
388 std::size_t ret = 0;
389 for (auto& p : map_)
390 ret += p.size();
391 return ret;
392 }
393
394 Value&
395 operator[](Key const& key)
396 {
397 return map_[partitioner(key)][key];
398 }
399
400private:
402};
403
404} // namespace ripple
405
406#endif // XRPL_BASICS_PARTITIONED_UNORDERED_MAP_H
T begin(T... args)
iterator erase(const_iterator position)
std::pair< iterator, bool > emplace(std::piecewise_construct_t const &, T &&keyTuple, U &&valueTuple)
std::pair< iterator, bool > emplace(T &&key, U &&val)
const_iterator find(key_type const &key) const
void find(key_type const &key, T &it) const
partitioned_unordered_map(std::optional< std::size_t > partitions=std::nullopt)
std::size_t partitioner(Key const &key) const
T end(T... args)
T hardware_concurrency(T... args)
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:6
std::size_t extract(uint256 const &key)
Definition base_uint.h:635
T piecewise_construct
T resize(T... args)
friend bool operator!=(const_iterator const &lhs, const_iterator const &rhs)
friend bool operator==(const_iterator const &lhs, const_iterator const &rhs)
friend bool operator!=(iterator const &lhs, iterator const &rhs)
friend bool operator==(iterator const &lhs, iterator const &rhs)