rippled
Loading...
Searching...
No Matches
partitioned_unordered_map.h
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2021 Ripple Labs Inc.
5
6 Permission to use, copy, modify, and/or distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#ifndef RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H
21#define RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H
22
23#include <xrpl/beast/hash/uhash.h>
24#include <xrpl/beast/utility/instrumentation.h>
25#include <functional>
26#include <optional>
27#include <string>
28#include <thread>
29#include <unordered_map>
30#include <utility>
31#include <vector>
32
33namespace ripple {
34
35template <typename Key>
36static std::size_t
37extract(Key const& key)
38{
39 return key;
40}
41
42template <>
43inline std::size_t
45{
46 return ::beast::uhash<>{}(key);
47}
48
49template <
50 typename Key,
51 typename Value,
52 typename Hash,
53 typename Pred = std::equal_to<Key>,
56{
58
59public:
60 using key_type = Key;
61 using mapped_type = Value;
65 using hasher = Hash;
66 using key_equal = Pred;
67 using allocator_type = Alloc;
71 using const_pointer = value_type const*;
72 using map_type = std::
73 unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
75
76 struct iterator
77 {
80 typename partition_map_type::iterator ait_;
81 typename map_type::iterator mit_;
82
83 iterator() = default;
84
86 {
87 }
88
90 operator*() const
91 {
92 return *mit_;
93 }
94
96 operator->() const
97 {
98 return &(*mit_);
99 }
100
101 void
103 {
104 ++mit_;
105 while (mit_ == ait_->end())
106 {
107 ++ait_;
108 if (ait_ == map_->end())
109 return;
110 mit_ = ait_->begin();
111 }
112 }
113
114 // ++it
115 iterator&
117 {
118 inc();
119 return *this;
120 }
121
122 // it++
125 {
126 iterator tmp(*this);
127 inc();
128 return tmp;
129 }
130
131 friend bool
132 operator==(iterator const& lhs, iterator const& rhs)
133 {
134 return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
135 lhs.mit_ == rhs.mit_;
136 }
137
138 friend bool
139 operator!=(iterator const& lhs, iterator const& rhs)
140 {
141 return !(lhs == rhs);
142 }
143 };
144
146 {
148
150 typename partition_map_type::iterator ait_;
151 typename map_type::iterator mit_;
152
153 const_iterator() = default;
154
156 {
157 }
158
160 {
161 map_ = orig.map_;
162 ait_ = orig.ait_;
163 mit_ = orig.mit_;
164 }
165
167 operator*() const
168 {
169 return *mit_;
170 }
171
174 {
175 return &(*mit_);
176 }
177
178 void
180 {
181 ++mit_;
182 while (mit_ == ait_->end())
183 {
184 ++ait_;
185 if (ait_ == map_->end())
186 return;
187 mit_ = ait_->begin();
188 }
189 }
190
191 // ++it
194 {
195 inc();
196 return *this;
197 }
198
199 // it++
202 {
203 const_iterator tmp(*this);
204 inc();
205 return tmp;
206 }
207
208 friend bool
210 {
211 return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
212 lhs.mit_ == rhs.mit_;
213 }
214
215 friend bool
217 {
218 return !(lhs == rhs);
219 }
220 };
221
222private:
224 partitioner(Key const& key) const
225 {
226 return extract(key) % partitions_;
227 }
228
229 template <class T>
230 static void
231 end(T& it)
232 {
233 it.ait_ = it.map_->end();
234 it.mit_ = it.map_->back().end();
235 }
236
237 template <class T>
238 static void
239 begin(T& it)
240 {
241 for (it.ait_ = it.map_->begin(); it.ait_ != it.map_->end(); ++it.ait_)
242 {
243 if (it.ait_->begin() == it.ait_->end())
244 continue;
245 it.mit_ = it.ait_->begin();
246 return;
247 }
248 end(it);
249 }
250
251public:
254 {
255 // Set partitions to the number of hardware threads if the parameter
256 // is either empty or set to 0.
258 ? *partitions
261 XRPL_ASSERT(
263 "ripple::partitioned_unordered_map::partitioned_unordered_map : "
264 "nonzero partitions");
265 }
266
269 {
270 return partitions_;
271 }
272
275 {
276 return map_;
277 }
278
279 iterator
281 {
282 iterator it(&map_);
283 begin(it);
284 return it;
285 }
286
288 cbegin() const
289 {
290 const_iterator it(&map_);
291 begin(it);
292 return it;
293 }
294
296 begin() const
297 {
298 return cbegin();
299 }
300
301 iterator
303 {
304 iterator it(&map_);
305 end(it);
306 return it;
307 }
308
310 cend() const
311 {
312 const_iterator it(&map_);
313 end(it);
314 return it;
315 }
316
318 end() const
319 {
320 return cend();
321 }
322
323private:
324 template <class T>
325 void
326 find(key_type const& key, T& it) const
327 {
328 it.ait_ = it.map_->begin() + partitioner(key);
329 it.mit_ = it.ait_->find(key);
330 if (it.mit_ == it.ait_->end())
331 end(it);
332 }
333
334public:
335 iterator
336 find(key_type const& key)
337 {
338 iterator it(&map_);
339 find(key, it);
340 return it;
341 }
342
344 find(key_type const& key) const
345 {
346 const_iterator it(&map_);
347 find(key, it);
348 return it;
349 }
350
351 template <class T, class U>
353 emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple)
354 {
355 auto const& key = std::get<0>(keyTuple);
356 iterator it(&map_);
357 it.ait_ = it.map_->begin() + partitioner(key);
358 auto [eit, inserted] = it.ait_->emplace(
359 std::piecewise_construct,
360 std::forward<T>(keyTuple),
361 std::forward<U>(valueTuple));
362 it.mit_ = eit;
363 return {it, inserted};
364 }
365
366 template <class T, class U>
368 emplace(T&& key, U&& val)
369 {
370 iterator it(&map_);
371 it.ait_ = it.map_->begin() + partitioner(key);
372 auto [eit, inserted] =
373 it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
374 it.mit_ = eit;
375 return {it, inserted};
376 }
377
378 void
380 {
381 for (auto& p : map_)
382 p.clear();
383 }
384
385 iterator
387 {
388 iterator it(&map_);
389 it.ait_ = position.ait_;
390 it.mit_ = position.ait_->erase(position.mit_);
391
392 while (it.mit_ == it.ait_->end())
393 {
394 ++it.ait_;
395 if (it.ait_ == it.map_->end())
396 break;
397 it.mit_ = it.ait_->begin();
398 }
399
400 return it;
401 }
402
404 size() const
405 {
406 std::size_t ret = 0;
407 for (auto& p : map_)
408 ret += p.size();
409 return ret;
410 }
411
412 Value&
413 operator[](Key const& key)
414 {
415 return map_[partitioner(key)][key];
416 }
417
418private:
420};
421
422} // namespace ripple
423
424#endif // RIPPLE_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)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
std::size_t extract(uint256 const &key)
Definition: base_uint.h:650
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)