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