1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 #pragma once
15
16 #include <algorithm>
17 #include <array>
18 #include <cstddef>
19 #include <initializer_list>
20 #include <iterator>
21 #include <limits>
22 #include <new>
23 #include <type_traits>
24 #include <utility>
25
26 #include "pw_assert/assert.h"
27 #include "pw_polyfill/language_feature_macros.h"
28
29 namespace pw {
30 namespace vector_impl {
31
32 template <typename I>
33 using IsIterator = std::negation<
34 std::is_same<typename std::iterator_traits<I>::value_type, void>>;
35
36 // Used as max_size in the generic-size Vector<T> interface.
37 PW_INLINE_VARIABLE constexpr size_t kGeneric = size_t(-1);
38
39 // The DestructorHelper is used to make Vector<T> trivially destructible if T
40 // is. This could be replaced with a C++20 constraint.
41 template <typename VectorClass, bool kIsTriviallyDestructible>
42 class DestructorHelper;
43
44 template <typename VectorClass>
45 class DestructorHelper<VectorClass, true> {
46 public:
47 ~DestructorHelper() = default;
48 };
49
50 template <typename VectorClass>
51 class DestructorHelper<VectorClass, false> {
52 public:
~DestructorHelper()53 ~DestructorHelper() { static_cast<VectorClass*>(this)->clear(); }
54 };
55
56 } // namespace vector_impl
57
58 // The Vector class is similar to std::vector, except it is backed by a
59 // fixed-size buffer. Vectors must be declared with an explicit maximum size
60 // (e.g. Vector<int, 10>) but vectors can be used and referred to without the
61 // max size template parameter (e.g. Vector<int>).
62 //
63 // To allow referring to a pw::Vector without an explicit maximum size, all
64 // Vector classes inherit from Vector<T, vector_impl::kGeneric>, which stores
65 // the maximum size in a variable. This allows Vectors to be used without having
66 // to know their maximum size at compile time. It also keeps code size small
67 // since function implementations are shared for all maximum sizes.
68 template <typename T, size_t max_size = vector_impl::kGeneric>
69 class Vector : public Vector<T, vector_impl::kGeneric> {
70 public:
71 using typename Vector<T, vector_impl::kGeneric>::value_type;
72 using typename Vector<T, vector_impl::kGeneric>::size_type;
73 using typename Vector<T, vector_impl::kGeneric>::difference_type;
74 using typename Vector<T, vector_impl::kGeneric>::reference;
75 using typename Vector<T, vector_impl::kGeneric>::const_reference;
76 using typename Vector<T, vector_impl::kGeneric>::pointer;
77 using typename Vector<T, vector_impl::kGeneric>::const_pointer;
78 using typename Vector<T, vector_impl::kGeneric>::iterator;
79 using typename Vector<T, vector_impl::kGeneric>::const_iterator;
80 using typename Vector<T, vector_impl::kGeneric>::reverse_iterator;
81 using typename Vector<T, vector_impl::kGeneric>::const_reverse_iterator;
82
83 // Construct
Vector()84 Vector() noexcept : Vector<T, vector_impl::kGeneric>(max_size) {}
85
Vector(size_type count,const T & value)86 Vector(size_type count, const T& value)
87 : Vector<T, vector_impl::kGeneric>(max_size, count, value) {}
88
Vector(size_type count)89 explicit Vector(size_type count)
90 : Vector<T, vector_impl::kGeneric>(max_size, count, T()) {}
91
92 template <
93 typename Iterator,
94 typename...,
95 typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
Vector(Iterator first,Iterator last)96 Vector(Iterator first, Iterator last)
97 : Vector<T, vector_impl::kGeneric>(max_size, first, last) {}
98
Vector(const Vector & other)99 Vector(const Vector& other)
100 : Vector<T, vector_impl::kGeneric>(max_size, other) {}
101
102 template <size_t kOtherMaxSize>
Vector(const Vector<T,kOtherMaxSize> & other)103 Vector(const Vector<T, kOtherMaxSize>& other)
104 : Vector<T, vector_impl::kGeneric>(max_size, other) {}
105
Vector(Vector && other)106 Vector(Vector&& other) noexcept
107 : Vector<T, vector_impl::kGeneric>(max_size, std::move(other)) {}
108
109 template <size_t kOtherMaxSize>
Vector(Vector<T,kOtherMaxSize> && other)110 Vector(Vector<T, kOtherMaxSize>&& other) noexcept
111 : Vector<T, vector_impl::kGeneric>(max_size, std::move(other)) {}
112
Vector(std::initializer_list<T> list)113 Vector(std::initializer_list<T> list)
114 : Vector<T, vector_impl::kGeneric>(max_size, list) {}
115
116 Vector& operator=(const Vector& other) {
117 Vector<T>::assign(other.begin(), other.end());
118 return *this;
119 }
120
121 template <size_t kOtherMaxSize>
122 Vector& operator=(const Vector<T, kOtherMaxSize>& other) noexcept {
123 Vector<T>::assign(other.begin(), other.end());
124 return *this;
125 }
126
127 Vector& operator=(Vector&& other) noexcept {
128 Vector<T>::operator=(std::move(other));
129 return *this;
130 }
131
132 template <size_t kOtherMaxSize>
133 Vector& operator=(Vector<T, kOtherMaxSize>&& other) noexcept {
134 Vector<T>::operator=(std::move(other));
135 return *this;
136 }
137
138 Vector& operator=(std::initializer_list<T> list) {
139 this->assign(list.begin(), list.end());
140 return *this;
141 }
142
143 // All other vector methods are implemented on the Vector<T> base class.
144
145 private:
146 friend class Vector<T, vector_impl::kGeneric>;
147
148 static_assert(max_size <= std::numeric_limits<size_type>::max());
149
150 // Provides access to the underlying array as an array of T.
151 #ifdef __cpp_lib_launder
array()152 pointer array() { return std::launder(reinterpret_cast<T*>(&array_)); }
array()153 const_pointer array() const {
154 return std::launder(reinterpret_cast<const T*>(&array_));
155 }
156 #else
array()157 pointer array() { return reinterpret_cast<T*>(&array_); }
array()158 const_pointer array() const { return reinterpret_cast<const T*>(&array_); }
159 #endif // __cpp_lib_launder
160
161 // Vector entries are stored as uninitialized memory blocks aligned correctly
162 // for the type. Elements are initialized on demand with placement new.
163 //
164 // This uses std::array instead of a C array to support zero-length Vectors.
165 // Zero-length C arrays are non-standard, but std::array<T, 0> is valid.
166 // The alignas specifier is required ensure that a zero-length array is
167 // aligned the same as an array with elements.
168 alignas(T) std::array<std::aligned_storage_t<sizeof(T), alignof(T)>,
169 max_size> array_;
170 };
171
172 // Defines the generic-sized Vector<T> specialization, which serves as the base
173 // class for Vector<T> of any maximum size. Except for constructors, all Vector
174 // methods are implemented on this class.
175 template <typename T>
176 class Vector<T, vector_impl::kGeneric>
177 : public vector_impl::DestructorHelper<
178 Vector<T, vector_impl::kGeneric>,
179 std::is_trivially_destructible<T>::value> {
180 public:
181 using value_type = T;
182
183 // Use unsigned short instead of size_t. Since Vectors are statically
184 // allocated, 65535 entries is a reasonable upper limit. This reduces Vector's
185 // overhead by packing the size and capacity into 32 bits.
186 using size_type = unsigned short;
187
188 using difference_type = ptrdiff_t;
189 using reference = value_type&;
190 using const_reference = const value_type&;
191 using pointer = T*;
192 using const_pointer = const T*;
193 using iterator = T*;
194 using const_iterator = const T*;
195 using reverse_iterator = std::reverse_iterator<iterator>;
196 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
197
198 // A vector without an explicit maximum size (Vector<T>) cannot be constructed
199 // directly. Instead, construct a Vector<T, max_size>. Vectors of any max size
200 // can be used through a Vector<T> pointer or reference.
201
202 // Assign
203
204 Vector& operator=(const Vector& other) {
205 assign(other.begin(), other.end());
206 return *this;
207 }
208
209 Vector& operator=(Vector&& other) noexcept {
210 clear();
211 MoveFrom(other);
212 return *this;
213 }
214
215 Vector& operator=(std::initializer_list<T> list) {
216 assign(list);
217 return *this;
218 }
219
assign(size_type count,const T & value)220 void assign(size_type count, const T& value) {
221 clear();
222 Append(count, value);
223 }
224
225 template <
226 typename Iterator,
227 typename...,
228 typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
assign(Iterator first,Iterator last)229 void assign(Iterator first, Iterator last) {
230 clear();
231 CopyFrom(first, last);
232 }
233
assign(std::initializer_list<T> list)234 void assign(std::initializer_list<T> list) {
235 assign(list.begin(), list.end());
236 }
237
238 // Access
239
at(size_type index)240 reference at(size_type index) {
241 PW_ASSERT(index < size());
242 return data()[index];
243 }
at(size_type index)244 const_reference at(size_type index) const {
245 PW_ASSERT(index < size());
246 return data()[index];
247 }
248
249 reference operator[](size_type index) {
250 PW_DASSERT(index < size());
251 return data()[index];
252 }
253 const_reference operator[](size_type index) const {
254 PW_DASSERT(index < size());
255 return data()[index];
256 }
257
front()258 reference front() { return data()[0]; }
front()259 const_reference front() const { return data()[0]; }
260
back()261 reference back() { return data()[size() - 1]; }
back()262 const_reference back() const { return data()[size() - 1]; }
263
264 // The underlying data is not part of the generic-length vector class. It is
265 // provided in the derived class from which this instance was constructed. To
266 // access the data, down-cast this to a Vector with a known max size, and
267 // return a pointer to the start of the array, which is the same for all
268 // vectors with explicit max size.
data()269 T* data() noexcept { return static_cast<Vector<T, 0>*>(this)->array(); }
data()270 const T* data() const noexcept {
271 return static_cast<const Vector<T, 0>*>(this)->array();
272 }
273
274 // Iterate
275
begin()276 iterator begin() noexcept { return &data()[0]; }
begin()277 const_iterator begin() const noexcept { return &data()[0]; }
cbegin()278 const_iterator cbegin() const noexcept { return &data()[0]; }
279
end()280 iterator end() noexcept { return &data()[size()]; }
end()281 const_iterator end() const noexcept { return &data()[size()]; }
cend()282 const_iterator cend() const noexcept { return &data()[size()]; }
283
rbegin()284 reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
rbegin()285 const_reverse_iterator rbegin() const { return reverse_iterator(end()); }
crbegin()286 const_reverse_iterator crbegin() const noexcept {
287 return reverse_iterator(cend());
288 }
289
rend()290 reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
rend()291 const_reverse_iterator rend() const { return reverse_iterator(begin()); }
crend()292 const_reverse_iterator crend() const noexcept {
293 return reverse_iterator(cbegin());
294 }
295
296 // Size
297
empty()298 [[nodiscard]] bool empty() const noexcept { return size() == 0u; }
299
300 // True if there is no free space in the vector. Operations that add elements
301 // (push_back, insert, etc.) will fail if full() is true.
full()302 [[nodiscard]] bool full() const noexcept { return size() == max_size(); }
303
304 // Returns the number of elements in the Vector. Uses size_t instead of
305 // size_type for consistency with other containers.
size()306 size_t size() const noexcept { return size_; }
307
308 // Returns the maximum number of elements in this Vector.
max_size()309 size_t max_size() const noexcept { return max_size_; }
310
capacity()311 size_t capacity() const noexcept { return max_size(); }
312
313 // Modify
314
315 void clear() noexcept;
316
317 // TODO(hepler): insert, emplace, and erase are not yet implemented.
318 // Currently, items can only be added to or removed from the end.
319 iterator insert(const_iterator index, const T& value);
320
321 iterator insert(const_iterator index, T&& value);
322
323 iterator insert(const_iterator index, size_type count, const T& value);
324
325 template <typename Iterator>
326 iterator insert(const_iterator index, Iterator first, Iterator last);
327
328 iterator insert(const_iterator index, std::initializer_list<T> list);
329
330 template <typename... Args>
331 iterator emplace(const_iterator index, Args&&... args);
332
333 iterator erase(const_iterator index);
334
335 iterator erase(const_iterator first, const_iterator last);
336
push_back(const T & value)337 void push_back(const T& value) { emplace_back(value); }
338
push_back(T && value)339 void push_back(T&& value) { emplace_back(std::move(value)); }
340
341 template <typename... Args>
342 void emplace_back(Args&&... args);
343
344 void pop_back();
345
resize(size_type new_size)346 void resize(size_type new_size) { resize(new_size, T()); }
347
348 void resize(size_type new_size, const T& value);
349
350 protected:
351 // Vectors without an explicit size cannot be constructed directly. Instead,
352 // the maximum size must be provided.
Vector(size_type max_size)353 explicit constexpr Vector(size_type max_size) noexcept
354 : max_size_(max_size) {}
355
Vector(size_type max_size,size_type count,const T & value)356 Vector(size_type max_size, size_type count, const T& value)
357 : Vector(max_size) {
358 Append(count, value);
359 }
360
Vector(size_type max_size,size_type count)361 Vector(size_type max_size, size_type count) : Vector(max_size, count, T()) {}
362
363 template <
364 typename Iterator,
365 typename...,
366 typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
Vector(size_type max_size,Iterator first,Iterator last)367 Vector(size_type max_size, Iterator first, Iterator last) : Vector(max_size) {
368 CopyFrom(first, last);
369 }
370
Vector(size_type max_size,const Vector & other)371 Vector(size_type max_size, const Vector& other) : Vector(max_size) {
372 CopyFrom(other.begin(), other.end());
373 }
374
Vector(size_type max_size,Vector && other)375 Vector(size_type max_size, Vector&& other) noexcept : Vector(max_size) {
376 MoveFrom(other);
377 }
378
Vector(size_type max_size,std::initializer_list<T> list)379 Vector(size_type max_size, std::initializer_list<T> list) : Vector(max_size) {
380 CopyFrom(list.begin(), list.end());
381 }
382
383 private:
384 template <typename Iterator>
385 void CopyFrom(Iterator first, Iterator last);
386
387 void MoveFrom(Vector& other) noexcept;
388
389 void Append(size_type count, const T& value);
390
391 const size_type max_size_;
392 size_type size_ = 0;
393 };
394
395 // Compare
396
397 template <typename T, size_t kLhsSize, size_t kRhsSize>
398 bool operator==(const Vector<T, kLhsSize>& lhs,
399 const Vector<T, kRhsSize>& rhs) {
400 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
401 }
402
403 template <typename T, size_t kLhsSize, size_t kRhsSize>
404 bool operator!=(const Vector<T, kLhsSize>& lhs,
405 const Vector<T, kRhsSize>& rhs) {
406 return !(lhs == rhs);
407 }
408
409 template <typename T, size_t kLhsSize, size_t kRhsSize>
410 bool operator<(const Vector<T, kLhsSize>& lhs, const Vector<T, kRhsSize>& rhs) {
411 return std::lexicographical_compare(
412 lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
413 }
414
415 template <typename T, size_t kLhsSize, size_t kRhsSize>
416 bool operator<=(const Vector<T, kLhsSize>& lhs,
417 const Vector<T, kRhsSize>& rhs) {
418 return !(rhs < lhs);
419 }
420
421 template <typename T, size_t kLhsSize, size_t kRhsSize>
422 bool operator>(const Vector<T, kLhsSize>& lhs, const Vector<T, kRhsSize>& rhs) {
423 return rhs < lhs;
424 }
425
426 template <typename T, size_t kLhsSize, size_t kRhsSize>
427 bool operator>=(const Vector<T, kLhsSize>& lhs,
428 const Vector<T, kRhsSize>& rhs) {
429 return !(lhs < rhs);
430 }
431
432 // Function implementations
433
434 template <typename T>
clear()435 void Vector<T, vector_impl::kGeneric>::clear() noexcept {
436 for (auto& item : *this) {
437 item.~T();
438 }
439 size_ = 0;
440 }
441
442 template <typename T>
443 template <typename... Args>
emplace_back(Args &&...args)444 void Vector<T, vector_impl::kGeneric>::emplace_back(Args&&... args) {
445 if (!full()) {
446 new (&data()[size_]) T(std::forward<Args>(args)...);
447 size_ += 1;
448 }
449 }
450
451 template <typename T>
pop_back()452 void Vector<T, vector_impl::kGeneric>::pop_back() {
453 if (!empty()) {
454 back().~T();
455 size_ -= 1;
456 }
457 }
458
459 template <typename T>
resize(size_type new_size,const T & value)460 void Vector<T, vector_impl::kGeneric>::resize(size_type new_size,
461 const T& value) {
462 if (size() < new_size) {
463 Append(std::min(max_size(), size_t(new_size)) - size(), value);
464 } else {
465 while (size() > new_size) {
466 pop_back();
467 }
468 }
469 }
470
471 template <typename T>
472 template <typename Iterator>
CopyFrom(Iterator first,Iterator last)473 void Vector<T, vector_impl::kGeneric>::CopyFrom(Iterator first, Iterator last) {
474 while (first != last) {
475 push_back(*first++);
476 }
477 }
478
479 template <typename T>
MoveFrom(Vector & other)480 void Vector<T, vector_impl::kGeneric>::MoveFrom(Vector& other) noexcept {
481 for (auto&& item : other) {
482 emplace_back(std::move(item));
483 }
484 other.clear();
485 }
486
487 template <typename T>
Append(size_type count,const T & value)488 void Vector<T, vector_impl::kGeneric>::Append(size_type count, const T& value) {
489 for (size_t i = 0; i < count; ++i) {
490 push_back(value);
491 }
492 }
493
494 } // namespace pw
495