• 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 <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