Ocean
Loading...
Searching...
No Matches
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
17namespace 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 */
30template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys = false>
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.
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.
262
263 /// The container lock.
264 mutable Lock lock_;
265};
266
267template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
269{
270 *this = std::move(ringMap);
271}
272
273template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
278
279template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
281 storageCapacity_(capacity)
282{
283 // nothing to do here
284}
285
286template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
288{
289 return storageCapacity_;
290}
291
292template <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
301template <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
334template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
335bool 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
342template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
343bool 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
394template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
395template <typename RingMapT<TKey, T, tThreadsafe, tOrderedKeys>::AccessMode tAccessMode>
396bool 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
439template <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
460template <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
481template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
482template <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
530template <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
539template <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
556template <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
576template <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
588template <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
596template <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
605template <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
622template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
623template <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
640template <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
656template <typename TKey, typename T, bool tThreadsafe, bool tOrderedKeys>
657template <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