Zero  0.1.0
multi_clock.hpp
Go to the documentation of this file.
1 #ifndef __MULTI_CLOCK_HPP
2 #define __MULTI_CLOCK_HPP
3 
5 
6 #include <cstdint>
7 #include <cstring>
8 #include <vector>
9 #include <array>
10 
11 namespace zero::multi_clock {
12 
17  typedef uint32_t ClockIndex;
18 
52  template<class key_type,
53  class value_type, uint32_t clock_count, key_type invalid_index, key_type invalid_clock_index = clock_count>
55  public:
65  MultiHandedClock(key_type entryCount) :
66  _entryCount(entryCount),
69  _clockMembership(_entryCount, invalid_clock_index) {
70  _hands.fill(invalid_index);
71  _sizes.fill(0);
72  };
73 
80 
90  template<ClockIndex clock>
91  void getHead(value_type& head) const {
92  static_assert(clock < clock_count);
93  if (!isEmpty<clock>()) {
94  w_assert1(_clockMembership[_hands[clock]] == clock);
95  head = _values[_hands[clock]];
96  } else {
97  w_assert1(_hands[clock] == invalid_index);
98  throw MultiHandedClockEmptyException<key_type, value_type, clock_count, invalid_index,
99  invalid_clock_index>(this, clock);
100  }
101  };
102 
112  template<ClockIndex clock>
113  void setHead(const value_type newValue) {
114  static_assert(clock < clock_count);
115  if (!isEmpty<clock>()) {
116  _values[_hands[clock]] = newValue;
117  } else {
118  throw MultiHandedClockEmptyException<key_type, value_type, clock_count, invalid_index,
119  invalid_clock_index>(this, clock);
120  }
121  };
122 
132  template<ClockIndex clock>
133  void getHeadIndex(key_type& headIndex) const {
134  static_assert(clock < clock_count);
135  if (!isEmpty<clock>()) {
136  w_assert1(_clockMembership[_hands[clock]] == clock);
137  headIndex = _hands[clock];
138  } else {
139  throw MultiHandedClockEmptyException<key_type, value_type, clock_count, invalid_index,
140  invalid_clock_index>(this, clock);
141  }
142  };
143 
155  template<ClockIndex clock>
156  void moveHead() {
157  static_assert(clock < clock_count);
158  if (!isEmpty<clock>()) {
159  _hands[clock] = _clocks[_hands[clock]]._after;
160  w_assert1(_clockMembership[_hands[clock]] == clock);
161  } else {
162  throw MultiHandedClockEmptyException<key_type, value_type, clock_count, invalid_index,
163  invalid_clock_index>(this, clock);
164  }
165  };
166 
181  template<ClockIndex clock>
182  void addTail(const key_type& index) {
183  static_assert(clock < clock_count);
184  if (!isValidIndex(index)) {
185  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
186  invalid_clock_index>(this, index);
187  } else if (isContainedIndex(index)) {
188  throw MultiHandedClockAlreadyContainedException<key_type, value_type, clock_count, invalid_index,
189  invalid_clock_index>(this, index);
190  } else {
191  if (isEmpty<clock>()) {
192  _hands[clock] = index;
193  _clocks[index]._before = index;
194  _clocks[index]._after = index;
195  } else {
196  _clocks[index]._before = _clocks[_hands[clock]]._before;
197  _clocks[index]._after = _hands[clock];
198  _clocks[_clocks[_hands[clock]]._before]._after = index;
199  _clocks[_hands[clock]]._before = index;
200  }
201  _sizes[clock]++;
202  _clockMembership[index] = clock;
203  }
204  };
205 
220  template<ClockIndex clock>
221  void addTail(key_type&& index) {
222  static_assert(clock < clock_count);
223  if (!isValidIndex(index)) {
224  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
225  invalid_clock_index>(this, index);
226  } else if (isContainedIndex(index)) {
227  throw MultiHandedClockAlreadyContainedException<key_type, value_type, clock_count, invalid_index,
228  invalid_clock_index>(this, index);
229  } else {
230  if (isEmpty<clock>()) {
231  _hands[clock] = index;
232  _clocks[index]._before = index;
233  _clocks[index]._after = index;
234  } else {
235  _clocks[index]._before = _clocks[_hands[clock]]._before;
236  _clocks[index]._after = _hands[clock];
237  _clocks[_clocks[_hands[clock]]._before]._after = index;
238  _clocks[_hands[clock]]._before = index;
239  }
240  _sizes[clock]++;
241  _clockMembership[index] = clock;
242  }
243  };
244 
261  void addBefore(const key_type& inside, const key_type& newEntry) {
262  if (isValidIndex(newEntry)) {
263  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
264  invalid_clock_index>(this, newEntry);
265  } else if (isValidIndex(inside)) {
266  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
267  invalid_clock_index>(this, inside);
268  } else if (isContainedIndex(newEntry)) {
269  throw MultiHandedClockAlreadyContainedException<key_type, value_type, clock_count, invalid_index,
270  invalid_clock_index>(this, newEntry);
271  } else if (!isContainedIndex(inside)) {
272  MultiHandedClockNotContainedException<key_type, value_type, clock_count, invalid_index,
273  invalid_clock_index>(this, inside);
274  } else {
275  w_assert1(_sizes[_clockMembership[inside]] >= 1);
276  _clocks[newEntry]._before = _clocks[inside]._before;
277  _clocks[newEntry]._after = inside;
278  _clocks[inside]._before = newEntry;
279  _clockMembership[newEntry] = _clockMembership[inside];
280  _sizes[_clockMembership[inside]]++;
281  }
282  };
283 
300  void addBefore(const key_type& inside, key_type&& newEntry) {
301  if (isValidIndex(newEntry)) {
302  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
303  invalid_clock_index>(this, newEntry);
304  } else if (isValidIndex(inside)) {
305  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
306  invalid_clock_index>(this, inside);
307  } else if (isContainedIndex(newEntry)) {
308  throw MultiHandedClockAlreadyContainedException<key_type, value_type, clock_count, invalid_index,
309  invalid_clock_index>(this, newEntry);
310  } else if (!isContainedIndex(inside)) {
311  MultiHandedClockNotContainedException<key_type, value_type, clock_count, invalid_index,
312  invalid_clock_index>(this, inside);
313  } else {
314  w_assert1(_sizes[_clockMembership[inside]] >= 1);
315  _clocks[newEntry]._before = _clocks[inside]._before;
316  _clocks[newEntry]._after = inside;
317  _clocks[inside]._before = newEntry;
318  _clockMembership[newEntry] = _clockMembership[inside];
319  _sizes[_clockMembership[inside]]++;
320  }
321  };
322 
339  void addAfter(const key_type& inside, const key_type& newEntry) {
340  if (isValidIndex(newEntry)) {
341  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
342  invalid_clock_index>(this, newEntry);
343  } else if (isValidIndex(inside)) {
344  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
345  invalid_clock_index>(this, inside);
346  } else if (isContainedIndex(newEntry)) {
347  throw MultiHandedClockAlreadyContainedException<key_type, value_type, clock_count, invalid_index,
348  invalid_clock_index>(this, newEntry);
349  } else if (!isContainedIndex(inside)) {
350  MultiHandedClockNotContainedException<key_type, value_type, clock_count, invalid_index,
351  invalid_clock_index>(this, inside);
352  } else {
353  w_assert1(_sizes[_clockMembership[inside]] >= 1);
354  _clocks[newEntry]._after = _clocks[inside]._after;
355  _clocks[newEntry]._before = inside;
356  _clocks[inside]._after = newEntry;
357  _clockMembership[newEntry] = _clockMembership[inside];
358  _sizes[_clockMembership[inside]]++;
359  }
360  };
361 
378  void addAfter(const key_type& inside, const key_type&& newEntry) {
379  if (isValidIndex(newEntry)) {
380  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
381  invalid_clock_index>(this, newEntry);
382  } else if (isValidIndex(inside)) {
383  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
384  invalid_clock_index>(this, inside);
385  } else if (isContainedIndex(newEntry)) {
386  throw MultiHandedClockAlreadyContainedException<key_type, value_type, clock_count, invalid_index,
387  invalid_clock_index>(this, newEntry);
388  } else if (!isContainedIndex(inside)) {
389  MultiHandedClockNotContainedException<key_type, value_type, clock_count, invalid_index,
390  invalid_clock_index>(this, inside);
391  } else {
392  w_assert1(_sizes[_clockMembership[inside]] >= 1);
393  _clocks[newEntry]._after = _clocks[inside]._after;
394  _clocks[newEntry]._before = inside;
395  _clocks[inside]._after = newEntry;
396  _clockMembership[newEntry] = _clockMembership[inside];
397  _sizes[_clockMembership[inside]]++;
398  }
399  };
400 
411  template<ClockIndex clock>
412  void removeHead(key_type& removedIndex) {
413  static_assert(clock < clock_count);
414  if (!isEmpty<clock>()) {
415  removedIndex = _hands[clock];
416  remove(removedIndex);
417  } else {
418  w_assert1(_hands[clock] == invalid_index);
419  throw MultiHandedClockEmptyException<key_type, value_type, clock_count, invalid_index,
420  invalid_clock_index>(this, clock);
421  }
422  };
423 
437  void remove(const key_type& index) {
438  if (!isValidIndex(index)) {
439  throw MultiHandedClockInvalidIndexException<key_type, value_type, clock_count, invalid_index,
440  invalid_clock_index>(this, index);
441  } else if (!isContainedIndex(index)) {
442  throw MultiHandedClockNotContainedException<key_type, value_type, clock_count, invalid_index,
443  invalid_clock_index>(this, index);
444  } else {
445  ClockIndex clock = _clockMembership[index];
446  if (_sizes[clock] == 1) {
447  w_assert1(_hands[clock] >= 0 && _hands[clock] <= _entryCount - 1 && _hands[clock] != invalid_index);
448  w_assert1(_clocks[_hands[clock]]._before == _hands[clock]);
449  w_assert1(_clocks[_hands[clock]]._after == _hands[clock]);
450 
451  _clocks[index]._before = invalid_index;
452  _clocks[index]._after = invalid_index;
453  _hands[clock] = invalid_index;
454  _clockMembership[index] = invalid_clock_index;
455  _sizes[clock]--;
456  } else {
457  _clocks[_clocks[index]._before]._after = _clocks[index]._after;
458  _clocks[_clocks[index]._after]._before = _clocks[index]._before;
459  _hands[clock] = _clocks[index]._after;
460  _clocks[index]._before = invalid_index;
461  _clocks[index]._after = invalid_index;
462  _clockMembership[index] = invalid_clock_index;
463  _sizes[clock]--;
464 
465  w_assert1(_hands[clock] != invalid_index);
466  }
467  }
468  };
469 
483  template<ClockIndex source, ClockIndex destination>
484  void switchHeadToTail(key_type& movedIndex) {
485  static_assert(source < clock_count);
486  static_assert(destination < clock_count);
487  movedIndex = invalid_index;
488  removeHead<source>(movedIndex);
489 
490  w_assert1(movedIndex != invalid_index);
491 
492  addTail<destination>(movedIndex);
493  };
494 
502  template<ClockIndex clock>
503  inline key_type sizeOf() const noexcept {
504  static_assert(clock < clock_count);
505  return _sizes[clock];
506  }
507 
515  template<ClockIndex clock>
516  inline bool isEmpty() const noexcept {
517  static_assert(clock < clock_count);
518  return sizeOf<clock>() == 0;
519  }
520 
528  inline bool isValidIndex(const key_type& index) const noexcept {
529  return index != invalid_index && index >= 0 && index <= _entryCount - 1;
530  }
531 
540  inline bool isContainedIndex(const key_type& index) const noexcept {
541  return isValidIndex(index) && _clockMembership[index] != invalid_clock_index;
542  }
543 
554  inline value_type& get(const key_type& index) noexcept {
555  if (isValidIndex(index)) {
556  return _values[index];
557  } else {
558  return _values[invalid_index];
559  }
560  }
561 
563  inline const value_type& get(const key_type& index) const noexcept {
564  if (isValidIndex(index)) {
565  return _values[index];
566  } else {
567  return _values[invalid_index];
568  }
569  }
570 
580  inline void set(const key_type& index, const value_type& newValue) noexcept {
581  if (isValidIndex(index)) {
582  _values[index] = newValue;
583  }
584  }
585 
595  inline void set(const key_type& index, value_type&& newValue) noexcept {
596  if (isValidIndex(index)) {
597  _values[index] = newValue;
598  }
599  }
600 
611  inline value_type& operator[](const key_type& index) noexcept {
612  if (isValidIndex(index)) {
613  return _values[index];
614  } else {
615  return _values[invalid_index];
616  }
617  }
618 
620  inline const value_type& operator[](const key_type& index) const noexcept {
621  if (isValidIndex(index)) {
622  return _values[index];
623  } else {
624  return _values[invalid_index];
625  }
626  }
627 
639  inline ClockIndex& getClockIndex(const key_type& index) noexcept {
640  if (isValidIndex(index)) {
641  return _clockMembership[index];
642  } else {
643  return invalid_clock_index;
644  }
645  }
646 
648  inline const ClockIndex& getClockIndex(const key_type& index) const noexcept {
649  if (isValidIndex(index)) {
650  return _clockMembership[index];
651  } else {
652  return invalid_clock_index;
653  }
654  }
655 
656  private:
661  class IndexPair {
662  public:
668  IndexPair() {};
669 
678  IndexPair(const key_type& before, const key_type& after) :
679  _before(before),
680  _after(after) {};
681 
687  key_type _before;
688 
694  key_type _after;
695  };
696 
703  key_type _entryCount;
704 
709  std::vector<value_type> _values;
710 
717  std::vector<IndexPair> _clocks;
718 
724  std::vector<ClockIndex> _clockMembership;
725 
731  std::array<key_type, clock_count> _hands;
732 
737  std::array<key_type, clock_count> _sizes;
738  };
739 } // zero::multi_clock
740 
741 #endif // __MULTI_CLOCK_HPP
std::array< key_type, clock_count > _sizes
Number of elements in the clocks.
Definition: multi_clock.hpp:737
std::vector< ClockIndex > _clockMembership
Membership of indexes to clocks.
Definition: multi_clock.hpp:724
key_type _before
Key before this key.
Definition: multi_clock.hpp:687
void moveHead()
Move the clock hand forward.
Definition: multi_clock.hpp:156
#define w_assert1(x)
Level 1 should not add significant extra time.
Definition: w_base.h:198
Exception Thrown When an Access to a MultiHandedClock with an Invalid Index Happens.
Definition: multi_clock_exceptions.hpp:138
Exception thrown when a MultiHandedClock is empty.
Definition: multi_clock_exceptions.hpp:84
bool isContainedIndex(const key_type &index) const noexcept
Returns true if the specified index is contained in any clock.
Definition: multi_clock.hpp:540
Pair of keys.
Definition: multi_clock.hpp:661
bool isEmpty() const noexcept
Returns true if the specified clock is empty.
Definition: multi_clock.hpp:516
ClockIndex & getClockIndex(const key_type &index) noexcept
Returns a reference to the index of the clock where the specified index is contained in...
Definition: multi_clock.hpp:639
void addTail(key_type &&index)
Make the specified index the tail of the specified clock (with move semantics)
Definition: multi_clock.hpp:221
key_type _after
Key after this key.
Definition: multi_clock.hpp:694
IndexPair(const key_type &before, const key_type &after)
Constructor of a pair of keys with initial values.
Definition: multi_clock.hpp:678
uint32_t ClockIndex
Data type of clock indexes.
Definition: multi_clock.hpp:17
bool isValidIndex(const key_type &index) const noexcept
Returns true if the specified index is valid.
Definition: multi_clock.hpp:528
void switchHeadToTail(key_type &movedIndex)
Moves an entry from the head of one clock to the tail of another one.
Definition: multi_clock.hpp:484
void getHeadIndex(key_type &headIndex) const
Get the index of the entry where the clock hand of the specified clock points to. ...
Definition: multi_clock.hpp:133
std::vector< IndexPair > _clocks
Clocks.
Definition: multi_clock.hpp:717
IndexPair()
Constructor for an empty pair of keys.
Definition: multi_clock.hpp:668
Definition: multi_clock.hpp:11
void getHead(value_type &head) const
Get the value of the entry where the clock hand of the specified clock points to. ...
Definition: multi_clock.hpp:91
~MultiHandedClock()
Destructor of Multiple Clocks with a Common Set of Entries.
Definition: multi_clock.hpp:79
std::vector< value_type > _values
Values.
Definition: multi_clock.hpp:709
void addBefore(const key_type &inside, key_type &&newEntry)
Add the specified index before another index in an arbitrary clock (with move semantics) ...
Definition: multi_clock.hpp:300
Exception thrown when a key is already contained in a MultiHandedClock.
Definition: multi_clock_exceptions.hpp:191
MultiHandedClock(key_type entryCount)
Constructor of Multiple Clocks with a Common Set of Entries.
Definition: multi_clock.hpp:65
value_type & operator[](const key_type &index) noexcept
Returns a reference to the value that corresponds to the specified index.
Definition: multi_clock.hpp:611
const ClockIndex & getClockIndex(const key_type &index) const noexcept
Returns a reference to the index of the clock where the specified index is contained in...
Definition: multi_clock.hpp:648
void addTail(const key_type &index)
Make the specified index the__ZERO_MULTICLOCK_HPP tail of the specified clock.
Definition: multi_clock.hpp:182
void addAfter(const key_type &inside, const key_type &&newEntry)
Add the specified index after another index in an arbitrary clock (with move semantics) ...
Definition: multi_clock.hpp:378
key_type _entryCount
Number of entries the clocks can hold.
Definition: multi_clock.hpp:703
void addBefore(const key_type &inside, const key_type &newEntry)
Add the specified index before another index in an arbitrary clock.
Definition: multi_clock.hpp:261
void setHead(const value_type newValue)
Set the value of the entry where the clock hand of the specified clock points to. ...
Definition: multi_clock.hpp:113
key_type sizeOf() const noexcept
Returns the number of entries in the specified clock.
Definition: multi_clock.hpp:503
Multiple Clocks with a Common Set of Entries.
Definition: multi_clock.hpp:54
const value_type & operator[](const key_type &index) const noexcept
Returns a reference to the value that corresponds to the specified index. noexcept ...
Definition: multi_clock.hpp:620
Exception thrown when a key is not already contained in a MultiHandedClock.
Definition: multi_clock_exceptions.hpp:246
void removeHead(key_type &removedIndex)
Remove the head entry from the specified clock.
Definition: multi_clock.hpp:412
void addAfter(const key_type &inside, const key_type &newEntry)
Add the specified index after another index in an arbitrary clock.
Definition: multi_clock.hpp:339
std::array< key_type, clock_count > _hands
Clock hands.
Definition: multi_clock.hpp:731