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 partition_map_type const&
281 map() const
282 {
283 return map_;
284 }
285
286 iterator
288 {
289 iterator it(&map_);
290 begin(it);
291 return it;
292 }
293
295 cbegin() const
296 {
297 const_iterator it(&map_);
298 begin(it);
299 return it;
300 }
301
303 begin() const
304 {
305 return cbegin();
306 }
307
308 iterator
310 {
311 iterator it(&map_);
312 end(it);
313 return it;
314 }
315
317 cend() const
318 {
319 const_iterator it(&map_);
320 end(it);
321 return it;
322 }
323
325 end() const
326 {
327 return cend();
328 }
329
331 partition_index(key_type const& key) const
332 {
333 return partitioner(key);
334 }
335
336private:
337 template <class T>
338 void
339 find(key_type const& key, T& it) const
340 {
341 it.ait_ = it.map_->begin() + partitioner(key);
342 it.mit_ = it.ait_->find(key);
343 if (it.mit_ == it.ait_->end())
344 end(it);
345 }
346
347public:
348 iterator
349 find(key_type const& key)
350 {
351 iterator it(&map_);
352 find(key, it);
353 return it;
354 }
355
357 find(key_type const& key) const
358 {
359 const_iterator it(&map_);
360 find(key, it);
361 return it;
362 }
363
364 template <class T, class U>
366 emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple)
367 {
368 auto const& key = std::get<0>(keyTuple);
369 iterator it(&map_);
370 it.ait_ = it.map_->begin() + partitioner(key);
371 auto [eit, inserted] = it.ait_->emplace(
373 std::forward<T>(keyTuple),
374 std::forward<U>(valueTuple));
375 it.mit_ = eit;
376 return {it, inserted};
377 }
378
379 template <class T, class U>
381 emplace(T&& key, U&& val)
382 {
383 iterator it(&map_);
384 it.ait_ = it.map_->begin() + partitioner(key);
385 auto [eit, inserted] =
386 it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
387 it.mit_ = eit;
388 return {it, inserted};
389 }
390
391 void
393 {
394 for (auto& p : map_)
395 p.clear();
396 }
397
398 iterator
400 {
401 iterator it(&map_);
402 it.ait_ = position.ait_;
403 it.mit_ = position.ait_->erase(position.mit_);
404
405 while (it.mit_ == it.ait_->end())
406 {
407 ++it.ait_;
408 if (it.ait_ == it.map_->end())
409 break;
410 it.mit_ = it.ait_->begin();
411 }
412
413 return it;
414 }
415
417 size() const
418 {
419 std::size_t ret = 0;
420 for (auto& p : map_)
421 ret += p.size();
422 return ret;
423 }
424
425 Value&
426 operator[](Key const& key)
427 {
428 return map_[partitioner(key)][key];
429 }
430
431private:
433};
434
435} // namespace ripple
436
437#endif // RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H
T begin(T... args)
partition_map_type const & map() const
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)
std::size_t partition_index(key_type const &key) const
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:644
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)