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
26#include <functional>
27#include <optional>
28#include <string>
29#include <thread>
30#include <unordered_map>
31#include <utility>
32#include <vector>
33
34namespace ripple {
35
36template <typename Key>
37static std::size_t
38extract(Key const& key)
39{
40 return key;
41}
42
43template <>
44inline std::size_t
46{
47 return ::beast::uhash<>{}(key);
48}
49
50template <
51 typename Key,
52 typename Value,
53 typename Hash,
54 typename Pred = std::equal_to<Key>,
57{
59
60public:
61 using key_type = Key;
62 using mapped_type = Value;
66 using hasher = Hash;
67 using key_equal = Pred;
68 using allocator_type = Alloc;
72 using const_pointer = value_type const*;
76
77 struct iterator
78 {
81 typename partition_map_type::iterator ait_;
82 typename map_type::iterator mit_;
83
84 iterator() = default;
85
89
91 operator*() const
92 {
93 return *mit_;
94 }
95
97 operator->() const
98 {
99 return &(*mit_);
100 }
101
102 void
104 {
105 ++mit_;
106 while (mit_ == ait_->end())
107 {
108 ++ait_;
109 if (ait_ == map_->end())
110 return;
111 mit_ = ait_->begin();
112 }
113 }
114
115 // ++it
116 iterator&
118 {
119 inc();
120 return *this;
121 }
122
123 // it++
126 {
127 iterator tmp(*this);
128 inc();
129 return tmp;
130 }
131
132 friend bool
133 operator==(iterator const& lhs, iterator const& rhs)
134 {
135 return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
136 lhs.mit_ == rhs.mit_;
137 }
138
139 friend bool
140 operator!=(iterator const& lhs, iterator const& rhs)
141 {
142 return !(lhs == rhs);
143 }
144 };
145
147 {
149
151 typename partition_map_type::iterator ait_;
152 typename map_type::iterator mit_;
153
154 const_iterator() = default;
155
159
161 {
162 map_ = orig.map_;
163 ait_ = orig.ait_;
164 mit_ = orig.mit_;
165 }
166
168 operator*() const
169 {
170 return *mit_;
171 }
172
175 {
176 return &(*mit_);
177 }
178
179 void
181 {
182 ++mit_;
183 while (mit_ == ait_->end())
184 {
185 ++ait_;
186 if (ait_ == map_->end())
187 return;
188 mit_ = ait_->begin();
189 }
190 }
191
192 // ++it
195 {
196 inc();
197 return *this;
198 }
199
200 // it++
203 {
204 const_iterator tmp(*this);
205 inc();
206 return tmp;
207 }
208
209 friend bool
211 {
212 return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
213 lhs.mit_ == rhs.mit_;
214 }
215
216 friend bool
218 {
219 return !(lhs == rhs);
220 }
221 };
222
223private:
225 partitioner(Key const& key) const
226 {
227 return extract(key) % partitions_;
228 }
229
230 template <class T>
231 static void
232 end(T& it)
233 {
234 it.ait_ = it.map_->end();
235 it.mit_ = it.map_->back().end();
236 }
237
238 template <class T>
239 static void
240 begin(T& it)
241 {
242 for (it.ait_ = it.map_->begin(); it.ait_ != it.map_->end(); ++it.ait_)
243 {
244 if (it.ait_->begin() == it.ait_->end())
245 continue;
246 it.mit_ = it.ait_->begin();
247 return;
248 }
249 end(it);
250 }
251
252public:
255 {
256 // Set partitions to the number of hardware threads if the parameter
257 // is either empty or set to 0.
259 ? *partitions
262 XRPL_ASSERT(
264 "ripple::partitioned_unordered_map::partitioned_unordered_map : "
265 "nonzero partitions");
266 }
267
270 {
271 return partitions_;
272 }
273
276 {
277 return map_;
278 }
279
280 iterator
282 {
283 iterator it(&map_);
284 begin(it);
285 return it;
286 }
287
289 cbegin() const
290 {
291 const_iterator it(&map_);
292 begin(it);
293 return it;
294 }
295
297 begin() const
298 {
299 return cbegin();
300 }
301
302 iterator
304 {
305 iterator it(&map_);
306 end(it);
307 return it;
308 }
309
311 cend() const
312 {
313 const_iterator it(&map_);
314 end(it);
315 return it;
316 }
317
319 end() const
320 {
321 return cend();
322 }
323
324private:
325 template <class T>
326 void
327 find(key_type const& key, T& it) const
328 {
329 it.ait_ = it.map_->begin() + partitioner(key);
330 it.mit_ = it.ait_->find(key);
331 if (it.mit_ == it.ait_->end())
332 end(it);
333 }
334
335public:
336 iterator
337 find(key_type const& key)
338 {
339 iterator it(&map_);
340 find(key, it);
341 return it;
342 }
343
345 find(key_type const& key) const
346 {
347 const_iterator it(&map_);
348 find(key, it);
349 return it;
350 }
351
352 template <class T, class U>
354 emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple)
355 {
356 auto const& key = std::get<0>(keyTuple);
357 iterator it(&map_);
358 it.ait_ = it.map_->begin() + partitioner(key);
359 auto [eit, inserted] = it.ait_->emplace(
361 std::forward<T>(keyTuple),
362 std::forward<U>(valueTuple));
363 it.mit_ = eit;
364 return {it, inserted};
365 }
366
367 template <class T, class U>
369 emplace(T&& key, U&& val)
370 {
371 iterator it(&map_);
372 it.ait_ = it.map_->begin() + partitioner(key);
373 auto [eit, inserted] =
374 it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
375 it.mit_ = eit;
376 return {it, inserted};
377 }
378
379 void
381 {
382 for (auto& p : map_)
383 p.clear();
384 }
385
386 iterator
388 {
389 iterator it(&map_);
390 it.ait_ = position.ait_;
391 it.mit_ = position.ait_->erase(position.mit_);
392
393 while (it.mit_ == it.ait_->end())
394 {
395 ++it.ait_;
396 if (it.ait_ == it.map_->end())
397 break;
398 it.mit_ = it.ait_->begin();
399 }
400
401 return it;
402 }
403
405 size() const
406 {
407 std::size_t ret = 0;
408 for (auto& p : map_)
409 ret += p.size();
410 return ret;
411 }
412
413 Value&
414 operator[](Key const& key)
415 {
416 return map_[partitioner(key)][key];
417 }
418
419private:
421};
422
423} // namespace ripple
424
425#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)
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25
std::size_t extract(uint256 const &key)
Definition base_uint.h:654
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)