FINAL CUT
char_ringbuffer.h
1 /***********************************************************************
2 * char_ringbuffer.h - Ring buffer for char elements *
3 * *
4 * This file is part of the FINAL CUT widget toolkit *
5 * *
6 * Copyright 2022-2024 Markus Gans *
7 * *
8 * FINAL CUT is free software; you can redistribute it and/or modify *
9 * it under the terms of the GNU Lesser General Public License as *
10 * published by the Free Software Foundation; either version 3 of *
11 * the License, or (at your option) any later version. *
12 * *
13 * FINAL CUT is distributed in the hope that it will be useful, but *
14 * WITHOUT ANY WARRANTY; without even the implied warranty of *
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16 * GNU Lesser General Public License for more details. *
17 * *
18 * You should have received a copy of the GNU Lesser General Public *
19 * License along with this program. If not, see *
20 * <http://www.gnu.org/licenses/>. *
21 ***********************************************************************/
22 
23 /* Inheritance diagram
24  * ═══════════════════
25  *
26  * ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▏
27  * ▕ FRingBuffer ▏
28  * ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▏
29  * ▲
30  * │
31  * ▕▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▏
32  * ▕ CharRingBuffer ▏
33  * ▕▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▁▏
34  */
35 
36 #ifndef CHARRINGBUFFER_H
37 #define CHARRINGBUFFER_H
38 
39 #if !defined (USE_FINAL_H) && !defined (COMPILE_FINAL_CUT)
40  #error "Only <final/final.h> can be included directly."
41 #endif
42 
43 #include <algorithm>
44 #include <array>
45 #include <cstring>
46 #include <string>
47 #include <utility>
48 
49 #include <final/util/fstring.h>
50 
51 namespace finalcut
52 {
53 
54 // class forward declaration
55 template <std::size_t>
57 
58 //----------------------------------------------------------------------
59 // class FRingBuffer
60 //----------------------------------------------------------------------
61 
62 template <typename T, std::size_t Capacity>
63 class FRingBuffer
64 {
65  public:
66  //------------------------------------------------------------------
67  // class ring_iterator
68  //------------------------------------------------------------------
69 
70  template <typename Type, std::size_t N>
72  {
73  public:
74  // Using-declarations
75  using iterator_category = std::forward_iterator_tag;
76  using value_type = Type;
77  using difference_type = std::ptrdiff_t;
78  using pointer = Type*;
79  using reference = Type&;
80 
81  explicit ring_iterator (pointer p, std::size_t start, std::size_t pos)
82  : ptr{p}
83  , offset{start}
84  , index{pos}
85  { }
86 
87  inline auto operator ++ () noexcept -> ring_iterator& // prefix
88  {
89  index++;
90  return *this;
91  }
92 
93  inline auto operator ++ (int) noexcept -> ring_iterator // postfix
94  {
95  ring_iterator i = *this;
96  index++;
97  return i;
98  }
99 
100  inline auto operator * () const noexcept -> reference
101  {
102  return ptr[(offset + index) % N];
103  }
104 
105  inline auto operator -> () const noexcept -> pointer
106  {
107  return &**this;
108  }
109 
110  friend inline auto operator == (const ring_iterator& lhs, const ring_iterator& rhs) noexcept -> bool
111  {
112  return lhs.index == rhs.index
113  && lhs.ptr == rhs.ptr
114  && lhs.offset == rhs.offset;
115  }
116 
117  friend inline auto operator != (const ring_iterator& lhs, const ring_iterator& rhs) noexcept -> bool
118  {
119  return ! (lhs == rhs);
120  }
121 
122  private:
123  // Data members
124  pointer ptr{nullptr};
125  const std::size_t offset{0U};
126  std::size_t index{0U};
127 
128  // Friend Non-member operator functions
129  inline friend auto operator + ( const ring_iterator& iter
130  , std::ptrdiff_t size ) noexcept -> ring_iterator
131  {
132  auto tmp = iter;
133  tmp.index += std::size_t(size);
134  return tmp;
135  }
136  };
137 
138  // Using-declarations
141  using difference_type = std::ptrdiff_t;
142  using pointer = T*;
143  using reference = T&;
144  using const_reference = const T&;
145  using value_type = T;
146 
147  // Constructors
148  FRingBuffer()
149  : buffer()
150  { }
151 
152  virtual ~FRingBuffer() = default;
153 
154  // Overloaded operators
155  inline auto operator [] (std::size_t index) noexcept -> reference
156  {
157  static_assert ( Capacity > 0, "Ring buffer has no memory" );
158  return buffer[(head + index) % Capacity];
159  }
160 
161  inline auto operator [] (std::size_t index) const noexcept -> const_reference
162  {
163  static_assert ( Capacity > 0, "Ring buffer has no memory" );
164  return buffer[(head + index) % Capacity];
165  }
166 
167  // Accessors
168  virtual inline auto getClassName() const -> FString
169  {
170  return "FRingBuffer";
171  }
172 
173  inline auto getSize() const noexcept -> std::size_t
174  {
175  return elements;
176  }
177 
178  inline auto getCapacity() const noexcept -> std::size_t
179  {
180  return Capacity;
181  }
182 
183  inline auto begin() noexcept -> iterator
184  {
185  return iterator(buffer.data(), head, 0);
186  }
187 
188  inline auto begin() const noexcept -> const_iterator
189  {
190  return const_iterator(buffer.data(), head, 0);
191  }
192 
193  inline auto end() noexcept -> iterator
194  {
195  return iterator(buffer.data(), head, getSize());
196  }
197 
198  inline auto end() const noexcept -> const_iterator
199  {
200  return const_iterator(buffer.data(), head, getSize());
201  }
202 
203  inline auto front() noexcept -> reference
204  {
205  if ( isEmpty() )
206  return empty_element;
207 
208  return buffer[head];
209  }
210 
211  inline auto front() const noexcept -> const_reference
212  {
213  if ( isEmpty() )
214  return empty_element;
215 
216  return buffer[head];
217  }
218 
219  inline auto back() noexcept -> reference
220  {
221  if ( isEmpty() )
222  return empty_element;
223 
224  std::size_t index = (tail == 0) ? Capacity - 1 : tail - 1;
225  return buffer[index];
226  }
227 
228  inline auto back() const noexcept -> const_reference
229  {
230  if ( isEmpty() )
231  return empty_element;
232 
233  std::size_t index = (tail == 0) ? Capacity - 1 : tail - 1;
234  return buffer[index];
235  }
236 
237  // Mutators
238  inline void clear() noexcept
239  {
240  head = 0U;
241  tail = 0U;
242  elements = 0U;
243  }
244 
245  // Inquiries
246  inline auto isEmpty() const noexcept -> bool
247  {
248  return elements == 0;
249  }
250 
251  inline auto hasData() const noexcept -> bool
252  {
253  return ! isEmpty();
254  }
255 
256  inline auto isFull() const noexcept -> bool
257  {
258  return elements == Capacity;
259  }
260 
261  // Methods
262  inline void push (const T& item) noexcept
263  {
264  if ( isFull() )
265  return;
266 
267  static_assert ( Capacity > 0, "Ring buffer has no memory" );
268  buffer[tail] = item;
269  tail = (tail + 1) % Capacity;
270  elements++;
271  }
272 
273  inline void push_back (const T& item) noexcept
274  {
275  push (item);
276  }
277 
278  template <typename... Args>
279  inline void emplace (Args&&... args)
280  {
281  if ( isFull() )
282  return;
283 
284  static_assert ( Capacity > 0, "Ring buffer has no memory" );
285  buffer[tail] = T(std::forward<Args>(args)...);
286  tail = (tail + 1) % Capacity;
287  elements++;
288  }
289 
290  template <typename... Args>
291  inline void emplace_back (Args&&... args)
292  {
293  emplace (std::forward<Args>(args)...);
294  }
295 
296  inline void pop() noexcept
297  {
298  if ( isEmpty() )
299  return;
300 
301  static_assert ( Capacity > 0, "Ring buffer has no memory" );
302  head = (head + 1) % Capacity;
303  elements--;
304  }
305 
306  inline void pop_front() noexcept
307  {
308  pop();
309  }
310 
311  inline void pop (std::size_t s) noexcept
312  {
313  if ( isEmpty() )
314  return;
315 
316  static_assert ( Capacity > 0, "Ring buffer has no memory" );
317  s = std::min(s, elements);
318  head = (head + s) % Capacity;
319  elements -= s;
320  }
321 
322  private:
323  // Data members
324  std::array<value_type, Capacity> buffer;
325  value_type empty_element{};
326  std::size_t head{0U};
327  std::size_t tail{0U};
328  std::size_t elements{0U};
329 
330  // Friend classes
331  friend class CharRingBuffer<Capacity>;
332 };
333 
334 
335 //----------------------------------------------------------------------
336 // class CharRingBuffer
337 //----------------------------------------------------------------------
338 
339 template <std::size_t Capacity>
340 class CharRingBuffer final : public FRingBuffer<char, Capacity>
341 {
342  public:
343  // Using-declarations
350 
351  // Accessor
352  inline auto getClassName() const -> FString override
353  {
354  return "CharRingBuffer";
355  }
356 
357  // Method
358  auto strncmp_front (const char* string, std::size_t length) const noexcept -> bool
359  {
360  if ( length > getSize() )
361  return false;
362 
363  if ( tail > head )
364  {
365  const auto min_length = std::min(length, getCapacity());
366  return std::memcmp(string, &front(), min_length) == 0;
367  }
368 
369  auto l1 = std::min(length, getCapacity() - head);
370  auto l2 = length - l1;
371 
372  if ( std::memcmp(string, &front(), l1) != 0 )
373  return false;
374 
375  if ( l2 == 0 )
376  return true;
377 
378  return std::memcmp(string + l1, &buffer[0], l2) == 0;
379  }
380 };
381 
382 } // namespace finalcut
383 
384 #endif // CHARRINGBUFFER_H
Definition: class_template.cpp:25
Definition: fstring.h:79
Definition: char_ringbuffer.h:71
Definition: ftermoutput.h:58
Definition: char_ringbuffer.h:56