rippled
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 <cassert>
24 #include <functional>
25 #include <optional>
26 #include <thread>
27 #include <unordered_map>
28 #include <utility>
29 #include <vector>
30 
31 namespace ripple {
32 
33 template <typename Key>
35 partitioner(Key const& key, std::size_t const numPartitions);
36 
37 template <
38  typename Key,
39  typename Value,
40  typename Hash,
41  typename Pred = std::equal_to<Key>,
44 {
46 
47 public:
48  using key_type = Key;
49  using mapped_type = Value;
53  using hasher = Hash;
54  using key_equal = Pred;
55  using allocator_type = Alloc;
57  using const_reference = value_type const&;
58  using pointer = value_type*;
59  using const_pointer = value_type const*;
60  using map_type = std::
61  unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
63 
64  struct iterator
65  {
68  typename partition_map_type::iterator ait_;
69  typename map_type::iterator mit_;
70 
71  iterator() = default;
72 
74  {
75  }
76 
77  reference
78  operator*() const
79  {
80  return *mit_;
81  }
82 
83  pointer
84  operator->() const
85  {
86  return &(*mit_);
87  }
88 
89  void
90  inc()
91  {
92  ++mit_;
93  while (mit_ == ait_->end())
94  {
95  ++ait_;
96  if (ait_ == map_->end())
97  return;
98  mit_ = ait_->begin();
99  }
100  }
101 
102  // ++it
103  iterator&
105  {
106  inc();
107  return *this;
108  }
109 
110  // it++
111  iterator
113  {
114  iterator tmp(*this);
115  inc();
116  return tmp;
117  }
118 
119  friend bool
120  operator==(iterator const& lhs, iterator const& rhs)
121  {
122  return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
123  lhs.mit_ == rhs.mit_;
124  }
125 
126  friend bool
127  operator!=(iterator const& lhs, iterator const& rhs)
128  {
129  return !(lhs == rhs);
130  }
131  };
132 
134  {
136 
138  typename partition_map_type::iterator ait_;
139  typename map_type::iterator mit_;
140 
141  const_iterator() = default;
142 
144  {
145  }
146 
148  {
149  map_ = orig.map_;
150  ait_ = orig.ait_;
151  mit_ = orig.mit_;
152  }
153 
155  operator*() const
156  {
157  return *mit_;
158  }
159 
161  operator->() const
162  {
163  return &(*mit_);
164  }
165 
166  void
167  inc()
168  {
169  ++mit_;
170  while (mit_ == ait_->end())
171  {
172  ++ait_;
173  if (ait_ == map_->end())
174  return;
175  mit_ = ait_->begin();
176  }
177  }
178 
179  // ++it
182  {
183  inc();
184  return *this;
185  }
186 
187  // it++
190  {
191  const_iterator tmp(*this);
192  inc();
193  return tmp;
194  }
195 
196  friend bool
197  operator==(const_iterator const& lhs, const_iterator const& rhs)
198  {
199  return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
200  lhs.mit_ == rhs.mit_;
201  }
202 
203  friend bool
204  operator!=(const_iterator const& lhs, const_iterator const& rhs)
205  {
206  return !(lhs == rhs);
207  }
208  };
209 
210 private:
212  partitioner(Key const& key) const
213  {
214  return ripple::partitioner(key, partitions_);
215  }
216 
217  template <class T>
218  static void
219  end(T& it)
220  {
221  it.ait_ = it.map_->end();
222  it.mit_ = it.map_->back().end();
223  }
224 
225  template <class T>
226  static void
227  begin(T& it)
228  {
229  for (it.ait_ = it.map_->begin(); it.ait_ != it.map_->end(); ++it.ait_)
230  {
231  if (it.ait_->begin() == it.ait_->end())
232  continue;
233  it.mit_ = it.ait_->begin();
234  return;
235  }
236  end(it);
237  }
238 
239 public:
241  std::optional<std::size_t> partitions = std::nullopt)
242  {
243  // Set partitions to the number of hardware threads if the parameter
244  // is either empty or set to 0.
246  ? *partitions
249  assert(partitions_);
250  }
251 
253  partitions() const
254  {
255  return partitions_;
256  }
257 
259  map()
260  {
261  return map_;
262  }
263 
264  iterator
266  {
267  iterator it(&map_);
268  begin(it);
269  return it;
270  }
271 
273  cbegin() const
274  {
275  const_iterator it(&map_);
276  begin(it);
277  return it;
278  }
279 
281  begin() const
282  {
283  return cbegin();
284  }
285 
286  iterator
287  end()
288  {
289  iterator it(&map_);
290  end(it);
291  return it;
292  }
293 
295  cend() const
296  {
297  const_iterator it(&map_);
298  end(it);
299  return it;
300  }
301 
303  end() const
304  {
305  return cend();
306  }
307 
308 private:
309  template <class T>
310  void
311  find(key_type const& key, T& it) const
312  {
313  it.ait_ = it.map_->begin() + partitioner(key);
314  it.mit_ = it.ait_->find(key);
315  if (it.mit_ == it.ait_->end())
316  end(it);
317  }
318 
319 public:
320  iterator
321  find(key_type const& key)
322  {
323  iterator it(&map_);
324  find(key, it);
325  return it;
326  }
327 
329  find(key_type const& key) const
330  {
331  const_iterator it(&map_);
332  find(key, it);
333  return it;
334  }
335 
336  template <class T, class U>
338  emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple)
339  {
340  auto const& key = std::get<0>(keyTuple);
341  iterator it(&map_);
342  it.ait_ = it.map_->begin() + partitioner(key);
343  auto [eit, inserted] = it.ait_->emplace(
344  std::piecewise_construct,
345  std::forward<T>(keyTuple),
346  std::forward<U>(valueTuple));
347  it.mit_ = eit;
348  return {it, inserted};
349  }
350 
351  template <class T, class U>
353  emplace(T&& key, U&& val)
354  {
355  iterator it(&map_);
356  it.ait_ = it.map_->begin() + partitioner(key);
357  auto [eit, inserted] =
358  it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
359  it.mit_ = eit;
360  return {it, inserted};
361  }
362 
363  void
365  {
366  for (auto& p : map_)
367  p.clear();
368  }
369 
370  iterator
372  {
373  iterator it(&map_);
374  it.ait_ = position.ait_;
375  it.mit_ = position.ait_->erase(position.mit_);
376 
377  while (it.mit_ == it.ait_->end())
378  {
379  ++it.ait_;
380  if (it.ait_ == it.map_->end())
381  break;
382  it.mit_ = it.ait_->begin();
383  }
384 
385  return it;
386  }
387 
389  size() const
390  {
391  std::size_t ret = 0;
392  for (auto& p : map_)
393  ret += p.size();
394  return ret;
395  }
396 
397  Value&
398  operator[](Key const& key)
399  {
400  return map_[partitioner(key)][key];
401  }
402 
403 private:
405 };
406 
407 } // namespace ripple
408 
409 #endif // RIPPLE_BASICS_PARTITIONED_UNORDERED_MAP_H
std::vector::resize
T resize(T... args)
ripple::partitioned_unordered_map< key_type, Entry, hardened_hash<>, std::equal_to< Key > >::key_type
key_type key_type
Definition: partitioned_unordered_map.h:48
ripple::partitioned_unordered_map::iterator::iterator
iterator()=default
ripple::partitioned_unordered_map::partitioned_unordered_map
partitioned_unordered_map(std::optional< std::size_t > partitions=std::nullopt)
Definition: partitioned_unordered_map.h:240
ripple::Dir::const_iterator
Definition: Directory.h:49
ripple::partitioned_unordered_map::size
std::size_t size() const
Definition: partitioned_unordered_map.h:389
utility
ripple::partitioned_unordered_map::find
iterator find(key_type const &key)
Definition: partitioned_unordered_map.h:321
ripple::partitioned_unordered_map::clear
void clear()
Definition: partitioned_unordered_map.h:364
ripple::partitioned_unordered_map::const_iterator::operator->
const_pointer operator->() const
Definition: partitioned_unordered_map.h:161
ripple::partitioned_unordered_map::map
partition_map_type & map()
Definition: partitioned_unordered_map.h:259
functional
ripple::partitioned_unordered_map::end
static void end(T &it)
Definition: partitioned_unordered_map.h:219
std::pair
ripple::partitioned_unordered_map::cend
const_iterator cend() const
Definition: partitioned_unordered_map.h:295
vector
ripple::partitioned_unordered_map::operator[]
Value & operator[](Key const &key)
Definition: partitioned_unordered_map.h:398
std::forward_iterator_tag
ripple::partitioned_unordered_map::partitioner
std::size_t partitioner(Key const &key) const
Definition: partitioned_unordered_map.h:212
ripple::partitioned_unordered_map::iterator::map_
partition_map_type * map_
Definition: partitioned_unordered_map.h:67
ripple::partitioned_unordered_map
Definition: partitioned_unordered_map.h:43
ripple::partitioned_unordered_map::find
void find(key_type const &key, T &it) const
Definition: partitioned_unordered_map.h:311
ripple::partitioned_unordered_map::partitions
std::size_t partitions() const
Definition: partitioned_unordered_map.h:253
ripple::partitioned_unordered_map::begin
iterator begin()
Definition: partitioned_unordered_map.h:265
ripple::partitioned_unordered_map::iterator::operator!=
friend bool operator!=(iterator const &lhs, iterator const &rhs)
Definition: partitioned_unordered_map.h:127
ripple::partitioned_unordered_map::iterator::iterator
iterator(partition_map_type *map)
Definition: partitioned_unordered_map.h:73
ripple::partitioned_unordered_map::const_iterator::operator++
const_iterator & operator++()
Definition: partitioned_unordered_map.h:181
ripple::partitioned_unordered_map::iterator::operator++
iterator operator++(int)
Definition: partitioned_unordered_map.h:112
ripple::partitioned_unordered_map::const_iterator::operator++
const_iterator operator++(int)
Definition: partitioned_unordered_map.h:189
ripple::partitioned_unordered_map::iterator::operator->
pointer operator->() const
Definition: partitioned_unordered_map.h:84
ripple::partitioned_unordered_map::iterator::mit_
map_type::iterator mit_
Definition: partitioned_unordered_map.h:69
std::piecewise_construct_t
ripple::partitioned_unordered_map::begin
const_iterator begin() const
Definition: partitioned_unordered_map.h:281
ripple::partitioned_unordered_map::const_iterator::const_iterator
const_iterator()=default
ripple::partitioned_unordered_map::iterator::operator++
iterator & operator++()
Definition: partitioned_unordered_map.h:104
thread
ripple::partitioned_unordered_map::iterator::inc
void inc()
Definition: partitioned_unordered_map.h:90
ripple::partitioner
std::size_t partitioner(Key const &key, std::size_t const numPartitions)
Definition: partitioned_unordered_map.cpp:61
std::thread::hardware_concurrency
T hardware_concurrency(T... args)
ripple::partitioned_unordered_map::const_iterator::inc
void inc()
Definition: partitioned_unordered_map.h:167
ripple::partitioned_unordered_map::const_iterator::ait_
partition_map_type::iterator ait_
Definition: partitioned_unordered_map.h:138
ripple::partitioned_unordered_map::const_iterator::operator!=
friend bool operator!=(const_iterator const &lhs, const_iterator const &rhs)
Definition: partitioned_unordered_map.h:204
ripple::hardened_hash
Seed functor once per construction.
Definition: hardened_hash.h:96
ripple::partitioned_unordered_map::const_iterator::map_
partition_map_type * map_
Definition: partitioned_unordered_map.h:137
ripple::partitioned_unordered_map< key_type, Entry, hardened_hash<>, std::equal_to< Key > >::const_reference
value_type const & const_reference
Definition: partitioned_unordered_map.h:57
ripple::partitioned_unordered_map::iterator::operator==
friend bool operator==(iterator const &lhs, iterator const &rhs)
Definition: partitioned_unordered_map.h:120
ripple::partitioned_unordered_map::emplace
std::pair< iterator, bool > emplace(std::piecewise_construct_t const &, T &&keyTuple, U &&valueTuple)
Definition: partitioned_unordered_map.h:338
ripple::partitioned_unordered_map::erase
iterator erase(const_iterator position)
Definition: partitioned_unordered_map.h:371
ripple::partitioned_unordered_map::map_
partition_map_type map_
Definition: partitioned_unordered_map.h:404
ripple::partitioned_unordered_map::iterator
Definition: partitioned_unordered_map.h:64
ripple::partitioned_unordered_map< key_type, Entry, hardened_hash<>, std::equal_to< Key > >::mapped_type
Entry mapped_type
Definition: partitioned_unordered_map.h:49
std::equal_to
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::partitioned_unordered_map::end
const_iterator end() const
Definition: partitioned_unordered_map.h:303
ripple::partitioned_unordered_map::end
iterator end()
Definition: partitioned_unordered_map.h:287
ripple::partitioned_unordered_map::find
const_iterator find(key_type const &key) const
Definition: partitioned_unordered_map.h:329
ripple::partitioned_unordered_map::const_iterator
Definition: partitioned_unordered_map.h:133
ripple::partitioned_unordered_map::begin
static void begin(T &it)
Definition: partitioned_unordered_map.h:227
ripple::partitioned_unordered_map::partitions_
std::size_t partitions_
Definition: partitioned_unordered_map.h:45
ripple::partitioned_unordered_map::cbegin
const_iterator cbegin() const
Definition: partitioned_unordered_map.h:273
ripple::partitioned_unordered_map::iterator::ait_
partition_map_type::iterator ait_
Definition: partitioned_unordered_map.h:68
ripple::partitioned_unordered_map::iterator::operator*
reference operator*() const
Definition: partitioned_unordered_map.h:78
ripple::partitioned_unordered_map::const_iterator::const_iterator
const_iterator(iterator const &orig)
Definition: partitioned_unordered_map.h:147
cassert
ripple::partitioned_unordered_map::const_iterator::operator*
const_reference operator*() const
Definition: partitioned_unordered_map.h:155
ripple::partitioned_unordered_map< key_type, Entry, hardened_hash<>, std::equal_to< Key > >::const_pointer
value_type const * const_pointer
Definition: partitioned_unordered_map.h:59
std::allocator
STL class.
optional
std::size_t
ripple::partitioned_unordered_map::const_iterator::mit_
map_type::iterator mit_
Definition: partitioned_unordered_map.h:139
std::vector::end
T end(T... args)
ripple::partitioned_unordered_map::const_iterator::operator==
friend bool operator==(const_iterator const &lhs, const_iterator const &rhs)
Definition: partitioned_unordered_map.h:197
unordered_map
ripple::partitioned_unordered_map::emplace
std::pair< iterator, bool > emplace(T &&key, U &&val)
Definition: partitioned_unordered_map.h:353
ripple::partitioned_unordered_map::const_iterator::const_iterator
const_iterator(partition_map_type *map)
Definition: partitioned_unordered_map.h:143
ripple::partitioned_unordered_map::partition_map_type
std::vector< map_type > partition_map_type
Definition: partitioned_unordered_map.h:62