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 <string_view>
24 #include <type_traits>
25 #include <utility>
26
27 #include "pw_assert/assert.h"
28 #include "pw_polyfill/language_feature_macros.h"
29
30 namespace pw {
31 namespace vector_impl {
32
33 template <typename I>
34 using IsIterator = std::negation<
35 std::is_same<typename std::iterator_traits<I>::value_type, void>>;
36
37 // Used as max_size in the generic-size Vector<T> interface.
38 PW_INLINE_VARIABLE constexpr size_t kGeneric = size_t(-1);
39
40 // The DestructorHelper is used to make Vector<T> trivially destructible if T
41 // is. This could be replaced with a C++20 constraint.
42 template <typename VectorClass, bool kIsTriviallyDestructible>
43 class DestructorHelper;
44
45 template <typename VectorClass>
46 class DestructorHelper<VectorClass, true> {
47 public:
48 ~DestructorHelper() = default;
49 };
50
51 template <typename VectorClass>
52 class DestructorHelper<VectorClass, false> {
53 public:
~DestructorHelper()54 ~DestructorHelper() { static_cast<VectorClass*>(this)->clear(); }
55 };
56
57 } // namespace vector_impl
58
59 // The Vector class is similar to std::vector, except it is backed by a
60 // fixed-size buffer. Vectors must be declared with an explicit maximum size
61 // (e.g. Vector<int, 10>) but vectors can be used and referred to without the
62 // max size template parameter (e.g. Vector<int>).
63 //
64 // To allow referring to a pw::Vector without an explicit maximum size, all
65 // Vector classes inherit from Vector<T, vector_impl::kGeneric>, which stores
66 // the maximum size in a variable. This allows Vectors to be used without having
67 // to know their maximum size at compile time. It also keeps code size small
68 // since function implementations are shared for all maximum sizes.
69 template <typename T, size_t kMaxSize = vector_impl::kGeneric>
70 class Vector : public Vector<T, vector_impl::kGeneric> {
71 public:
72 using typename Vector<T, vector_impl::kGeneric>::value_type;
73 using typename Vector<T, vector_impl::kGeneric>::size_type;
74 using typename Vector<T, vector_impl::kGeneric>::difference_type;
75 using typename Vector<T, vector_impl::kGeneric>::reference;
76 using typename Vector<T, vector_impl::kGeneric>::const_reference;
77 using typename Vector<T, vector_impl::kGeneric>::pointer;
78 using typename Vector<T, vector_impl::kGeneric>::const_pointer;
79 using typename Vector<T, vector_impl::kGeneric>::iterator;
80 using typename Vector<T, vector_impl::kGeneric>::const_iterator;
81 using typename Vector<T, vector_impl::kGeneric>::reverse_iterator;
82 using typename Vector<T, vector_impl::kGeneric>::const_reverse_iterator;
83
84 // Construct
Vector()85 Vector() noexcept : Vector<T, vector_impl::kGeneric>(kMaxSize) {}
86
Vector(size_type count,const T & value)87 Vector(size_type count, const T& value)
88 : Vector<T, vector_impl::kGeneric>(kMaxSize, count, value) {}
89
Vector(size_type count)90 explicit Vector(size_type count)
91 : Vector<T, vector_impl::kGeneric>(kMaxSize, count, T()) {}
92
93 template <
94 typename Iterator,
95 typename...,
96 typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
Vector(Iterator first,Iterator last)97 Vector(Iterator first, Iterator last)
98 : Vector<T, vector_impl::kGeneric>(kMaxSize, first, last) {}
99
Vector(const Vector & other)100 Vector(const Vector& other)
101 : Vector<T, vector_impl::kGeneric>(kMaxSize, other) {}
102
103 template <size_t kOtherMaxSize>
Vector(const Vector<T,kOtherMaxSize> & other)104 Vector(const Vector<T, kOtherMaxSize>& other)
105 : Vector<T, vector_impl::kGeneric>(kMaxSize, other) {}
106
Vector(Vector && other)107 Vector(Vector&& other) noexcept
108 : Vector<T, vector_impl::kGeneric>(kMaxSize, std::move(other)) {}
109
110 template <size_t kOtherMaxSize>
Vector(Vector<T,kOtherMaxSize> && other)111 Vector(Vector<T, kOtherMaxSize>&& other) noexcept
112 : Vector<T, vector_impl::kGeneric>(kMaxSize, std::move(other)) {}
113
Vector(std::initializer_list<T> list)114 Vector(std::initializer_list<T> list)
115 : Vector<T, vector_impl::kGeneric>(kMaxSize, list) {}
116
max_size()117 static constexpr size_t max_size() { return kMaxSize; }
118
119 // Construct from std::string_view when T is char.
120 template <typename U = T,
121 typename = std::enable_if_t<std::is_same_v<U, char>>>
Vector(std::string_view source)122 Vector(std::string_view source) : Vector(source.begin(), source.end()) {}
123
124 // Construct from const char* when T is char.
125 template <typename U = T,
126 typename = std::enable_if_t<std::is_same_v<U, char>>>
Vector(const char * source)127 Vector(const char* source) : Vector(std::string_view(source)) {}
128
129 Vector& operator=(const Vector& other) {
130 Vector<T>::assign(other.begin(), other.end());
131 return *this;
132 }
133
134 template <size_t kOtherMaxSize>
135 Vector& operator=(const Vector<T, kOtherMaxSize>& other) noexcept {
136 Vector<T>::assign(other.begin(), other.end());
137 return *this;
138 }
139
140 Vector& operator=(Vector&& other) noexcept {
141 Vector<T>::operator=(std::move(other));
142 return *this;
143 }
144
145 template <size_t kOtherMaxSize>
146 Vector& operator=(Vector<T, kOtherMaxSize>&& other) noexcept {
147 Vector<T>::operator=(std::move(other));
148 return *this;
149 }
150
151 Vector& operator=(std::initializer_list<T> list) {
152 this->assign(list.begin(), list.end());
153 return *this;
154 }
155
156 // All other vector methods are implemented on the Vector<T> base class.
157
158 private:
159 friend class Vector<T, vector_impl::kGeneric>;
160
161 static_assert(kMaxSize <= std::numeric_limits<size_type>::max());
162
163 // Provides access to the underlying array as an array of T.
164 #ifdef __cpp_lib_launder
array()165 pointer array() { return std::launder(reinterpret_cast<T*>(&array_)); }
array()166 const_pointer array() const {
167 return std::launder(reinterpret_cast<const T*>(&array_));
168 }
169 #else
array()170 pointer array() { return reinterpret_cast<T*>(&array_); }
array()171 const_pointer array() const { return reinterpret_cast<const T*>(&array_); }
172 #endif // __cpp_lib_launder
173
174 // Vector entries are stored as uninitialized memory blocks aligned correctly
175 // for the type. Elements are initialized on demand with placement new.
176 //
177 // This uses std::array instead of a C array to support zero-length Vectors.
178 // Zero-length C arrays are non-standard, but std::array<T, 0> is valid.
179 // The alignas specifier is required ensure that a zero-length array is
180 // aligned the same as an array with elements.
181 alignas(T) std::array<std::aligned_storage_t<sizeof(T), alignof(T)>,
182 kMaxSize> array_;
183 };
184
185 // Defines the generic-sized Vector<T> specialization, which serves as the base
186 // class for Vector<T> of any maximum size. Except for constructors, all Vector
187 // methods are implemented on this class.
188 template <typename T>
189 class Vector<T, vector_impl::kGeneric>
190 : public vector_impl::DestructorHelper<
191 Vector<T, vector_impl::kGeneric>,
192 std::is_trivially_destructible<T>::value> {
193 public:
194 using value_type = T;
195
196 // Use unsigned short instead of size_t. Since Vectors are statically
197 // allocated, 65535 entries is a reasonable upper limit. This reduces Vector's
198 // overhead by packing the size and capacity into 32 bits.
199 using size_type = unsigned short;
200
201 using difference_type = ptrdiff_t;
202 using reference = value_type&;
203 using const_reference = const value_type&;
204 using pointer = T*;
205 using const_pointer = const T*;
206 using iterator = T*;
207 using const_iterator = const T*;
208 using reverse_iterator = std::reverse_iterator<iterator>;
209 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
210
211 // A vector without an explicit maximum size (Vector<T>) cannot be constructed
212 // directly. Instead, construct a Vector<T, kMaxSize>. Vectors of any max size
213 // can be used through a Vector<T> pointer or reference.
214
215 // Assign
216
217 Vector& operator=(const Vector& other) {
218 assign(other.begin(), other.end());
219 return *this;
220 }
221
222 Vector& operator=(Vector&& other) noexcept {
223 clear();
224 MoveFrom(other);
225 return *this;
226 }
227
228 Vector& operator=(std::initializer_list<T> list) {
229 assign(list);
230 return *this;
231 }
232
assign(size_type count,const T & value)233 void assign(size_type count, const T& value) {
234 clear();
235 Append(count, value);
236 }
237
238 template <
239 typename Iterator,
240 typename...,
241 typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
assign(Iterator first,Iterator last)242 void assign(Iterator first, Iterator last) {
243 clear();
244 CopyFrom(first, last);
245 }
246
assign(std::initializer_list<T> list)247 void assign(std::initializer_list<T> list) {
248 assign(list.begin(), list.end());
249 }
250
251 // Access
252
at(size_type index)253 reference at(size_type index) {
254 PW_ASSERT(index < size());
255 return data()[index];
256 }
at(size_type index)257 const_reference at(size_type index) const {
258 PW_ASSERT(index < size());
259 return data()[index];
260 }
261
262 reference operator[](size_type index) {
263 PW_DASSERT(index < size());
264 return data()[index];
265 }
266 const_reference operator[](size_type index) const {
267 PW_DASSERT(index < size());
268 return data()[index];
269 }
270
front()271 reference front() { return data()[0]; }
front()272 const_reference front() const { return data()[0]; }
273
back()274 reference back() { return data()[size() - 1]; }
back()275 const_reference back() const { return data()[size() - 1]; }
276
277 // The underlying data is not part of the generic-length vector class. It is
278 // provided in the derived class from which this instance was constructed. To
279 // access the data, down-cast this to a Vector with a known max size, and
280 // return a pointer to the start of the array, which is the same for all
281 // vectors with explicit max size.
data()282 T* data() noexcept { return static_cast<Vector<T, 0>*>(this)->array(); }
data()283 const T* data() const noexcept {
284 return static_cast<const Vector<T, 0>*>(this)->array();
285 }
286
287 // Iterate
288
begin()289 iterator begin() noexcept { return &data()[0]; }
begin()290 const_iterator begin() const noexcept { return &data()[0]; }
cbegin()291 const_iterator cbegin() const noexcept { return &data()[0]; }
292
end()293 iterator end() noexcept { return &data()[size()]; }
end()294 const_iterator end() const noexcept { return &data()[size()]; }
cend()295 const_iterator cend() const noexcept { return &data()[size()]; }
296
rbegin()297 reverse_iterator rbegin() noexcept { return reverse_iterator(end()); }
rbegin()298 const_reverse_iterator rbegin() const { return reverse_iterator(end()); }
crbegin()299 const_reverse_iterator crbegin() const noexcept {
300 return reverse_iterator(cend());
301 }
302
rend()303 reverse_iterator rend() noexcept { return reverse_iterator(begin()); }
rend()304 const_reverse_iterator rend() const { return reverse_iterator(begin()); }
crend()305 const_reverse_iterator crend() const noexcept {
306 return reverse_iterator(cbegin());
307 }
308
309 // Size
310
empty()311 [[nodiscard]] bool empty() const noexcept { return size() == 0u; }
312
313 // True if there is no free space in the vector. Operations that add elements
314 // (push_back, insert, etc.) will fail if full() is true.
full()315 [[nodiscard]] bool full() const noexcept { return size() == max_size(); }
316
317 // Returns the number of elements in the Vector. Uses size_t instead of
318 // size_type for consistency with other containers.
size()319 size_t size() const noexcept { return size_; }
320
321 // Returns the maximum number of elements in this Vector.
max_size()322 size_t max_size() const noexcept { return max_size_; }
323
capacity()324 size_t capacity() const noexcept { return max_size(); }
325
326 // Modify
327
328 void clear() noexcept;
329
330 iterator insert(const_iterator index, size_type count, const T& value);
331
insert(const_iterator index,const T & value)332 iterator insert(const_iterator index, const T& value) {
333 return insert(index, 1, value);
334 }
335
336 iterator insert(const_iterator index, T&& value);
337
338 template <typename Iterator>
339 iterator insert(const_iterator index, Iterator first, Iterator last);
340
insert(const_iterator index,std::initializer_list<T> list)341 iterator insert(const_iterator index, std::initializer_list<T> list) {
342 return insert(index, list.begin(), list.end());
343 }
344
345 template <typename... Args>
346 iterator emplace(const_iterator index, Args&&... args);
347
348 iterator erase(const_iterator first, const_iterator last);
349
erase(const_iterator index)350 iterator erase(const_iterator index) { return erase(index, index + 1); }
351
push_back(const T & value)352 void push_back(const T& value) { emplace_back(value); }
353
push_back(T && value)354 void push_back(T&& value) { emplace_back(std::move(value)); }
355
356 template <typename... Args>
357 void emplace_back(Args&&... args);
358
359 void pop_back();
360
resize(size_type new_size)361 void resize(size_type new_size) { resize(new_size, T()); }
362
363 void resize(size_type new_size, const T& value);
364
365 protected:
366 // Vectors without an explicit size cannot be constructed directly. Instead,
367 // the maximum size must be provided.
Vector(size_type max_size)368 explicit constexpr Vector(size_type max_size) noexcept
369 : max_size_(max_size) {}
370
Vector(size_type max_size,size_type count,const T & value)371 Vector(size_type max_size, size_type count, const T& value)
372 : Vector(max_size) {
373 Append(count, value);
374 }
375
Vector(size_type max_size,size_type count)376 Vector(size_type max_size, size_type count) : Vector(max_size, count, T()) {}
377
378 template <
379 typename Iterator,
380 typename...,
381 typename = std::enable_if_t<vector_impl::IsIterator<Iterator>::value>>
Vector(size_type max_size,Iterator first,Iterator last)382 Vector(size_type max_size, Iterator first, Iterator last) : Vector(max_size) {
383 CopyFrom(first, last);
384 }
385
Vector(size_type max_size,const Vector & other)386 Vector(size_type max_size, const Vector& other) : Vector(max_size) {
387 CopyFrom(other.begin(), other.end());
388 }
389
Vector(size_type max_size,Vector && other)390 Vector(size_type max_size, Vector&& other) noexcept : Vector(max_size) {
391 MoveFrom(other);
392 }
393
Vector(size_type max_size,std::initializer_list<T> list)394 Vector(size_type max_size, std::initializer_list<T> list) : Vector(max_size) {
395 CopyFrom(list.begin(), list.end());
396 }
397
398 private:
399 template <typename Iterator>
400 void CopyFrom(Iterator first, Iterator last);
401
402 void MoveFrom(Vector& other) noexcept;
403
404 void Append(size_type count, const T& value);
405
406 const size_type max_size_;
407 size_type size_ = 0;
408 };
409
410 // Compare
411
412 template <typename T, size_t kLhsSize, size_t kRhsSize>
413 bool operator==(const Vector<T, kLhsSize>& lhs,
414 const Vector<T, kRhsSize>& rhs) {
415 return std::equal(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
416 }
417
418 template <typename T, size_t kLhsSize, size_t kRhsSize>
419 bool operator!=(const Vector<T, kLhsSize>& lhs,
420 const Vector<T, kRhsSize>& rhs) {
421 return !(lhs == rhs);
422 }
423
424 template <typename T, size_t kLhsSize, size_t kRhsSize>
425 bool operator<(const Vector<T, kLhsSize>& lhs, const Vector<T, kRhsSize>& rhs) {
426 return std::lexicographical_compare(
427 lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
428 }
429
430 template <typename T, size_t kLhsSize, size_t kRhsSize>
431 bool operator<=(const Vector<T, kLhsSize>& lhs,
432 const Vector<T, kRhsSize>& rhs) {
433 return !(rhs < lhs);
434 }
435
436 template <typename T, size_t kLhsSize, size_t kRhsSize>
437 bool operator>(const Vector<T, kLhsSize>& lhs, const Vector<T, kRhsSize>& rhs) {
438 return rhs < lhs;
439 }
440
441 template <typename T, size_t kLhsSize, size_t kRhsSize>
442 bool operator>=(const Vector<T, kLhsSize>& lhs,
443 const Vector<T, kRhsSize>& rhs) {
444 return !(lhs < rhs);
445 }
446
447 // Function implementations
448
449 template <typename T>
clear()450 void Vector<T, vector_impl::kGeneric>::clear() noexcept {
451 if constexpr (!std::is_trivially_destructible_v<value_type>) {
452 for (auto& item : *this) {
453 item.~T();
454 }
455 }
456 size_ = 0;
457 }
458
459 template <typename T>
460 template <typename... Args>
emplace_back(Args &&...args)461 void Vector<T, vector_impl::kGeneric>::emplace_back(Args&&... args) {
462 if (!full()) {
463 new (&data()[size_]) T(std::forward<Args>(args)...);
464 size_ += 1;
465 }
466 }
467
468 template <typename T>
pop_back()469 void Vector<T, vector_impl::kGeneric>::pop_back() {
470 if (!empty()) {
471 if constexpr (!std::is_trivially_destructible_v<value_type>) {
472 back().~T();
473 }
474 size_ -= 1;
475 }
476 }
477
478 template <typename T>
resize(size_type new_size,const T & value)479 void Vector<T, vector_impl::kGeneric>::resize(size_type new_size,
480 const T& value) {
481 if (size() < new_size) {
482 Append(std::min(max_size(), size_t(new_size)) - size(), value);
483 } else {
484 while (size() > new_size) {
485 pop_back();
486 }
487 }
488 }
489
490 template <typename T>
insert(Vector<T>::const_iterator index,T && value)491 typename Vector<T>::iterator Vector<T>::insert(Vector<T>::const_iterator index,
492 T&& value) {
493 PW_DASSERT(index >= cbegin());
494 PW_DASSERT(index <= cend());
495 PW_DASSERT(!full());
496
497 iterator insertion_point = begin() + std::distance(cbegin(), index);
498 if (insertion_point == end()) {
499 emplace_back(std::move(value));
500 return insertion_point;
501 }
502
503 std::move_backward(insertion_point, end(), end() + 1);
504 *insertion_point = std::move(value);
505 ++size_;
506
507 // Return an iterator pointing to the inserted value.
508 return insertion_point;
509 }
510
511 template <typename T>
512 template <typename Iterator>
insert(Vector<T>::const_iterator index,Iterator first,Iterator last)513 typename Vector<T>::iterator Vector<T>::insert(Vector<T>::const_iterator index,
514 Iterator first,
515 Iterator last) {
516 PW_DASSERT(index >= cbegin());
517 PW_DASSERT(index <= cend());
518 PW_DASSERT(!full());
519
520 iterator insertion_point = begin() + std::distance(cbegin(), index);
521
522 const size_t insertion_count = std::distance(first, last);
523 if (insertion_count == 0) {
524 return insertion_point;
525 }
526 PW_DASSERT(size() + insertion_count <= max_size());
527
528 iterator return_value = insertion_point;
529
530 if (insertion_point != end()) {
531 std::move_backward(insertion_point, end(), end() + insertion_count);
532 }
533
534 while (first != last) {
535 *insertion_point = *first;
536 ++first;
537 ++insertion_point;
538 }
539 size_ += insertion_count;
540
541 // Return an iterator pointing to the first element inserted.
542 return return_value;
543 }
544
545 template <typename T>
insert(Vector<T>::const_iterator index,size_type count,const T & value)546 typename Vector<T>::iterator Vector<T>::insert(Vector<T>::const_iterator index,
547 size_type count,
548 const T& value) {
549 PW_DASSERT(index >= cbegin());
550 PW_DASSERT(index <= cend());
551 PW_DASSERT(size() + count <= max_size());
552
553 iterator insertion_point = begin() + std::distance(cbegin(), index);
554 if (count == size_type{}) {
555 return insertion_point;
556 }
557
558 if (insertion_point != end()) {
559 std::move_backward(insertion_point, end(), end() + count);
560 }
561
562 iterator return_value = insertion_point;
563
564 for (size_type final_count = size_ + count; size_ != final_count; ++size_) {
565 *insertion_point = value;
566 ++insertion_point;
567 }
568
569 // Return an iterator pointing to the first element inserted.
570 return return_value;
571 }
572
573 template <typename T>
erase(Vector<T>::const_iterator first,Vector<T>::const_iterator last)574 typename Vector<T>::iterator Vector<T>::erase(Vector<T>::const_iterator first,
575 Vector<T>::const_iterator last) {
576 iterator source = begin() + std::distance(cbegin(), last);
577 if (first == last) {
578 return source;
579 }
580
581 if constexpr (!std::is_trivially_destructible_v<T>) {
582 std::destroy(first, last);
583 }
584
585 iterator destination = begin() + std::distance(cbegin(), first);
586 iterator new_end = std::move(source, end(), destination);
587
588 size_ = std::distance(begin(), new_end);
589
590 // Return an iterator following the last removed element.
591 return new_end;
592 }
593
594 template <typename T>
595 template <typename Iterator>
CopyFrom(Iterator first,Iterator last)596 void Vector<T, vector_impl::kGeneric>::CopyFrom(Iterator first, Iterator last) {
597 while (first != last) {
598 push_back(*first++);
599 }
600 }
601
602 template <typename T>
MoveFrom(Vector & other)603 void Vector<T, vector_impl::kGeneric>::MoveFrom(Vector& other) noexcept {
604 for (auto&& item : other) {
605 emplace_back(std::move(item));
606 }
607 other.clear();
608 }
609
610 template <typename T>
Append(size_type count,const T & value)611 void Vector<T, vector_impl::kGeneric>::Append(size_type count, const T& value) {
612 for (size_t i = 0; i < count; ++i) {
613 push_back(value);
614 }
615 }
616
617 } // namespace pw
618