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