1 // Copyright 2023 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 <array> 17 #include <cstddef> 18 #include <new> 19 #include <type_traits> 20 21 namespace pw::containers::internal { 22 23 // Used as max_size in generic-sized interfaces using RawStorage<T>. 24 inline constexpr size_t kGenericSized = static_cast<size_t>(-1); 25 26 template <typename InputIterator> 27 using EnableIfInputIterator = std::enable_if_t<std::is_convertible< 28 typename std::iterator_traits<InputIterator>::iterator_category, 29 std::input_iterator_tag>::value>; 30 31 template <typename T> 32 using EnableIfIterable = 33 std::enable_if_t<true, decltype(T().begin(), T().end())>; 34 35 // Container similar to std::array that provides an array of Elements which are 36 // stored as uninitialized memory blocks aligned correctly for the type. 37 // 38 // The caller is responsible for constructing, accessing, and destructing 39 // elements. In addition, the caller is responsible for element access and all 40 // associated bounds checking. 41 template <typename ValueType, size_t kCapacity> 42 class RawStorage { 43 public: 44 using value_type = ValueType; 45 using size_type = size_t; 46 using difference_type = ptrdiff_t; 47 using reference = value_type&; 48 using const_reference = const value_type&; 49 using pointer = value_type*; 50 using const_pointer = const value_type*; 51 52 // Construct RawStorage()53 constexpr RawStorage() noexcept : null_bits_() {} 54 55 // Do not permit copying and move for now. 56 RawStorage(const RawStorage&) = delete; 57 RawStorage& operator=(const RawStorage&) = delete; 58 RawStorage(RawStorage&&) = delete; 59 RawStorage&& operator=(RawStorage&&) = delete; 60 data()61 pointer data() noexcept { 62 return std::launder(reinterpret_cast<pointer>(&bytes_)); 63 } data()64 const_pointer data() const noexcept { 65 return std::launder(reinterpret_cast<const_pointer>(&bytes_)); 66 } 67 size()68 constexpr size_type size() const noexcept { return max_size(); } max_size()69 constexpr size_type max_size() const noexcept { return kCapacity; } 70 71 private: 72 struct Empty {}; 73 74 union { 75 // Elements must initialized on demand with placement new, this array 76 // provides the right amount of storage needed for the elements, however it 77 // is never constructed nor destructed by the RawStorage container, as 78 // null_bits_ is used instead. 79 // 80 // This uses std::array instead of a C array to support zero-length arrays. 81 // Zero-length C arrays are non-standard, but std::array<T, 0> is valid. 82 // The alignas specifier is required ensure that a zero-length array is 83 // aligned the same as an array with elements. 84 alignas(value_type) 85 std::array<std::byte, sizeof(value_type) * kCapacity> bytes_; 86 87 // Empty struct used when initializing the storage in the constexpr 88 // constructor. 89 Empty null_bits_; 90 }; 91 }; 92 93 } // namespace pw::containers::internal 94