Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(327)

Side by Side Diff: webrtc/base/numerics/cyclic_buffer.h

Issue 2691073002: New implementation of generic cyclic buffer.
Patch Set: Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « webrtc/base/BUILD.gn ('k') | webrtc/base/numerics/cyclic_buffer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /*
2 * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #ifndef WEBRTC_BASE_NUMERICS_CYCLIC_BUFFER_H_
12 #define WEBRTC_BASE_NUMERICS_CYCLIC_BUFFER_H_
13
14 #include <utility> // for move
15
16 #include "webrtc/base/checks.h"
17
18 namespace webrtc {
19
20 enum GrowthPolicy { ASSERT = 0, DISCARD_OLDEST, GROW_BUFFER };
21
22 template <typename T, GrowthPolicy policy>
23 class CyclicBuffer {
24 public:
25 explicit CyclicBuffer(size_t size);
26 ~CyclicBuffer();
27
28 // TODO(terelius): Check what happens if size_ == capacity_ == 1
29 // TODO(terelius): Overload for rvalue references. Refactor to avoid code
30 // duplication.
31 void push_back(const T& elem) {
32 T* new_position = extend_back();
33 *new_position = elem;
34 }
35
36 void push_back(T&& elem) {
37 T* new_position = extend_back();
38 *new_position = std::move(elem);
39 }
40
41 void push_front(const T& elem) {
42 T* new_position = extend_front();
43 *new_position = elem;
44 }
45
46 void push_front(T&& elem) {
47 T* new_position = extend_front();
48 *new_position = std::move(elem);
49 }
50
51 void pop_front() {
52 RTC_DCHECK_GT(size_, 0);
53 if (size_ == 1) {
54 head_ = tail_ = nullptr;
55 size_ = 0;
56 return;
57 }
58
59 head_++;
60 if (head_ == buffer_end_)
61 head_ = buffer_begin_;
62 size_--;
63 }
64
65 void pop_back() {
66 RTC_DCHECK_GT(size_, 0);
67 if (size_ == 1) {
68 head_ = tail_ = nullptr;
69 size_ = 0;
70 return;
71 }
72
73 if (tail_ == buffer_begin_)
74 tail_ = buffer_end_;
75 tail_--;
76 size_--;
77 }
78
79 T& front() {
80 RTC_DCHECK_GT(size_, 0);
81 return *head_;
82 }
83
84 const T& front() const {
85 RTC_DCHECK_GT(size_, 0);
86 return *head_;
87 }
88
89 T& back() {
90 RTC_DCHECK_GT(size_, 0);
91 return *tail_;
92 }
93
94 const T& back() const {
95 RTC_DCHECK_GT(size_, 0);
96 return *tail_;
97 }
98
99 size_t size() const { return size_; }
100
101 size_t capacity() const { return capacity_; }
102
103 // TODO(terelius): Implement resize() instead? Make it private?
104 void Grow(size_t new_capacity) {
105 RTC_DCHECK_GT(new_capacity, capacity_);
106 T* new_buffer = new T[new_capacity];
107 T* read_it = head_;
108 T* write_it = new_buffer;
109 if (size_ > 0) {
110 // Copy the contents to the new buffer
111 do {
112 *write_it = *read_it;
113 write_it++;
114 read_it++;
115 if (read_it == buffer_end_)
116 read_it = buffer_begin_;
117 } while (read_it != tail_);
118 }
119
120 delete[] buffer_begin_;
121 buffer_begin_ = new_buffer;
122 buffer_end_ = buffer_begin_ + new_capacity;
123 capacity_ = new_capacity;
124 head_ = buffer_begin_;
125 tail_ = buffer_begin_ + size_ - 1;
126 }
127
128 private:
129 T* extend_back();
130 T* extend_front();
131
132 T* buffer_begin_;
133 T* buffer_end_;
134 T* head_;
135 T* tail_;
136 size_t capacity_;
137 size_t size_;
138 };
139
140 template <typename T, GrowthPolicy policy>
141 CyclicBuffer<T, policy>::CyclicBuffer(size_t capacity)
142 : buffer_begin_(nullptr),
143 buffer_end_(nullptr),
144 head_(nullptr),
145 tail_(nullptr),
146 capacity_(capacity),
147 size_(0) {
148 RTC_CHECK(capacity > 0);
149 buffer_begin_ = new T[capacity];
150 buffer_end_ = buffer_begin_ + capacity;
151 }
152
153 template <typename T, GrowthPolicy policy>
154 CyclicBuffer<T, policy>::~CyclicBuffer() {
155 delete[] buffer_begin_;
156 }
157
158 // TODO(terelius): Handle capacity 0?
159 // TODO(terelius): Verify correctness for capacity 1.
160 template <typename T, GrowthPolicy policy>
161 T* CyclicBuffer<T, policy>::extend_back() {
162 if (size_ == 0) {
163 head_ = tail_ = buffer_begin_;
164 size_++;
165 return tail_;
166 }
167
168 // Ensure there is enough space to insert the element.
169 if (policy == ASSERT) {
170 RTC_DCHECK_LT(size_, capacity_);
171 } else if (policy == DISCARD_OLDEST && size_ == capacity_) {
172 pop_front(); // Redundant if we discard oldest element below.
173 } else if (policy == GROW_BUFFER && size_ == capacity_) {
174 Grow(2 * capacity_ + 1);
175 }
176 // Find next place to insert.
177 tail_++;
178 if (tail_ == buffer_end_)
179 tail_ = buffer_begin_;
180
181 // Discard oldest element if buffer is full.
182 if (tail_ == head_) {
183 head_++;
184 if (head_ == buffer_end_)
185 head_ = buffer_begin_;
186 size_--;
187 }
188
189 // Insert element.
190 size_++;
191 return tail_;
192 }
193
194 // TODO(terelius): Handle capacity 0?
195 // TODO(terelius): Verify correctness for capacity 1.
196 template <typename T, GrowthPolicy policy>
197 T* CyclicBuffer<T, policy>::extend_front() {
198 if (size_ == 0) {
199 head_ = tail_ = buffer_begin_;
200 size_++;
201 return tail_;
202 }
203
204 // Ensure there is enough space to insert the element.
205 if (policy == ASSERT) {
206 RTC_DCHECK_LT(size_, capacity_);
207 } else if (policy == DISCARD_OLDEST && size_ == capacity_) {
208 pop_back(); // Redundant if we discard oldest element below.
209 } else if (policy == GROW_BUFFER && size_ == capacity_) {
210 Grow(2 * capacity_ + 1);
211 }
212 // Find next place to insert.
213 if (head_ == buffer_begin_)
214 head_ = buffer_end_;
215 head_--;
216
217 // Discard oldest element if buffer is full.
218 if (head_ == tail_) {
219 if (tail_ == buffer_begin_)
220 tail_ = buffer_end_;
221 tail_--;
222 size_--;
223 }
224
225 // Insert element.
226 size_++;
227 return head_;
228 }
229
230 } // namespace webrtc
231
232 #endif // WEBRTC_BASE_NUMERICS_CYCLIC_BUFFER_H_
OLDNEW
« no previous file with comments | « webrtc/base/BUILD.gn ('k') | webrtc/base/numerics/cyclic_buffer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698