• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2021 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // CircularBuffer.h:
7 //   An array class with an index that loops through the elements.
8 //
9 
10 #ifndef COMMON_CIRCULARBUFFER_H_
11 #define COMMON_CIRCULARBUFFER_H_
12 
13 #include "common/debug.h"
14 
15 #include <algorithm>
16 #include <array>
17 
18 namespace angle
19 {
20 template <class T, size_t N, class Storage = std::array<T, N>>
21 class CircularBuffer final
22 {
23   public:
24     using value_type      = typename Storage::value_type;
25     using size_type       = typename Storage::size_type;
26     using reference       = typename Storage::reference;
27     using const_reference = typename Storage::const_reference;
28     using pointer         = typename Storage::pointer;
29     using const_pointer   = typename Storage::const_pointer;
30     using iterator        = typename Storage::iterator;
31     using const_iterator  = typename Storage::const_iterator;
32 
33     CircularBuffer();
34     CircularBuffer(const value_type &value);
35 
36     CircularBuffer(const CircularBuffer<T, N, Storage> &other);
37     CircularBuffer(CircularBuffer<T, N, Storage> &&other);
38 
39     CircularBuffer<T, N, Storage> &operator=(const CircularBuffer<T, N, Storage> &other);
40     CircularBuffer<T, N, Storage> &operator=(CircularBuffer<T, N, Storage> &&other);
41 
42     ~CircularBuffer();
43 
44     // begin() and end() are used to iterate over all elements regardless of the current position of
45     // the front of the buffer.  Useful for initialization and clean up, as otherwise only the front
46     // element is expected to be accessed.
47     iterator begin();
48     const_iterator begin() const;
49 
50     iterator end();
51     const_iterator end() const;
52 
53     size_type size() const;
54 
55     reference front();
56     const_reference front() const;
57 
58     void swap(CircularBuffer<T, N, Storage> &other);
59 
60     // Move the front forward to the next index, looping back to the beginning if the end of the
61     // array is reached.
62     void next();
63 
64   private:
65     Storage mData;
66     size_type mFrontIndex;
67 };
68 
69 template <class T, size_t N, class Storage>
CircularBuffer()70 CircularBuffer<T, N, Storage>::CircularBuffer() : mFrontIndex(0)
71 {}
72 
73 template <class T, size_t N, class Storage>
CircularBuffer(const value_type & value)74 CircularBuffer<T, N, Storage>::CircularBuffer(const value_type &value) : CircularBuffer()
75 {
76     std::fill(begin(), end(), value);
77 }
78 
79 template <class T, size_t N, class Storage>
CircularBuffer(const CircularBuffer<T,N,Storage> & other)80 CircularBuffer<T, N, Storage>::CircularBuffer(const CircularBuffer<T, N, Storage> &other)
81 {
82     *this = other;
83 }
84 
85 template <class T, size_t N, class Storage>
CircularBuffer(CircularBuffer<T,N,Storage> && other)86 CircularBuffer<T, N, Storage>::CircularBuffer(CircularBuffer<T, N, Storage> &&other)
87     : CircularBuffer()
88 {
89     swap(other);
90 }
91 
92 template <class T, size_t N, class Storage>
93 CircularBuffer<T, N, Storage> &CircularBuffer<T, N, Storage>::operator=(
94     const CircularBuffer<T, N, Storage> &other)
95 {
96     std::copy(other.begin(), other.end(), begin());
97     mFrontIndex = other.mFrontIndex;
98     return *this;
99 }
100 
101 template <class T, size_t N, class Storage>
102 CircularBuffer<T, N, Storage> &CircularBuffer<T, N, Storage>::operator=(
103     CircularBuffer<T, N, Storage> &&other)
104 {
105     swap(other);
106     return *this;
107 }
108 
109 template <class T, size_t N, class Storage>
110 CircularBuffer<T, N, Storage>::~CircularBuffer() = default;
111 
112 template <class T, size_t N, class Storage>
begin()113 ANGLE_INLINE typename CircularBuffer<T, N, Storage>::iterator CircularBuffer<T, N, Storage>::begin()
114 {
115     return mData.begin();
116 }
117 
118 template <class T, size_t N, class Storage>
119 ANGLE_INLINE typename CircularBuffer<T, N, Storage>::const_iterator
begin()120 CircularBuffer<T, N, Storage>::begin() const
121 {
122     return mData.begin();
123 }
124 
125 template <class T, size_t N, class Storage>
end()126 ANGLE_INLINE typename CircularBuffer<T, N, Storage>::iterator CircularBuffer<T, N, Storage>::end()
127 {
128     return mData.end();
129 }
130 
131 template <class T, size_t N, class Storage>
132 ANGLE_INLINE typename CircularBuffer<T, N, Storage>::const_iterator
end()133 CircularBuffer<T, N, Storage>::end() const
134 {
135     return mData.end();
136 }
137 
138 template <class T, size_t N, class Storage>
size()139 ANGLE_INLINE typename CircularBuffer<T, N, Storage>::size_type CircularBuffer<T, N, Storage>::size()
140     const
141 {
142     return N;
143 }
144 
145 template <class T, size_t N, class Storage>
146 ANGLE_INLINE typename CircularBuffer<T, N, Storage>::reference
front()147 CircularBuffer<T, N, Storage>::front()
148 {
149     ASSERT(mFrontIndex < size());
150     return mData[mFrontIndex];
151 }
152 
153 template <class T, size_t N, class Storage>
154 ANGLE_INLINE typename CircularBuffer<T, N, Storage>::const_reference
front()155 CircularBuffer<T, N, Storage>::front() const
156 {
157     ASSERT(mFrontIndex < size());
158     return mData[mFrontIndex];
159 }
160 
161 template <class T, size_t N, class Storage>
swap(CircularBuffer<T,N,Storage> & other)162 void CircularBuffer<T, N, Storage>::swap(CircularBuffer<T, N, Storage> &other)
163 {
164     std::swap(mData, other.mData);
165     std::swap(mFrontIndex, other.mFrontIndex);
166 }
167 
168 template <class T, size_t N, class Storage>
next()169 void CircularBuffer<T, N, Storage>::next()
170 {
171     mFrontIndex = (mFrontIndex + 1) % size();
172 }
173 }  // namespace angle
174 
175 #endif  // COMMON_CIRCULARBUFFER_H_
176