hyperledger/iroha
Iroha - A simple, decentralized ledger http://iroha.tech
ring_buffer.hpp
Go to the documentation of this file.
1 
6 #ifndef IROHA_COMMON_RING_BUFFER_HPP
7 #define IROHA_COMMON_RING_BUFFER_HPP
8 
9 namespace iroha {
10  namespace containers {
17  template <typename T, size_t Count>
18  class RingBuffer final {
19  public:
20  using Type = T;
21  using Handle = size_t;
22 
23  private:
24  static_assert(Count > 0, "Unexpected count value. It must be above 0.");
25  static_assert(Count <= (std::numeric_limits<size_t>::max() >> 1),
26  "To prevent overflow");
27 
28  enum { kTypeSize = sizeof(Type) };
29 
33  enum { kActualLimit = Count };
34 
41  enum { kVirtualLimit = 2 * kActualLimit };
42 
43  struct Node {
44  uint8_t data[kTypeSize];
45  } data_[Count];
46 
47  Handle begin_;
48  Handle end_;
49 
50  inline size_t internalSizeFromPosition(Handle h) const {
51  return (((h + kVirtualLimit) - end_) % kVirtualLimit);
52  }
53 
54  inline bool handleInBound(Handle h) const {
58  auto const sz_handle = internalSizeFromPosition(h);
59  auto const sz_begin = internalSizeFromPosition(begin_);
60  return (sz_handle < sz_begin);
61  }
62 
63  inline size_t incrementAndNormalize(size_t val) const {
64  return (++val % kVirtualLimit);
65  }
66 
67  inline size_t handleToPosition(Handle h) const {
68  return (h % kActualLimit);
69  }
70 
71  inline size_t internalSize() const {
72  auto const normalized_size = internalSizeFromPosition(begin_);
73  assert(normalized_size <= kActualLimit);
74  return normalized_size;
75  }
76 
77  inline bool internalEmpty() const {
78  return (begin_ == end_);
79  }
80 
81  inline Type &internalGetItem(Node &node) {
82  return *reinterpret_cast<Type *>(node.data);
83  }
84 
85  inline Type const &internalGetItem(Node const &node) const {
86  return *reinterpret_cast<Type const *>(node.data);
87  }
88 
89  inline void destruct(Node &node) {
90  assert(!internalEmpty());
91 
92  auto &item = internalGetItem(node);
93  item.~Type();
94  }
95 
96  template <typename FuncOnRemove>
97  inline void destructLast(FuncOnRemove &&on_remove) {
98  auto &node = internalToNode(end_);
99  on_remove(end_, internalGetItem(node));
100 
101  destruct(node);
102  end_ = incrementAndNormalize(end_);
103  }
104 
105  template <typename... Args>
106  inline void construct(Node &node, Args &&... args) {
107  assert(internalSize() < kActualLimit);
108  new (node.data) Type(std::forward<Args>(args)...);
109  }
110 
111  template <typename FuncOnAdd, typename... Args>
112  inline void constructFirst(FuncOnAdd &&on_add, Args &&... args) {
113  auto &node = internalToNode(begin_);
114  auto const constructed_h = begin_;
115 
116  construct(node, std::forward<Args>(args)...);
117  begin_ = incrementAndNormalize(begin_);
118 
119  on_add(constructed_h, internalGetItem(node));
120  }
121 
122  inline Node &internalToNode(Handle h) {
123  assert(h < kVirtualLimit);
124  return data_[handleToPosition(h)];
125  }
126 
127  inline Node const &internalToNode(Handle h) const {
128  assert(h < kVirtualLimit);
129  return data_[handleToPosition(h)];
130  }
131 
132  public:
133  RingBuffer() : begin_(0ull), end_(0ull) {}
134 
136  while (!internalEmpty()) pop([](Handle, Type const &) {});
137  }
138 
139  template <typename FuncOnAdd, typename FuncOnRemove, typename... Args>
140  void push(FuncOnAdd &&on_add, FuncOnRemove &&on_remove, Args &&... args) {
141  assert(internalSize() <= kActualLimit);
142  if (internalSize() == kActualLimit) {
143  destructLast(std::move(on_remove));
144  }
145  constructFirst(std::move(on_add), std::forward<Args>(args)...);
146  }
147 
148  template <typename FuncOnRemove>
149  void pop(FuncOnRemove &&on_remove) {
150  if (!internalEmpty()) {
151  destructLast(std::move(on_remove));
152  }
153  }
154 
156  assert(handleInBound(h));
157  return internalGetItem(internalToNode(h));
158  }
159 
160  Type const &getItem(Handle h) const {
161  assert(handleInBound(h));
162  return internalGetItem(internalToNode(h));
163  }
164 
165  bool empty() const {
166  return internalEmpty();
167  }
168 
169  size_t size() const {
170  return internalSize();
171  }
172  };
173  } // namespace containers
174 } // namespace iroha
175 
176 #endif // IROHA_COMMON_RING_BUFFER_HPP
~RingBuffer()
Definition: ring_buffer.hpp:135
Type const & getItem(Handle h) const
Definition: ring_buffer.hpp:160
KeyAndValue Type
Definition: ring_buffer.hpp:20
Type & getItem(Handle h)
Definition: ring_buffer.hpp:155
RingBuffer()
Definition: ring_buffer.hpp:133
bool empty() const
Definition: ring_buffer.hpp:165
Definition: block_query.hpp:15
void push(FuncOnAdd &&on_add, FuncOnRemove &&on_remove, Args &&... args)
Definition: ring_buffer.hpp:140
void pop(FuncOnRemove &&on_remove)
Definition: ring_buffer.hpp:149
size_t size() const
Definition: ring_buffer.hpp:169
Definition: ring_buffer.hpp:18
size_t Handle
Definition: ring_buffer.hpp:21