iceoryx2
C++ Language Bindings
Loading...
Searching...
No Matches
raw_byte_storage.hpp
Go to the documentation of this file.
1// Copyright (c) 2025 Contributors to the Eclipse Foundation
2//
3// See the NOTICE file(s) distributed with this work for additional
4// information regarding copyright ownership.
5//
6// This program and the accompanying materials are made available under the
7// terms of the Apache Software License 2.0 which is available at
8// https://www.apache.org/licenses/LICENSE-2.0, or the MIT license
9// which is available at https://opensource.org/licenses/MIT.
10//
11// SPDX-License-Identifier: Apache-2.0 OR MIT
12
13#ifndef IOX2_INCLUDE_GUARD_BB_DETAIL_RAW_BYTE_STORAGE_HPP
14#define IOX2_INCLUDE_GUARD_BB_DETAIL_RAW_BYTE_STORAGE_HPP
15
17
18#include <algorithm>
19#include <cstdint>
20#include <memory>
21#include <new>
22#include <type_traits>
23
24namespace iox2 {
25namespace bb {
26namespace detail {
27
30template <typename T, uint64_t Capacity>
32 static_assert(std::is_standard_layout<T>::value, "Storage is only valid for standard layout types.");
33
34 private:
35 // NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) raw storage, will not be used as array
36 alignas(T) char m_bytes[sizeof(T) * Capacity];
37 uint64_t m_size;
38
39 public:
40 constexpr RawByteStorage() noexcept
41 : m_bytes {}
42 , m_size(0) {
43 }
44
45 constexpr RawByteStorage(RawByteStorage const& rhs)
46 : m_bytes {}
47 , m_size(rhs.m_size) {
48 for (uint64_t index = 0; index < m_size; ++index) {
49 new (pointer_from_index(index)) T(*rhs.pointer_from_index(index));
50 }
51 }
52
53 constexpr RawByteStorage(RawByteStorage&& rhs) noexcept
54 : m_bytes {}
55 , m_size(rhs.m_size) {
56 for (uint64_t index = 0; index < m_size; ++index) {
57 new (pointer_from_index(index)) T(std::move_if_noexcept(*rhs.pointer_from_index(index)));
58 }
59 }
60
61 template <uint64_t M, std::enable_if_t<(Capacity > M), bool> = true>
62 // NOLINTNEXTLINE(hicpp-explicit-conversions), conceptually a copy constructor
64 : m_bytes {}
65 , m_size(rhs.size()) {
66 for (uint64_t index = 0; index < m_size; ++index) {
67 new (pointer_from_index(index)) T(*rhs.pointer_from_index(index));
68 }
69 }
70
71 template <uint64_t M, std::enable_if_t<(Capacity > M), bool> = true>
72 // NOLINTNEXTLINE(hicpp-explicit-conversions), conceptually a move constructor
73 constexpr RawByteStorage(RawByteStorage<T, M>&& rhs) noexcept
74 : m_bytes {}
75 , m_size(rhs.size()) {
76 for (uint64_t index = 0; index < m_size; ++index) {
77 new (pointer_from_index(index)) T(std::move_if_noexcept(*rhs.pointer_from_index(index)));
78 }
79 }
80
82 for (uint64_t i = m_size; i != 0; --i) {
83 uint64_t const index = i - 1;
84 pointer_from_index(index)->~T();
85 }
86 }
87
88 constexpr auto operator=(RawByteStorage const& rhs) -> RawByteStorage& {
89 if (&rhs != this) {
90 for (uint64_t i = 0; i < std::min(m_size, rhs.m_size); ++i) {
92 }
93 for (uint64_t i = m_size; i < rhs.m_size; ++i) {
94 //NOLINTNEXTLINE(clang-analyzer-cplusplus.PlacementNew) false positive in clang-tidy version 19 only
95 new (pointer_from_index(i)) T(*rhs.pointer_from_index(i));
96 }
97 for (uint64_t i = rhs.m_size; i < m_size; ++i) {
98 pointer_from_index(i)->~T();
99 }
100 m_size = rhs.m_size;
101 }
102 return *this;
103 }
104
105 constexpr auto operator=(RawByteStorage&& rhs) noexcept(std::is_nothrow_move_constructible<T>::value
106 && std::is_nothrow_move_assignable<T>::value)
107 -> RawByteStorage& {
108 if (&rhs != this) {
109 for (uint64_t i = 0; i < std::min(m_size, rhs.m_size); ++i) {
110 *pointer_from_index(i) = std::move(*rhs.pointer_from_index(i));
111 }
112 for (uint64_t i = m_size; i < rhs.m_size; ++i) {
113 new (pointer_from_index(i)) T(std::move(*rhs.pointer_from_index(i)));
114 }
115 for (uint64_t i = rhs.m_size; i < m_size; ++i) {
116 pointer_from_index(i)->~T();
117 }
118 m_size = rhs.m_size;
119 }
120 return *this;
121 }
122
123 auto constexpr size() const noexcept -> uint64_t {
124 return m_size;
125 }
126
127 // @pre size() < Capacity
128 template <typename... Args>
129 constexpr void emplace_back(Args&&... args) {
130 new (pointer_from_index(size())) T(std::forward<Args>(args)...);
131 ++m_size;
132 }
133
134 // @pre (size() < Capacity) && (index <= size())
135 template <typename... Args>
136 constexpr void emplace_at(uint64_t index, Args&&... args) {
137 emplace_back(std::forward<Args>(args)...);
138 rotate_from_back(index, m_size - 1);
139 }
140
141 // @pre (index <= size()) && (size() + count <= Capacity)
142 constexpr void insert_at(uint64_t index, uint64_t count, T const& value) {
143 for (uint64_t i = 0; i < count; ++i) {
144 emplace_back(value);
145 }
146 rotate_from_back(index, m_size - count);
147 }
148
149 // @pre (index < size())
150 constexpr void erase_at(uint64_t index) {
151 remove_at(index, 1);
152 shrink_from_back(m_size - 1);
153 }
154
155 // @pre (end_index <= size()) && (begin_index <= end_index)
156 constexpr void erase_at(uint64_t begin_index, uint64_t end_index) {
157 uint64_t const range = end_index - begin_index;
158 remove_at(begin_index, range);
159 shrink_from_back(m_size - range);
160 }
161
162 // @pre (index + range_size <= size())
163 constexpr void remove_at(uint64_t index, uint64_t range_size) {
164// gcc 15 generates a false positive here, where range checks performed
165// by outer functions are not taken into account correctly
166#pragma GCC diagnostic push
167#pragma GCC diagnostic ignored "-Warray-bounds"
168 std::move(pointer_from_index(index + range_size), pointer_from_index(m_size), pointer_from_index(index));
169#pragma GCC diagnostic pop
170 }
171
172 // @pre target_size < size()
173 constexpr void shrink_from_back(uint64_t target_size) {
174 for (uint64_t i = m_size; i != target_size; --i) {
175 uint64_t const index = i - 1;
176 pointer_from_index(index)->~T();
177 }
178 m_size = target_size;
179 }
180
181 // @pre (index_first_from < size()) && (index_to < index_first_from)
182 constexpr void rotate_from_back(uint64_t index_to, uint64_t index_first_from) {
183 std::rotate(pointer_from_index(index_to), pointer_from_index(index_first_from), pointer_from_index(m_size));
184 }
185
186 // @pre (idx >= 0) && (idx < size())
187 auto pointer_from_index(uint64_t idx) -> T* {
188 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast), required for storage access
189 return reinterpret_cast<T*>(m_bytes + (idx * sizeof(T)));
190 }
191
192 // @pre (idx >= 0) && (idx < size())
193 auto pointer_from_index(uint64_t idx) const -> T const* {
194 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast), required for storage access
195 return reinterpret_cast<T const*>(m_bytes + (idx * sizeof(T)));
196 }
197
198 // Memory layout metrics.
199 // Contains all relevant metrics to verify the exact layout of the storage in memory.
209
211 using Self = std::remove_reference_t<decltype(*this)>;
213 ret.storage_alignment = alignof(Self);
214 ret.storage_size = sizeof(Self);
215 ret.sizeof_bytes = sizeof(m_bytes);
216 ret.offset_bytes = offsetof(Self, m_bytes);
217 ret.sizeof_size = sizeof(m_size);
218 ret.offset_size = offsetof(Self, m_size);
219 ret.size_is_unsigned = std::is_unsigned<decltype(m_size)>::value;
220 return ret;
221 }
222};
223} // namespace detail
224} // namespace bb
225} // namespace iox2
226
227#endif // IOX2_INCLUDE_GUARD_BB_DETAIL_RAW_BYTE_STORAGE_HPP
#define IOX2_CONSTEXPR_DTOR
constexpr auto operator=(RawByteStorage const &rhs) -> RawByteStorage &
constexpr void remove_at(uint64_t index, uint64_t range_size)
auto pointer_from_index(uint64_t idx) const -> T const *
constexpr void insert_at(uint64_t index, uint64_t count, T const &value)
auto constexpr size() const noexcept -> uint64_t
constexpr void shrink_from_back(uint64_t target_size)
constexpr RawByteStorage(RawByteStorage< T, M > &&rhs) noexcept
auto pointer_from_index(uint64_t idx) -> T *
constexpr RawByteStorage(RawByteStorage< T, M > const &rhs)
IOX2_CONSTEXPR_DTOR ~RawByteStorage()
constexpr RawByteStorage(RawByteStorage &&rhs) noexcept
constexpr void emplace_back(Args &&... args)
constexpr RawByteStorage(RawByteStorage const &rhs)
constexpr auto operator=(RawByteStorage &&rhs) noexcept(std::is_nothrow_move_constructible< T >::value &&std::is_nothrow_move_assignable< T >::value) -> RawByteStorage &
constexpr void erase_at(uint64_t begin_index, uint64_t end_index)
constexpr void erase_at(uint64_t index)
constexpr void rotate_from_back(uint64_t index_to, uint64_t index_first_from)
constexpr auto static_memory_layout_metrics() noexcept -> StorageMemoryLayoutMetrics
constexpr void emplace_at(uint64_t index, Args &&... args)