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

Side by Side Diff: mojo/public/cpp/bindings/lib/deque.h

Issue 2900543002: Mojo C++ bindings: introduce mojo::internal::deque and use it in MultiplexRouter. (Closed)
Patch Set: . Created 3 years, 6 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 | « mojo/public/cpp/bindings/BUILD.gn ('k') | mojo/public/cpp/bindings/lib/multiplex_router.h » ('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 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef MOJO_PUBLIC_CPP_BINDINGS_LIB_DEQUE_H_
6 #define MOJO_PUBLIC_CPP_BINDINGS_LIB_DEQUE_H_
7
8 #include <algorithm>
9 #include <limits>
10 #include <vector>
11
12 #include "base/logging.h"
13 #include "base/numerics/safe_math.h"
14
15 namespace mojo {
16 namespace test {
17 template <typename T>
18 class DequeAccessor;
19 }
20
21 namespace internal {
22
23 // This class uses a std::vector as ring buffer, which is expanded when
24 // necessary.
25 // The reason to introduce this class is that std::deque is memory inefficient.
26 // (Please see crbug.com/674287 for more details.)
27 template <typename T>
28 class deque {
29 public:
30 static constexpr size_t kInvalidIndex = std::numeric_limits<size_t>::max();
31 static constexpr size_t kDefaultInitialCapacity = 4;
32
33 explicit deque(size_t initial_capacity = kDefaultInitialCapacity)
34 : buffer_(initial_capacity) {}
35
36 deque(deque&& other)
37 : front_(other.front_),
38 back_(other.back_),
39 buffer_(std::move(other.buffer_)) {
40 other.front_ = kInvalidIndex;
41 other.back_ = kInvalidIndex;
42 }
43
44 deque& operator=(deque&& other) {
45 front_ = other.front_;
46 back_ = other.back_;
47 buffer_ = std::move(other.buffer_);
48
49 other.front_ = kInvalidIndex;
50 other.back_ = kInvalidIndex;
51
52 return *this;
53 }
54
55 void push_front(const T& value) {
56 expand_if_necessary();
57 if (empty()) {
58 front_ = 0;
59 back_ = 0;
60 } else {
61 front_ = get_prev(front_);
62 }
63 buffer_[front_] = value;
64 }
65
66 void push_front(T&& value) {
67 expand_if_necessary();
68 if (empty()) {
69 front_ = 0;
70 back_ = 0;
71 } else {
72 front_ = get_prev(front_);
73 }
74 buffer_[front_] = std::forward<T>(value);
75 }
76
77 void pop_front() {
78 DCHECK(!empty());
79
80 buffer_[front_] = T();
81 if (front_ == back_) {
82 front_ = kInvalidIndex;
83 back_ = kInvalidIndex;
84 } else {
85 front_ = get_next(front_);
86 }
87 }
88
89 T& front() {
90 DCHECK(!empty());
91 return buffer_[front_];
92 }
93
94 const T& front() const {
95 DCHECK(!empty());
96 return buffer_[front_];
97 }
98
99 void push_back(const T& value) {
100 expand_if_necessary();
101 if (empty()) {
102 front_ = 0;
103 back_ = 0;
104 } else {
105 back_ = get_next(back_);
106 }
107 buffer_[back_] = value;
108 }
109
110 void push_back(T&& value) {
111 expand_if_necessary();
112 if (empty()) {
113 front_ = 0;
114 back_ = 0;
115 } else {
116 back_ = get_next(back_);
117 }
118 buffer_[back_] = std::forward<T>(value);
119 }
120
121 void pop_back() {
122 DCHECK(!empty());
123
124 buffer_[back_] = T();
125 if (front_ == back_) {
126 front_ = kInvalidIndex;
127 back_ = kInvalidIndex;
128 } else {
129 back_ = get_prev(back_);
130 }
131 }
132
133 T& back() {
134 DCHECK(!empty());
135 return buffer_[back_];
136 }
137
138 const T& back() const {
139 DCHECK(!empty());
140 return buffer_[back_];
141 }
142
143 void clear() {
144 if (empty())
145 return;
146
147 if (back_ >= front_) {
148 for (size_t i = front_; i <= back_; ++i)
149 buffer_[i] = T();
150 } else {
151 for (size_t i = front_; i < buffer_.size(); ++i)
152 buffer_[i] = T();
153 for (size_t i = 0; i <= back_; ++i)
154 buffer_[i] = T();
155 }
156
157 front_ = kInvalidIndex;
158 back_ = kInvalidIndex;
159 }
160
161 bool empty() const { return front_ == kInvalidIndex; }
162
163 private:
164 friend class ::mojo::test::DequeAccessor<T>;
165
166 size_t get_next(size_t index) {
167 DCHECK(!buffer_.empty());
168 return index != buffer_.size() - 1 ? index + 1 : 0;
169 }
170
171 size_t get_prev(size_t index) {
172 DCHECK(!buffer_.empty());
173 return index != 0 ? index - 1 : buffer_.size() - 1;
174 }
175
176 void expand_if_necessary() {
177 if (buffer_.empty()) {
178 DCHECK_EQ(kInvalidIndex, front_);
179 DCHECK_EQ(kInvalidIndex, back_);
180
181 buffer_.resize(kDefaultInitialCapacity);
182 } else {
183 // Whether the buffer still has available slots.
184 if (empty() || get_prev(front_) != back_)
185 return;
186
187 size_t original_size = buffer_.size();
188 base::CheckedNumeric<size_t> new_size = original_size;
189 new_size *= 2;
190 buffer_.resize(new_size.ValueOrDie());
191
192 // Whether we need to move part of the elements to remain a ring buffer.
193 if (front_ != 0) {
194 if (back_ < original_size / 2) {
195 // Move [0, back_] to [original_size, original_size + back_].
196 std::move(buffer_.begin(), buffer_.begin() + back_ + 1,
197 buffer_.begin() + original_size);
198 back_ += original_size;
199 } else {
200 // Move [front_, original_size - 1] to
201 // [front_ + buffer_.size() - original_size, buffer_.size() - 1].
202 size_t new_front = front_ + buffer_.size() - original_size;
203 std::move(buffer_.begin() + front_, buffer_.begin() + original_size,
204 buffer_.begin() + new_front);
205 front_ = new_front;
206 }
207 }
208 }
209 }
210
211 size_t front_ = kInvalidIndex;
212 // NOTE: |back_| is inclusive.
213 size_t back_ = kInvalidIndex;
214 // TODO(yzshen): This buffer default-constructs T instances for unoccupied
215 // slots. It would be nice to avoid that.
216 std::vector<T> buffer_;
217 };
218
219 template <typename T>
220 constexpr size_t deque<T>::kInvalidIndex;
221
222 } // namespace internal
223 } // namespace mojo
224
225 #endif // MOJO_PUBLIC_CPP_BINDINGS_LIB_DEQUE_H_
OLDNEW
« no previous file with comments | « mojo/public/cpp/bindings/BUILD.gn ('k') | mojo/public/cpp/bindings/lib/multiplex_router.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698