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