Ocean
RingMap.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) Meta Platforms, Inc. and affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  */
7 
8 #ifndef META_OCEAN_BASE_RING_MAP_H
9 #define META_OCEAN_BASE_RING_MAP_H
10 
11 #include "ocean/base/Base.h"
12 #include "ocean/base/DataType.h"
13 #include "ocean/base/Lock.h"
14 
15 #include <list>
16 
17 namespace Ocean
18 {
19 
20 /**
21  * This class implements a data storage map that stores the data elements in a ring manner.
22  * The map can hold a maximal number of elements and exchanges the oldest object by a new object if this map is full.<br>
23  * Each stored object is connected with a key so that the object can be addressed.<br>
24  * @tparam TKey Data type of the map keys
25  * @tparam T Data type of the map elements
26  * @tparam tThreadsafe True, to create a thread-safe object
27  * @tparam tOrderedKeys True, to allow accessing the keys in order; False, if the order of the keys is not of interest
28  * @ingroup base
29  */
30 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys = false>
31 class RingMapT
32 {
33  template <typename TKey2, typename T2, bool tThreadsafe2, bool tOrderedKeys2> friend class RingMapT;
34 
35  public:
36 
37  /**
38  * The data type of the objects that are stored in this container.
39  */
40  typedef T Type;
41 
42  /**
43  * The data type of the keys that are used to address the data objects.
44  */
45  typedef TKey TypeKey;
46 
47  /**
48  * Definition of individual element access modes.
49  */
50  enum AccessMode : uint32_t
51  {
52  /// The element's key must be a perfect match.
53  AM_MATCH = 0u,
54  /// The element with highest key is returned if no perfect match can be found, only if 'tOrderedKeys == true'.
56  /// The element with lowest key is returned if no perfect match can be found, only if 'tOrderedKeys == true'.
58  };
59 
60  protected:
61 
62  /**
63  * Definition of a double-linked list holding the keys in order how they have been inserted.
64  */
65  using KeyList = std::list<TKey>;
66 
67  /**
68  * Definition of a pair combining a value with a list iterator.
69  */
70  using ValuePair = std::pair<T, typename KeyList::iterator>;
71 
72  /**
73  * Definition of a map that maps keys to value pairs.
74  */
75  typedef typename MapTyper<tOrderedKeys>::template TMap<TKey, ValuePair> KeyMap;
76 
77  public:
78 
79  /**
80  * Creates a new ring storage object with no capacity.
81  */
82  RingMapT() = default;
83 
84  /**
85  * Move constructor.
86  * @param ringMap Object to be moved
87  */
89 
90  /**
91  * Copy constructor.
92  * @param ringMap Object to be copied
93  */
95 
96  /**
97  * Creates a new ring storage object with a specified capacity.
98  * @param capacity The capacity of the storage container, with range [0, infinity)
99  */
100  explicit inline RingMapT(const size_t capacity);
101 
102  /**
103  * Returns the capacity of this storage container.
104  * @return Capacity of this storage container
105  */
106  inline size_t capacity() const;
107 
108  /**
109  * Returns the number of elements that are currently stored in this container.
110  * @return Number of elements, with range [0, capacity()]
111  */
112  inline size_t size() const;
113 
114  /**
115  * Sets or changes the capacity of this storage container.
116  * @param capacity The capacity to be set, with range [0, infinity)
117  */
118  void setCapacity(const size_t capacity);
119 
120  /**
121  * Inserts a new element into this storage container.
122  * @param key The key of the new element
123  * @param element The element that will be inserted
124  * @param forceOverwrite True, to overwrite an existing element with some key, False to avoid that an element is inserted if an element with same key exists already
125  * @return True, if the element has been inserted
126  */
127  bool insertElement(const TKey& key, const T& element, const bool forceOverwrite = false);
128 
129  /**
130  * Inserts a new element into this storage container.
131  * This function moves the new element.
132  * @param key The key of the new element
133  * @param element The element that will be inserted
134  * @param forceOverwrite True, to overwrite an existing element with some key, False to avoid that an element is inserted if an element with same key exists already
135  * @return True, if the element has been inserted
136  */
137  bool insertElement(const TKey& key, T&& element, const bool forceOverwrite = false);
138 
139  /**
140  * Returns an element of this storage container.
141  * @param key The key of the element to be returned
142  * @param element Resulting element
143  * @return True, if the requested element exists
144  * @tparam tAccessMode The access mode to be used
145  * @see checkoutElement().
146  */
147  template <AccessMode tAccessMode = AM_MATCH>
148  bool element(const TKey& key, T& element) const;
149 
150  /**
151  * Returns the element with highest key.
152  * The map must be created with 'tOrderedKeys == true'.
153  * @param element Resulting element
154  * @return True, if the requested element exists
155  * @see element().
156  */
157  bool highestElement(T& element) const;
158 
159  /**
160  * Returns the element with lowest key.
161  * The map must be created with 'tOrderedKeys == true'.
162  * @param element Resulting element
163  * @return True, if the requested element exists
164  * @see element().
165  */
166  bool lowestElement(T& element) const;
167 
168  /**
169  * Returns an element of this storage container and removes the element from the container.
170  * @param key The key of the element to be returned
171  * @param element Resulting element
172  * @return True, if the requested element exists
173  * @tparam tAccessMode The access mode to be used
174  * @see element().
175  */
176  template <AccessMode tAccessMode = AM_MATCH>
177  bool checkoutElement(const TKey& key, T& element);
178 
179  /**
180  * Returns whether this storage container holds a specific element.
181  * @param key The key of the element that is checked
182  * @return True, if so
183  */
184  bool hasElement(const TKey& key) const;
185 
186  /**
187  * Checks whether a specified element exists and changes the age of this element.
188  * If the specified element exists, the age of the element will be changed so that the element is the newest element in the database.<br>
189  * @param key The key of the element that will be refreshed
190  * @return True, if the element exists
191  */
192  bool refreshElement(const TKey& key);
193 
194  /**
195  * Returns all elements of this map as a vector.
196  * In case 'tOrderedKeys == true', the resulting elements will be in order based on their corresponding keys.
197  * @return The map's element
198  */
199  std::vector<T> elements() const;
200 
201  /**
202  * Clears all elements of this storage container.
203  */
204  void clear();
205 
206  /**
207  * Returns whether this ring map holds at least one element.
208  * @return True, if so
209  */
210  inline bool isEmpty() const;
211 
212  /**
213  * Move operator.
214  * @param ringMap The ring map to be moved
215  * @return Reference to this object
216  */
218 
219  /**
220  * Move operator.
221  * @param ringMap The ring map to be moved
222  * @return Reference to this object
223  * @tparam tThreadSafeSecond True, if the map to be moved is thread-safe
224  */
225  template <bool tThreadSafeSecond>
227 
228  /**
229  * Copy operator.
230  * @param ringMap The ring map to be moved
231  * @return Reference to this object
232  */
234 
235  /**
236  * Copy operator.
237  * @param ringMap The ring map to be moved
238  * @return Reference to this object
239  * @tparam tThreadSafeSecond True, if the map to be moved is thread-safe
240  */
241  template <bool tThreadSafeSecond>
243 
244  protected:
245 
246  /**
247  * Returns whether the internal states of this storage container is valid.
248  * @return True, if so
249  */
250  inline bool isValid() const;
251 
252  protected:
253 
254  /// The map mapping keys to value pairs.
256 
257  /// The list holding the keys in order how they have been added, oldest keys first.
259 
260  /// The capacity of this storage container.
261  size_t storageCapacity_ = 0;
262 
263  /// The container lock.
264  mutable Lock lock_;
265 };
266 
267 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
269 {
270  *this = std::move(ringMap);
271 }
272 
273 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
275 {
276  *this = ringMap;
277 }
278 
279 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
281  storageCapacity_(capacity)
282 {
283  // nothing to do here
284 }
285 
286 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
288 {
289  return storageCapacity_;
290 }
291 
292 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
294 {
295  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
296  ocean_assert(isValid());
297 
298  return keyMap_.size();
299 }
300 
301 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
303 {
304  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
305  ocean_assert(isValid());
306 
307  if (capacity == storageCapacity_)
308  {
309  return;
310  }
311 
312  if (capacity == 0)
313  {
314  keyMap_.clear();
315  keyList_.clear();
316 
317  }
318  else if (capacity < storageCapacity_)
319  {
320  while (keyMap_.size() > capacity)
321  {
322  ocean_assert(keyMap_.find(keyList_.front()) != keyMap_.cend());
323  keyMap_.erase(keyList_.front());
324 
325  keyList_.pop_front();
326  }
327  }
328 
329  storageCapacity_ = capacity;
330 
331  ocean_assert(isValid());
332 }
333 
334 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
335 bool RingMapT<TKey, T, tThreadsafe, tOrderedKeys>::insertElement(const TKey& key, const T& element, const bool forceOverwrite)
336 {
337  T copyElement(element);
338 
339  return insertElement(key, std::move(copyElement), forceOverwrite);
340 }
341 
342 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
343 bool RingMapT<TKey, T, tThreadsafe, tOrderedKeys>::insertElement(const TKey& key, T&& element, const bool forceOverwrite)
344 {
345  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
346  ocean_assert(isValid());
347 
348  if (storageCapacity_ == 0)
349  {
350  return false;
351  }
352 
353  // check whether the key exist already
354  const typename KeyMap::iterator iMap = keyMap_.find(key);
355  if (iMap != keyMap_.cend())
356  {
357  if (!forceOverwrite)
358  {
359  return false;
360  }
361 
362  iMap->second.first = std::move(element);
363 
364  // moving the list entry to the end (making it the youngest entry), note: a list's iterator is still valid after moving an element
365  keyList_.splice(keyList_.cend(), keyList_, iMap->second.second);
366 
367  return true;
368  }
369 
370  // the key does not exist
371 
372  ocean_assert(keyMap_.size() <= storageCapacity_);
373 
374  if (keyMap_.size() >= storageCapacity_)
375  {
376  // the map is too big, we remove the oldest entry
377  const TKey oldKey(keyList_.front());
378  keyList_.pop_front();
379 
380  ocean_assert(keyMap_.find(oldKey) != keyMap_.end());
381  keyMap_.erase(oldKey);
382  }
383 
384  ocean_assert(keyMap_.size() < storageCapacity_);
385 
386  keyList_.emplace_back(key);
387 
388  keyMap_[key] = std::make_pair(std::move(element), --keyList_.end());
389 
390  ocean_assert(isValid());
391  return true;
392 }
393 
394 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
395 template <typename RingMapT<TKey, T, tThreadsafe, tOrderedKeys>::AccessMode tAccessMode>
396 bool RingMapT<TKey, T, tThreadsafe, tOrderedKeys>::element(const TKey& key, T& element) const
397 {
398  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
399  ocean_assert(isValid());
400 
401  if (storageCapacity_ == 0 || keyMap_.empty())
402  {
403  return false;
404  }
405 
406  typename KeyMap::const_iterator iMap = keyMap_.find(key);
407  if (iMap == keyMap_.end())
408  {
409  if constexpr (tOrderedKeys)
410  {
411  if constexpr (tAccessMode == AM_MATCH_OR_HIGHEST)
412  {
413  iMap = keyMap_.rbegin().base();
414  --iMap;
415  }
416  else if constexpr (tAccessMode == AM_MATCH_OR_LOWEST)
417  {
418  iMap = keyMap_.begin();
419  }
420  else
421  {
422  ocean_assert(tAccessMode == AM_MATCH);
423  return false;
424  }
425  }
426  else
427  {
428  ocean_assert(tAccessMode == AM_MATCH);
429  return false;
430  }
431  }
432 
433  element = iMap->second.first;
434 
435  ocean_assert(isValid());
436  return true;
437 }
438 
439 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
441 {
442  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
443  ocean_assert(isValid());
444 
445  if (keyMap_.empty())
446  {
447  return false;
448  }
449 
450  if constexpr (tOrderedKeys)
451  {
452  element = keyMap_.rbegin()->second.first;
453 
454  return true;
455  }
456 
457  return false;
458 }
459 
460 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
462 {
463  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
464  ocean_assert(isValid());
465 
466  if (keyMap_.empty())
467  {
468  return false;
469  }
470 
471  if constexpr (tOrderedKeys)
472  {
473  element = keyMap_.begin()->second;
474 
475  return true;
476  }
477 
478  return false;
479 }
480 
481 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
482 template <typename RingMapT<TKey, T, tThreadsafe, tOrderedKeys>::AccessMode tAccessMode>
484 {
485  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
486  ocean_assert(isValid());
487 
488  if (storageCapacity_ == 0 || keyMap_.empty())
489  {
490  return false;
491  }
492 
493  typename KeyMap::iterator iMap = keyMap_.find(key);
494  if (iMap == keyMap_.end())
495  {
496  if constexpr (tOrderedKeys)
497  {
498  if constexpr (tAccessMode == AM_MATCH_OR_HIGHEST)
499  {
500  iMap = keyMap_.rbegin().base();
501  --iMap;
502  }
503  else if constexpr (tAccessMode == AM_MATCH_OR_LOWEST)
504  {
505  iMap = keyMap_.begin();
506  }
507  else
508  {
509  ocean_assert(tAccessMode == AM_MATCH);
510  return false;
511  }
512  }
513  else
514  {
515  ocean_assert(tAccessMode == AM_MATCH);
516  return false;
517  }
518  }
519 
520  keyList_.erase(iMap->second.second);
521 
522  element = std::move(iMap->second.first);
523 
524  keyMap_.erase(iMap);
525 
526  ocean_assert(isValid());
527  return true;
528 }
529 
530 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
532 {
533  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
534  ocean_assert(isValid());
535 
536  return keyMap_.find(key) != keyMap_.end();
537 }
538 
539 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
541 {
542  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
543  ocean_assert(isValid());
544 
545  std::vector<T> result;
546  result.reserve(keyMap_.size());
547 
548  for (typename KeyMap::const_iterator iMap = keyMap_.cbegin(); iMap != keyMap_.cend(); ++iMap)
549  {
550  result.emplace_back(iMap->second.first);
551  }
552 
553  return result;
554 }
555 
556 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
558 {
559  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
560  ocean_assert(isValid());
561 
562  const typename KeyMap::const_iterator iMap = keyMap_.find(key);
563 
564  if (iMap == keyMap_.cend())
565  {
566  return false;
567  }
568 
569  // moving the list entry to the end (making it the youngest entry), note: a list's iterator is still valid after moving an element
570  keyList_.splice(keyList_.cend(), keyList_, iMap->second.second);
571 
572  ocean_assert(isValid());
573  return true;
574 }
575 
576 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
578 {
579  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
580  ocean_assert(isValid());
581 
582  keyMap_.clear();
583  keyList_.clear();
584 
585  ocean_assert(isValid());
586 }
587 
588 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
590 {
591  ocean_assert(keyMap_.size() == keyList_.size());
592 
593  return keyMap_.size() <= storageCapacity_ && keyMap_.size() == keyList_.size();
594 }
595 
596 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
598 {
599  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
600  ocean_assert(isValid());
601 
602  return keyMap_.empty();
603 }
604 
605 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
607 {
608  if (this != &ringMap)
609  {
610  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
611  const TemplatedScopedLock<tThreadsafe> scopedLockSecond(ringMap.lock_); // will not create a dead-lock unless both maps depend on each other
612 
613  keyMap_ = std::move(ringMap.keyMap_);
614  keyList_ = std::move(ringMap.keyList_);
615  storageCapacity_ = ringMap.storageCapacity_;
616  ringMap.storageCapacity_ = 0;
617  }
618 
619  return *this;
620 }
621 
622 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
623 template <bool tThreadSafeSecond>
625 {
626  if ((void*)(this) != (void*)(&ringMap))
627  {
628  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
629  const TemplatedScopedLock<tThreadSafeSecond> scopedLockSecond(ringMap.lock_); // will not create a dead-lock unless both maps depend on each other
630 
631  keyMap_ = std::move(ringMap.keyMap_);
632  keyList_ = std::move(ringMap.keyList_);
633  storageCapacity_ = ringMap.storageCapacity_;
634  ringMap.storageCapacity_ = 0;
635  }
636 
637  return *this;
638 }
639 
640 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
642 {
643  if (this != &ringMap)
644  {
645  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
646  const TemplatedScopedLock<tThreadsafe> scopedLockSecond(ringMap.lock_); // will not create a dead-lock unless both maps depend on each other
647 
648  keyMap_ = ringMap.keyMap_;
649  keyList_ = ringMap.keyList_;
650  storageCapacity_ = ringMap.storageCapacity_;
651  }
652 
653  return *this;
654 }
655 
656 template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
657 template <bool tThreadSafeSecond>
659 {
660  if ((void*)(this) != (void*)(&ringMap))
661  {
662  const TemplatedScopedLock<tThreadsafe> scopedLock(lock_);
663  const TemplatedScopedLock<tThreadSafeSecond> scopedLockSecond(ringMap.lock_); // will not create a dead-lock unless both maps depend on each other
664 
665  keyMap_ = ringMap.keyMap_;
666  keyList_ = ringMap.keyList_;
667  storageCapacity_ = ringMap.storageCapacity_;
668  }
669 
670  return *this;
671 }
672 
673 }
674 
675 #endif // META_OCEAN_BASE_RING_MAP_H
This class implements a recursive lock object.
Definition: Lock.h:31
Helper class allowing to define an ordered or unordered map based on the template parameter 'tOrdered...
Definition: DataType.h:518
This class implements a data storage map that stores the data elements in a ring manner.
Definition: RingMap.h:32
std::pair< T, typename KeyList::iterator > ValuePair
Definition of a pair combining a value with a list iterator.
Definition: RingMap.h:70
KeyMap keyMap_
The map mapping keys to value pairs.
Definition: RingMap.h:255
bool hasElement(const TKey &key) const
Returns whether this storage container holds a specific element.
Definition: RingMap.h:531
RingMapT< TKey, T, tThreadsafe, tOrderedKeys > & operator=(RingMapT< TKey, T, tThreadsafe, tOrderedKeys > &&ringMap) noexcept
Move operator.
Definition: RingMap.h:606
std::list< TKey > KeyList
Definition of a double-linked list holding the keys in order how they have been inserted.
Definition: RingMap.h:65
MapTyper< tOrderedKeys >::template TMap< TKey, ValuePair > KeyMap
Definition of a map that maps keys to value pairs.
Definition: RingMap.h:75
bool lowestElement(T &element) const
Returns the element with lowest key.
Definition: RingMap.h:461
bool isValid() const
Returns whether the internal states of this storage container is valid.
Definition: RingMap.h:589
RingMapT< TKey, T, tThreadsafe, tOrderedKeys > & operator=(RingMapT< TKey, T, tThreadSafeSecond, tOrderedKeys > &&ringMap) noexcept
Move operator.
Definition: RingMap.h:624
bool refreshElement(const TKey &key)
Checks whether a specified element exists and changes the age of this element.
Definition: RingMap.h:557
RingMapT< TKey, T, tThreadsafe, tOrderedKeys > & operator=(const RingMapT< TKey, T, tThreadsafe, tOrderedKeys > &ringMap)
Copy operator.
Definition: RingMap.h:641
RingMapT< TKey, T, tThreadsafe, tOrderedKeys > & operator=(const RingMapT< TKey, T, tThreadSafeSecond, tOrderedKeys > &ringMap)
Copy operator.
Definition: RingMap.h:658
void clear()
Clears all elements of this storage container.
Definition: RingMap.h:577
RingMapT(const RingMapT< TKey, T, tThreadsafe, tOrderedKeys > &ringMap)
Copy constructor.
Definition: RingMap.h:274
size_t size() const
Returns the number of elements that are currently stored in this container.
Definition: RingMap.h:293
size_t capacity() const
Returns the capacity of this storage container.
Definition: RingMap.h:287
bool highestElement(T &element) const
Returns the element with highest key.
Definition: RingMap.h:440
TKey TypeKey
The data type of the keys that are used to address the data objects.
Definition: RingMap.h:45
KeyList keyList_
The list holding the keys in order how they have been added, oldest keys first.
Definition: RingMap.h:258
std::vector< T > elements() const
Returns all elements of this map as a vector.
Definition: RingMap.h:540
T Type
The data type of the objects that are stored in this container.
Definition: RingMap.h:40
bool element(const TKey &key, T &element) const
Returns an element of this storage container.
Definition: RingMap.h:396
Lock lock_
The container lock.
Definition: RingMap.h:264
bool insertElement(const TKey &key, T &&element, const bool forceOverwrite=false)
Inserts a new element into this storage container.
Definition: RingMap.h:343
bool insertElement(const TKey &key, const T &element, const bool forceOverwrite=false)
Inserts a new element into this storage container.
Definition: RingMap.h:335
bool isEmpty() const
Returns whether this ring map holds at least one element.
Definition: RingMap.h:597
RingMapT()=default
Creates a new ring storage object with no capacity.
size_t storageCapacity_
The capacity of this storage container.
Definition: RingMap.h:261
AccessMode
Definition of individual element access modes.
Definition: RingMap.h:51
@ AM_MATCH_OR_LOWEST
The element with lowest key is returned if no perfect match can be found, only if 'tOrderedKeys == tr...
Definition: RingMap.h:57
@ AM_MATCH_OR_HIGHEST
The element with highest key is returned if no perfect match can be found, only if 'tOrderedKeys == t...
Definition: RingMap.h:55
@ AM_MATCH
The element's key must be a perfect match.
Definition: RingMap.h:53
bool checkoutElement(const TKey &key, T &element)
Returns an element of this storage container and removes the element from the container.
Definition: RingMap.h:483
RingMapT(const size_t capacity)
Creates a new ring storage object with a specified capacity.
Definition: RingMap.h:280
friend class RingMapT
Definition: RingMap.h:33
void setCapacity(const size_t capacity)
Sets or changes the capacity of this storage container.
Definition: RingMap.h:302
RingMapT(RingMapT< TKey, T, tThreadsafe, tOrderedKeys > &&ringMap) noexcept
Move constructor.
Definition: RingMap.h:268
This class implements a recursive scoped lock object that is activated by a boolean template paramete...
Definition: Lock.h:178
The namespace covering the entire Ocean framework.
Definition: Accessor.h:15