• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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