xref: /aosp_15_r20/external/pigweed/pw_containers/public/pw_containers/internal/raw_storage.h (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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