Arene Base
Fundamental Utilities For Safety Critical C++
Loading...
Searching...
No Matches
deque.hpp
Go to the documentation of this file.
1// Copyright 2026, Toyota Motor Corporation
2//
3// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
4
5#ifndef INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_DEQUE_HPP_
6#define INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_DEQUE_HPP_
7
8#include "arene/base/algorithm/copy.hpp"
9#include "arene/base/algorithm/rotate.hpp"
10#include "arene/base/array/array.hpp"
11#include "arene/base/constraints/constraints.hpp"
12#include "arene/base/contracts/contract.hpp"
13#include "arene/base/inline_container/detail/iterator_interface.hpp"
14#include "arene/base/inline_container/detail/range_interface.hpp"
15#include "arene/base/inline_container/detail/try_construct_interface.hpp"
16#include "arene/base/inline_container/detail/unsafe_element_storage.hpp"
17#include "arene/base/iterator/distance.hpp"
18#include "arene/base/iterator/next.hpp"
19#include "arene/base/memory/construct_at.hpp"
20#include "arene/base/stdlib_choice/cstddef.hpp"
21#include "arene/base/stdlib_choice/declval.hpp"
22#include "arene/base/stdlib_choice/enable_if.hpp"
23#include "arene/base/stdlib_choice/forward.hpp"
24#include "arene/base/stdlib_choice/ignore.hpp"
25#include "arene/base/stdlib_choice/initializer_list.hpp"
26#include "arene/base/stdlib_choice/integral_constant.hpp"
27#include "arene/base/stdlib_choice/is_constructible.hpp"
28#include "arene/base/stdlib_choice/is_copy_assignable.hpp"
29#include "arene/base/stdlib_choice/is_copy_constructible.hpp"
30#include "arene/base/stdlib_choice/is_default_constructible.hpp"
31#include "arene/base/stdlib_choice/is_move_assignable.hpp"
32#include "arene/base/stdlib_choice/is_move_constructible.hpp"
33#include "arene/base/stdlib_choice/is_same.hpp"
34#include "arene/base/stdlib_choice/is_trivially_copyable.hpp"
35#include "arene/base/stdlib_choice/iterator_tags.hpp"
36#include "arene/base/stdlib_choice/iterator_traits.hpp"
37#include "arene/base/stdlib_choice/min_value_overload.hpp"
38#include "arene/base/stdlib_choice/move.hpp"
39#include "arene/base/stdlib_choice/numeric_limits.hpp"
40#include "arene/base/type_manipulation/non_constructible_dummy.hpp"
41#include "arene/base/type_traits/conditional.hpp"
42#include "arene/base/type_traits/iterator_category_traits.hpp"
43#include "arene/base/utility/safe_comparisons.hpp"
44
45// parasoft-begin-suppress AUTOSAR-M2_10_1-a-2 "Similar names permitted by M2-10-1 Permit #1"
46
47namespace arene {
48namespace base {
49
50namespace inline_deque_detail {
51
52/// @brief Performs an optimized modulo operation when @c value is constrained to be in <c>[0, 2*modulus)</c>
53/// @tparam T The type of the arguments; must be the same for both arguments to prevent unwanted promotions
54/// @param value Value to be used in the modulo operation
55/// @param modulus Modulus to be used in the modulo operation
56/// @return @c value mod @c modulus (note this is always positive, unlike the @c % remainder operator)
57/// @pre <c>0 <= value < 2*modulus</c>, otherwise the result will be incorrect
58template <typename T>
59constexpr auto constrained_modulo(T value, T modulus) noexcept -> T {
60 return value < modulus ? value : value - modulus;
61}
62
63// parasoft-begin-suppress AUTOSAR-A7_1_5-a "False positive: Function uses trailing return type, not auto"
64/// @brief Get the first index after @c current_front which is *not* in the deque (so it can be added)
65/// @param current_front The current front index of a deque
66/// @param capacity The capacity of the deque which @c current_front is an index of
67/// @return The physical index one toward the front of <c>current_front</c>, wrapped to stay in bounds
68/// @note This impl function takes @c capacity as a runtime parameter in order to improve test coverage.
69constexpr auto next_at_front_impl(std::size_t const current_front, std::size_t const capacity) noexcept -> std::size_t {
70 return current_front > 0U ? current_front - 1U : capacity - 1U;
71}
72// parasoft-end-suppress AUTOSAR-A7_1_5-a
73
74/// @brief Aggregate object for holding a bundle of physical indices encountered when iterating over a deque
75struct physical_indices {
76 /// @brief Sentinel value for the logical end of the deque; does not correspond to a physical index
77 static constexpr std::size_t logical_end{std::numeric_limits<std::size_t>::max()};
78
79 /// @brief Current physical index being iterated over
80 std::size_t current;
81 /// @brief Physical index of the logical front of the deque
82 std::size_t front;
83 /// @brief Physical index of the logical back of the deque
84 std::size_t back;
85 /// @brief Capacity of the deque
86 std::size_t capacity;
87};
88
89/// @brief ring-buffer indices independent of the contained value type
90/// @tparam Capacity The capacity of the deque
91/// @tparam AllowWrapping Whether index wraparound is allowed (true) or treated as a precondition violation (false)
92template <std::size_t Capacity, bool AllowWrapping>
93class ring_buffer_indices {
94 public:
95 /// @brief The type used to hold the size
96 using size_type = std::size_t;
97
98 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "False positive: this is not 'member data', it is a public property"
99 /// @brief Alias to @c Capacity with type @c size_type to reduce the required conversions
100 static constexpr std::integral_constant<size_type, Capacity> capacity{};
101 // parasoft-end-suppress AUTOSAR-M11_0_1-a
102
103 /// @brief Get the index to the back of the deque
104 /// @return the back index
105 constexpr auto back_index() const noexcept -> size_type { return n_from_front(size() - 1U); }
106
107 /// @brief Get the index @c offset elements from the back of the deque
108 /// @param offset The offset from the back
109 /// @return The index @c offset elements from the back, wrapped to stay in bounds
110 /// @pre <c>offset < size()</c> or the returned index will be invalid
111 constexpr auto n_from_back(size_type offset) const noexcept -> size_type {
112 return n_from_front(size() - 1U - offset);
113 }
114
115 /// @brief Get the index of the front of the deque
116 /// @return the front index
117 constexpr auto front_index() const noexcept -> size_type { return front_; }
118
119 /// @brief Get the index @c offset elements back from the front of the queue
120 /// @param offset The offset from the front
121 /// @return The index @c offset elements from the front, wrapped to stay in bounds
122 /// @pre <c>offset < capacity()</c> or the returned index will be invalid
123 constexpr auto n_from_front(size_type offset) const noexcept -> size_type {
124 return constrained_modulo(front_index() + offset, capacity());
125 }
126
127 /// @brief Get the first index after @c front_index() which is *not* in the deque (so it can be added)
128 /// @return The physical index one toward the front of <c>front</c>, wrapped to stay in bounds
129 constexpr auto next_at_front() const noexcept -> size_type { return next_at_front_impl(front_index(), capacity()); }
130
131 /// @brief Get the first index after @c back_index() which is *not* in the deque (so it can be added)
132 /// @return The physical index one toward the back of <c>back</c>, wrapped to stay in bounds
133 constexpr auto next_at_back() const noexcept -> size_type { return n_from_front(size()); }
134
135 /// @brief Get the number of elements
136 /// @return the size
137 constexpr auto size() const noexcept -> size_type { return size_; }
138
139 /// @brief Check if the number of elements is zero
140 /// @return @c true if the number of elements is zero, @c false otherwise
141 constexpr auto empty() const noexcept -> bool { return size() == 0U; }
142
143 /// @brief Shrink the buffer by removing space for one or more elements at the front
144 /// @param amount The amount to grow by
145 constexpr void shrink_at_front(size_type amount = 1U) noexcept {
146 front_ = n_from_front(amount);
147 size_ -= amount;
148 }
149
150 /// @brief Shrink the buffer by removing space for one element at the back
151 constexpr void shrink_at_back() noexcept { --size_; }
152
153 /// @brief Grow the buffer by adding space for one element at the front
154 constexpr void grow_at_front() noexcept {
155 front_ = next_at_front();
156 ++size_;
157 }
158
159 /// @brief Grow the buffer by adding space for one or more elements at the back
160 /// @param amount The amount to grow by
161 constexpr void grow_at_back(size_type amount = 1U) noexcept { size_ += amount; }
162
163 /// @brief Get a bundle of all of the physical indices relevant to iteration over a deque
164 /// @param current_index Physical index currently being iterated over
165 /// @return A bundle of @c current_index along with the front, back, and capacity of the deque
166 /// @note This is provided as a runtime value so that functions using it are not capacity-dependent templates
167 constexpr auto get_physical_indices(std::size_t current_index) const noexcept -> physical_indices {
168 return {current_index, front_index(), back_index(), capacity()};
169 }
170
171 private:
172 /// @brief Index of the front of the deque (the lowest/leftmost populated index)
173 size_type front_{0U};
174 /// @brief Number of elements
175 size_type size_{0U};
176};
177
178template <std::size_t Capacity, bool AllowWrapping>
179constexpr std::integral_constant<typename ring_buffer_indices<Capacity, AllowWrapping>::size_type, Capacity>
180 ring_buffer_indices<Capacity, AllowWrapping>::capacity;
181
182/// @brief An interface for @c inline_deque_internal_storage to conditionally allow storage to wrap around
183/// @tparam Derived The derived class using this interface
184/// @tparam AllowWrapping Whether to allow wrapping (if true) or treat it as a precondition violation (if false)
185/// @note This is the version where wrapping is allowed, in which space will be cleared out from the opposite side
186template <typename Derived, bool AllowWrapping>
187class storage_wrapping_interface {
188 /// @brief Get a reference to the current instance cast down to the derived class
189 /// @return @c *this as a <c>Derived&</c>
190 constexpr auto derived() noexcept -> Derived& { return static_cast<Derived&>(*this); }
191
192 protected:
193 /// @brief Ensure that space is available at the back, either as a precondition check or by clearing space when full
194 /// @pre If @c AllowWrapping is <c>false</c> and <c>size() >= capacity()</c>, crashes with a precondition violation
195 /// @post If this function returns, there is at least one free space at the back of the deque
196 constexpr auto ensure_space_at_back() noexcept -> void {
197 if (derived().size() == Derived::capacity()) {
198 using value_type = typename Derived::value_type;
199
200 // To make space at the *back*, we clear an entry off of the *front*
201 // parasoft-begin-suppress CERT_C-ERR33-a "False positive: at_buffer_idx's return value is used"
202 // parasoft-begin-suppress CERT_C-POS54-a "False positive: at_buffer_idx's return value is used"
203 // parasoft-begin-suppress AUTOSAR-A0_1_2-a "False positive: at_buffer_idx's return value is used"
204 derived().at_buffer_idx(derived().front_index()).~value_type();
205 derived().shrink_at_front();
206 // parasoft-end-suppress CERT_C-ERR33-a
207 // parasoft-end-suppress CERT_C-POS54-a
208 // parasoft-end-suppress AUTOSAR-A0_1_2-a
209 }
210 }
211
212 /// @brief Ensure that space is available at the front, either as a precondition check or by clearing space when full
213 /// @pre If @c AllowWrapping is <c>false</c> and <c>size() >= capacity()</c>, crashes with a precondition violation
214 /// @post If this function returns, there is at least one free space at the front of the deque
215 constexpr auto ensure_space_at_front() noexcept -> void {
216 if (derived().size() == Derived::capacity()) {
217 using value_type = typename Derived::value_type;
218
219 // To make space at the *front*, we clear an entry off of the *back*
220 // parasoft-begin-suppress CERT_C-ERR33-a "False positive: at_buffer_idx's return value is used"
221 // parasoft-begin-suppress CERT_C-POS54-a "False positive: at_buffer_idx's return value is used"
222 // parasoft-begin-suppress AUTOSAR-A0_1_2-a "False positive: at_buffer_idx's return value is used"
223 derived().at_buffer_idx(derived().back_index()).~value_type();
224 derived().shrink_at_back();
225 // parasoft-end-suppress CERT_C-ERR33-a
226 // parasoft-end-suppress CERT_C-POS54-a
227 // parasoft-end-suppress AUTOSAR-A0_1_2-a
228 }
229 }
230};
231
232/// @brief An interface for @c inline_deque_internal_storage to conditionally allow storage to wrap around
233/// @tparam Derived The derived class using this interface
234/// @note This is the version where wrapping is not allowed, with a precondition check that the deque is not full
235template <typename Derived>
236class storage_wrapping_interface<Derived, false> {
237 /// @brief Get an immutable reference to the current instance cast down to the derived class
238 /// @return @c *this as a <c>Derived const&</c>
239 constexpr auto derived() const noexcept -> Derived const& { return static_cast<Derived const&>(*this); }
240
241 protected:
242 /// @brief Ensure that space is available at the back, either as a precondition check or by clearing space when full
243 /// @pre If @c AllowWrapping is <c>false</c> and <c>size() >= capacity()</c>, crashes with a precondition violation
244 /// @post If this function returns, there is at least one free space at the back of the deque
245 constexpr auto ensure_space_at_back() const noexcept -> void {
246 ARENE_PRECONDITION(derived().size() < Derived::capacity());
247 }
248
249 /// @brief Ensure that space is available at the front, either as a precondition check or by clearing space when full
250 /// @pre If @c AllowWrapping is <c>false</c> and <c>size() >= capacity()</c>, crashes with a precondition violation
251 /// @post If this function returns, there is at least one free space at the front of the deque
252 constexpr auto ensure_space_at_front() const noexcept -> void {
253 ARENE_PRECONDITION(derived().size() < Derived::capacity());
254 }
255};
256
257// parasoft-begin-suppress AUTOSAR-A1_1_1-c "False positive: this class defines all special member functions"
258// parasoft-begin-suppress CERT_CPP-MEM51-c "False positive: this class defines all special member functions"
259// parasoft-begin-suppress AUTOSAR-M14_5_3-a "False positive: this does have a copy assignment operator"
260// parasoft-begin-suppress AUTOSAR-A14_5_1-a "False positive: this does have a copy constructor"
261// parasoft-begin-suppress AUTOSAR-A12_0_1-a "False positive: this does have a copy constructor and assignment operator"
262// parasoft-begin-suppress AUTOSAR-A10_1_1-a "Multiple inheritance to provide mixin member function implementation"
263/// @brief Base class for @c inline_deque that holds the elements
264/// @note This specialization applies when @c T is not trivially constructible or not trivially copyable.
265/// @tparam T The type of the elements
266/// @tparam Capacity The capacity of the deque
267/// @tparam AllowWrapping Whether index wraparound is allowed (true) or treated as a precondition violation (false)
268template <
269 typename T,
270 std::size_t Capacity,
271 bool AllowWrapping,
272 bool = std::is_trivially_default_constructible<T>::value && std::is_trivially_copyable<T>::value>
273// NOLINTNEXTLINE(hicpp-special-member-functions)
274class inline_deque_internal_storage
275 : private array<inline_container::detail::unsafe_element_storage<T>, Capacity>
276 , private ring_buffer_indices<Capacity, AllowWrapping>
277 , protected storage_wrapping_interface<inline_deque_internal_storage<T, Capacity, AllowWrapping>, AllowWrapping> {
278 protected:
279 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "Friend mechanism allows mixin to access protected member functions"
280 /// @brief This mixin needs access to the class's protected and private members; it's only used inside this class
281 friend storage_wrapping_interface<inline_deque_internal_storage, AllowWrapping>;
282 // parasoft-end-suppress AUTOSAR-A11_3_1-a
283
284 /// @brief The type used to hold the size
285 using size_type = typename ring_buffer_indices<Capacity, AllowWrapping>::size_type;
286 /// @brief The type of the values stored
287 using value_type = T;
288 /// @brief The type of a reference to a value stored
289 using reference = value_type&;
290 /// @brief The type of a const reference to a value stored
291 using const_reference = value_type const&;
292
293 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "False positive: this is not 'member data', it is a public property"
294 /// @brief Get the maximum number of elements in the storage, @c Capacity
295 static constexpr std::integral_constant<size_type, Capacity> capacity{};
296 // parasoft-end-suppress AUTOSAR-M11_0_1-a
297
298 /// @brief Check the current _logical size_ of the container
299 /// @note Specifying this causes it to override @c array::size which is the _buffer size_ (i.e. the capacity)
300 using ring_buffer_indices<Capacity, AllowWrapping>::size;
301
302 /// @brief Check if the current _logical size_ of the container is 0
303 /// @note Specifying this causes it to override @c array::empty which uses the _buffer size_ (i.e. the capacity)
304 using ring_buffer_indices<Capacity, AllowWrapping>::empty;
305
306 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::front_index
307 using ring_buffer_indices<Capacity, AllowWrapping>::front_index;
308
309 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::back_index
310 using ring_buffer_indices<Capacity, AllowWrapping>::back_index;
311
312 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::n_from_front
313 using ring_buffer_indices<Capacity, AllowWrapping>::n_from_front;
314
315 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::n_from_back
316 using ring_buffer_indices<Capacity, AllowWrapping>::n_from_back;
317
318 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::get_physical_indices
319 using ring_buffer_indices<Capacity, AllowWrapping>::get_physical_indices;
320
321 private:
322 /// @brief underlying element type that allows a value to exist or not exist
323 using element_storage = inline_container::detail::unsafe_element_storage<T>;
324
325 // parasoft-begin-suppress CERT_C-PRE31-c-3 "False positive: static_assert is a compile-time assert and can have no
326 // side-effects"
327 static_assert(alignof(element_storage) == alignof(T), "Alignment must be the same");
328 // parasoft-end-suppress CERT_C-PRE31-c-3
329 static_assert(sizeof(element_storage) == sizeof(T), "Size must be the same");
330
331 /// @brief The type of the argument to the "copy constructor": either @c
332 /// inline_deque_internal_storage to provide a real copy constructor if @c T is
333 /// copy-constructible, or @c non_constructible_dummy otherwise.
334 using copy_constructor_arg =
335 conditional_t<std::is_copy_constructible<T>::value, inline_deque_internal_storage, non_constructible_dummy>;
336
337 /// @brief The type of the argument to the "copy assignment operator": either @c
338 /// inline_deque_internal_storage to provide a real copy assignment operator if @c T is
339 /// copy-constructible and copy-assignable, or @c non_constructible_dummy otherwise.
340 using copy_assignment_arg = conditional_t<
341 std::is_copy_constructible<T>::value && std::is_copy_assignable<T>::value,
342 inline_deque_internal_storage,
343 non_constructible_dummy>;
344
345 /// @brief The type of the argument to the "move constructor": either @c
346 /// inline_deque_internal_storage to provide a real move constructor if @c T is
347 /// move-constructible, or @c non_constructible_dummy otherwise.
348 using move_constructor_arg =
349 conditional_t<std::is_move_constructible<T>::value, inline_deque_internal_storage, non_constructible_dummy>;
350
351 /// @brief The type of the argument to the "move assignment operator": either @c
352 /// inline_deque_internal_storage to provide a real move assignment operator if @c T is
353 /// move-constructible and move-assignable, or @c non_constructible_dummy otherwise.
354 using move_assignment_arg = conditional_t<
355 std::is_move_constructible<T>::value && std::is_move_assignable<T>::value,
356 inline_deque_internal_storage,
357 non_constructible_dummy>;
358
359 protected:
360 /// @brief Constructs the storage with no elements
361 constexpr inline_deque_internal_storage() = default;
362
363 /// @brief Construct storage from a range of elements, taken to be in front -> back order
364 /// @tparam Iterator The type of the iterators to construct from
365 /// @param in_begin An iterator to the beginning (front) of the input range
366 /// @param in_end An iterator to the end (back+1) of the input range
367 /// @pre <c>distance(in_begin, in_end) >= 0</c> and <c><= capacity()</c>, otherwise @c ARENE_PRECONDITION violation
368 template <typename Iterator>
369 constexpr inline_deque_internal_storage(Iterator in_begin, Iterator in_end) noexcept(
370 noexcept(::arene::base::distance(in_begin, in_end)) &&
371 std::is_nothrow_constructible<T, typename std::iterator_traits<Iterator>::reference>::value
372 )
373 : ::arene::base::array<element_storage, Capacity>{} {
374 typename std::iterator_traits<Iterator>::difference_type const distance{::arene::base::distance(in_begin, in_end)};
375 ARENE_PRECONDITION(distance >= 0);
376 ARENE_PRECONDITION(static_cast<size_type>(distance) <= capacity);
377
378 while (in_begin != in_end) {
379 std::ignore = emplace_back(*in_begin);
380 // parasoft-begin-suppress AUTOSAR-M5_0_15-a "False positive: this is iterator arithmetic, not pointer-specific"
381 ++in_begin;
382 // parasoft-end-suppress AUTOSAR-M5_0_15-a
383 }
384 }
385
386 /// @brief Copy constructor if @c T is copy-constructible, otherwise
387 /// conversion from @c non_constructible_dummy. If copying, copies
388 /// alive elements from @c other into @c *this.
389 /// @param other The source
390 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) This is a copy constructor
391 constexpr inline_deque_internal_storage(copy_constructor_arg const& other
392 ) noexcept(std::is_nothrow_copy_constructible<T>::value) {
393 for (inline_deque_internal_storage::size_type i{}; i < other.size(); i++) {
394 std::ignore = emplace_front(other[other.n_from_back(i)].object);
395 }
396 }
397
398 // parasoft-begin-suppress AUTOSAR-A15_5_1-b "noexcept specification is set based on that of the element type"
399 /// @brief Move constructor if @c T is move-constructible, useless conversion from @c
400 /// non_constructible_dummy otherwise.
401 /// @param other The source
402 /// @post @c other is empty
403 // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions) This is a move constructor
404 constexpr inline_deque_internal_storage(move_constructor_arg&& other
405 ) noexcept(std::is_nothrow_move_constructible<T>::value) {
406 for (inline_deque_internal_storage::size_type i{}; i < other.size(); i++) {
407 std::ignore = emplace_front(std::move(other[other.n_from_back(i)].object));
408 }
409 other.clear();
410 }
411 // parasoft-end-suppress AUTOSAR-A15_5_1-b
412
413 // parasoft-begin-suppress AUTOSAR-A15_5_3-h "False positive: this is noexcept(false) when it can throw"
414 // parasoft-begin-suppress CERT_CPP-ERR50-h "False positive: this is noexcept(false) when it can throw"
415 // parasoft-begin-suppress CERT_CPP-ERR55-a "False positive: this is noexcept(false) when it can throw"
416 /// @brief Copy assignment operator if @c T is copy-constructible, useless
417 /// assignment from @c non_constructible_dummy otherwise.
418 /// @param other The source
419 /// @return @c *this
420 constexpr auto operator=(copy_assignment_arg const& other
421 ) noexcept(std::is_nothrow_copy_constructible<T>::value && std::is_nothrow_copy_assignable<T>::value)
422 -> inline_deque_internal_storage& {
423 if (&other != this) {
424 // If *this is bigger than other, first shrink so that they match
425 while (this->size() > other.size()) {
426 pop_back();
427 }
428
429 // Assign as many elements as possible (however many already exist)
430 inline_deque_internal_storage::size_type assignments{std::min(this->size(), other.size())};
431 for (inline_deque_internal_storage::size_type i{}; i < assignments; ++i) {
432 (*this)[this->n_from_back(i)].object = other[other.n_from_back(i)].object;
433 }
434
435 // If other is bigger than *this, push in additional elements after the assignments
436 if (this->size() < other.size()) {
437 size_type const pushes{other.size() - this->size()};
438 for (inline_deque_internal_storage::size_type i{}; i < pushes; ++i) {
439 std::ignore = emplace_front(other[other.n_from_back(assignments + i)].object);
440 }
441 }
442 }
443 return *this;
444 }
445
446 // parasoft-begin-suppress AUTOSAR-A15_5_1-b "noexcept specification is set based on that of the element type"
447 /// @brief Move assignment operator if @c T is move-constructible, useless
448 /// assignment from @c non_constructible_dummy otherwise.
449 /// Move assigns over all of the elements of @c *this that are already alive, then move constructs remaining elements
450 /// if @c other.size() was greater than @c this->size()
451 /// @param other The source
452 /// @post @c other is empty
453 /// @return @c *this
454 constexpr auto operator=(move_assignment_arg&& other
455 ) noexcept(std::is_nothrow_move_constructible<T>::value && std::is_nothrow_move_assignable<T>::value)
456 -> inline_deque_internal_storage& {
457 if (&other != this) {
458 size_type const target_size{other.size()};
459
460 // If *this is bigger than other, first shrink so that they match
461 while (this->size() > target_size) {
462 pop_back();
463 }
464
465 // Assign as many elements as possible (however many already exist)
466 for (inline_deque_internal_storage::size_type i{}; i < this->size(); ++i) {
467 (*this)[this->n_from_back(i)].object = std::move(other[other.back_index()].object);
468 other.pop_back();
469 }
470
471 // If other is bigger than *this, push in additional elements after the assignments
472 while (this->size() < target_size) {
473 std::ignore = emplace_front(std::move(other[other.back_index()].object));
474 other.pop_back();
475 }
476
477 other.clear();
478 }
479 return *this;
480 }
481 // parasoft-end-suppress AUTOSAR-A15_5_3-h
482 // parasoft-end-suppress CERT_CPP-ERR50-h
483 // parasoft-end-suppress CERT_CPP-ERR55-a
484 // parasoft-end-suppress AUTOSAR-A15_5_1-b
485
486 /// @brief Destroy all alive elements
487 ~inline_deque_internal_storage() { clear(); }
488
489 // parasoft-begin-suppress AUTOSAR-A15_5_3-h "False positive: this is noexcept(false) when it can throw"
490 // parasoft-begin-suppress CERT_CPP-ERR50-h "False positive: this is noexcept(false) when it can throw"
491 // parasoft-begin-suppress CERT_CPP-ERR55-a "False positive: this is noexcept(false) when it can throw"
492 /// @brief Construct a new element at the front
493 /// @tparam Args The types of the arguments
494 /// @param args The constructor arguments
495 /// @return A reference to the emplaced element
496 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
497 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c back() is removed and iterators
498 /// pointing to it are invalidated.
499 template <typename... Args>
500 constexpr auto emplace_front(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) -> T& {
501 this->ensure_space_at_front();
502 T& new_ref{*construct_at(&(*this)[this->next_at_front()].object, std::forward<Args>(args)...)};
503 this->grow_at_front();
504 return new_ref;
505 }
506
507 /// @brief Construct a new element at the front
508 /// @tparam Args The types of the arguments
509 /// @param args The constructor arguments
510 /// @return A reference to the emplaced element
511 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
512 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c front() is removed and iterators
513 /// pointing to it are invalidated.
514 template <typename... Args>
515 constexpr auto emplace_back(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) -> T& {
516 this->ensure_space_at_back();
517 T& new_ref{*construct_at(&(*this)[this->next_at_back()].object, std::forward<Args>(args)...)};
518 this->grow_at_back();
519 return new_ref;
520 }
521 // parasoft-end-suppress AUTOSAR-A15_5_3-h
522 // parasoft-end-suppress CERT_CPP-ERR50-h
523 // parasoft-end-suppress CERT_CPP-ERR55-a
524
525 /// @brief Destroy the element at the front and decrease the size
526 /// @pre <c>size() > 0</c>, otherwise @c ARENE_PRECONDITION violation
527 constexpr void pop_front() noexcept {
528 ARENE_PRECONDITION(this->size() > size_type{});
529 (*this)[this->front_index()].object.~T();
530 this->shrink_at_front();
531 }
532
533 /// @brief Destroy the element at the back and decrease the size
534 /// @pre <c>size() > 0</c>, otherwise @c ARENE_PRECONDITION violation
535 constexpr void pop_back() noexcept {
536 ARENE_PRECONDITION(this->size() > size_type{});
537 (*this)[this->back_index()].object.~T();
538 this->shrink_at_back();
539 }
540
541 /// @brief Perform an unchecked dereference of the element at the given *physical buffer* index
542 /// @param buffer_idx The *physical* index to dereference; assumed to refer to a currently-valid element
543 /// @return A const reference to the element at *physical* index @c idx
544 constexpr auto at_buffer_idx(std::size_t buffer_idx) const noexcept -> const_reference {
545 return (*this)[buffer_idx].object;
546 }
547
548 /// @brief Perform an unchecked dereference of the element at the given *physical buffer* index
549 /// @param buffer_idx The *physical* index to dereference; assumed to refer to a currently-valid element
550 /// @return A mutable reference to the element at *physical* index @c idx
551 constexpr auto at_buffer_idx(std::size_t buffer_idx) noexcept -> reference { return (*this)[buffer_idx].object; }
552
553 private:
554 /// @brief Empties the storage
555 constexpr void clear() noexcept {
556 while (!this->empty()) {
557 pop_back();
558 }
559 }
560};
561// parasoft-end-suppress AUTOSAR-A1_1_1-c
562// parasoft-end-suppress CERT_CPP-MEM51-c
563// parasoft-end-suppress AUTOSAR-M14_5_3-a
564// parasoft-end-suppress AUTOSAR-A14_5_1-a
565// parasoft-end-suppress AUTOSAR-A12_0_1-a
566// parasoft-end-suppress AUTOSAR-A10_1_1-a
567
568// parasoft-begin-suppress AUTOSAR-A10_1_1-a "Multiple inheritance to provide mixin member function implementation"
569/// @brief Base class for @c inline_deque that holds the elements
570/// @note This specialization applies when @c T is both trivially constructible and trivially copyable.
571/// @tparam T The type of the elements
572/// @tparam Capacity The capacity of the deque
573/// @tparam AllowWrapping Whether index wraparound is allowed (true) or treated as a precondition violation (false)
574template <typename T, std::size_t Capacity, bool AllowWrapping>
575class inline_deque_internal_storage<T, Capacity, AllowWrapping, true>
576 : private array<T, Capacity>
577 , private ring_buffer_indices<Capacity, AllowWrapping>
578 , protected storage_wrapping_interface<inline_deque_internal_storage<T, Capacity, AllowWrapping>, AllowWrapping> {
579 protected:
580 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "Friend mechanism allows mixin to access protected member functions"
581 /// @brief This mixin needs access to the class's protected and private members; it's only used inside this class
582 friend storage_wrapping_interface<inline_deque_internal_storage, AllowWrapping>;
583 // parasoft-end-suppress AUTOSAR-A11_3_1-a
584
585 /// @brief The type used to hold the size
586 using size_type = typename ring_buffer_indices<Capacity, AllowWrapping>::size_type;
587 /// @brief The type of a value stored
588 using value_type = T;
589 /// @brief The type of a reference to a value stored
590 using reference = value_type&;
591 /// @brief The type of a const reference to a value stored
592 using const_reference = value_type const&;
593
594 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "False positive: this is not 'member data', it is a public property"
595 /// @brief Get the maximum number of elements in the deque, @c Capacity
596 static constexpr std::integral_constant<size_type, Capacity> capacity{};
597 // parasoft-end-suppress AUTOSAR-M11_0_1-a
598
599 /// @brief Check the current _logical size_ of the container
600 /// @note Specifying this causes it to override @c array::size which is the _buffer size_ (i.e. the capacity)
601 using ring_buffer_indices<Capacity, AllowWrapping>::size;
602
603 /// @brief Check if the current _logical size_ of the container is 0
604 /// @note Specifying this causes it to override @c array::empty which uses the _buffer size_ (i.e. the capacity)
605 using ring_buffer_indices<Capacity, AllowWrapping>::empty;
606
607 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::front_index
608 using ring_buffer_indices<Capacity, AllowWrapping>::front_index;
609
610 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::back_index
611 using ring_buffer_indices<Capacity, AllowWrapping>::back_index;
612
613 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::n_from_front
614 using ring_buffer_indices<Capacity, AllowWrapping>::n_from_front;
615
616 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::n_from_back
617 using ring_buffer_indices<Capacity, AllowWrapping>::n_from_back;
618
619 /// @copydoc ring_buffer_indices<Capacity, AllowWrapping>::get_physical_indices
620 using ring_buffer_indices<Capacity, AllowWrapping>::get_physical_indices;
621
622 // parasoft-begin-suppress AUTOSAR-A12_7_1-a "False positive: defining with =default would not be constexpr"
623 /// @brief Constructs the storage with no elements
624 constexpr inline_deque_internal_storage() noexcept
625 : array<T, Capacity>{},
626 ring_buffer_indices<Capacity, AllowWrapping>{},
627 storage_wrapping_interface<inline_deque_internal_storage, AllowWrapping>{} {}
628 // parasoft-end-suppress AUTOSAR-A12_7_1-a
629
630 /// @brief Construct storage from a range of elements, taken to be in front -> back order
631 /// @tparam Iterator The type of the iterators to construct from
632 /// @param in_begin An iterator to the beginning (front) of the input range
633 /// @param in_end An iterator to the end (back+1) of the input range
634 /// @pre <c>distance(in_begin, in_end) >= 0</c> and <c><= capacity()</c>, otherwise @c ARENE_PRECONDITION violation
635 template <typename Iterator>
636 constexpr inline_deque_internal_storage(Iterator in_begin, Iterator in_end) noexcept(noexcept(
637 ::arene::base::distance(in_begin, in_end)
638 ) && noexcept(::arene::base::copy(in_begin, in_end, std::declval<array<T, Capacity>&>().begin())))
639 : ::arene::base::array<T, Capacity>{} {
640 auto const count = ::arene::base::distance(in_begin, in_end);
641 ARENE_PRECONDITION((count >= 0) && (static_cast<std::size_t>(count) <= capacity()));
642
643 typename ::arene::base::array<T, Capacity>::iterator const new_end{
644 ::arene::base::copy(in_begin, in_end, this->begin())
645 };
646
647 // Cast here is OK because the returned value of copy will always be equal to or after this->begin()
648 this->grow_at_back(static_cast<std::size_t>(::arene::base::distance(this->begin(), new_end)));
649 }
650
651 /// @brief Construct a new element at the front
652 /// @tparam Args The types of the arguments
653 /// @param args The constructor arguments
654 /// @return A reference to the emplaced element
655 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
656 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c back() is removed and iterators
657 /// pointing to it are invalidated.
658 template <typename... Args>
659 constexpr auto emplace_front(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) -> T& {
660 this->ensure_space_at_front();
661
662 // parasoft-begin-suppress AUTOSAR-A5_2_2-a "False positive: not a C-cast, generic syntax needed for constructors"
663 T& new_ref{((*this)[this->next_at_front()] = T(std::forward<Args>(args)...))};
664 // parasoft-end-suppress AUTOSAR-A5_2_2-a
665
666 this->grow_at_front();
667 return new_ref;
668 }
669
670 /// @brief Construct a new element at the front
671 /// @tparam Args The types of the arguments
672 /// @param args The constructor arguments
673 /// @return A reference to the emplaced element
674 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
675 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c front() is removed and iterators
676 /// pointing to it are invalidated.
677 template <typename... Args>
678 constexpr auto emplace_back(Args&&... args) noexcept(std::is_nothrow_constructible<T, Args...>::value) -> T& {
679 this->ensure_space_at_back();
680
681 // parasoft-begin-suppress AUTOSAR-A5_2_2-a "False positive: not a C-cast, generic syntax needed for constructors"
682 T& new_ref{((*this)[this->next_at_back()] = T(std::forward<Args>(args)...))};
683 // parasoft-end-suppress AUTOSAR-A5_2_2-a
684
685 this->grow_at_back();
686 return new_ref;
687 }
688
689 /// @brief Decrease the size by one element from the front
690 /// @pre <c>size() > 0</c>, otherwise @c ARENE_PRECONDITION violation
691 constexpr void pop_front() noexcept {
692 ARENE_PRECONDITION(this->size() > size_type{});
693 this->shrink_at_front();
694 }
695
696 /// @brief Decrease the size by one element from the back
697 /// @pre <c>size() > 0</c>, otherwise @c ARENE_PRECONDITION violation
698 constexpr void pop_back() noexcept {
699 ARENE_PRECONDITION(this->size() > size_type{});
700 this->shrink_at_back();
701 }
702
703 /// @brief Perform an unchecked dereference of the element at the given *physical buffer* index
704 /// @param buffer_idx The *physical* index to dereference; assumed to refer to a currently-valid element
705 /// @return A const reference to the element at *physical* index @c idx
706 constexpr auto at_buffer_idx(std::size_t buffer_idx) const noexcept -> const_reference { return (*this)[buffer_idx]; }
707
708 /// @brief Perform an unchecked dereference of the element at the given *physical buffer* index
709 /// @param buffer_idx The *physical* index to dereference; assumed to refer to a currently-valid element
710 /// @return A mutable reference to the element at *physical* index @c idx
711 constexpr auto at_buffer_idx(std::size_t buffer_idx) noexcept -> reference { return (*this)[buffer_idx]; }
712};
713// parasoft-end-suppress AUTOSAR-A10_1_1-a
714
715template <typename T, std::size_t Capacity, bool AllowWrapping, bool IsTrivial>
716constexpr std::integral_constant<
717 typename inline_deque_internal_storage<T, Capacity, AllowWrapping, IsTrivial>::size_type,
718 Capacity>
719 inline_deque_internal_storage<T, Capacity, AllowWrapping, IsTrivial>::capacity;
720
721template <typename T, std::size_t Capacity, bool AllowWrapping>
722constexpr std::
723 integral_constant<typename inline_deque_internal_storage<T, Capacity, AllowWrapping, true>::size_type, Capacity>
724 inline_deque_internal_storage<T, Capacity, AllowWrapping, true>::capacity;
725
726// parasoft-begin-suppress AUTOSAR-A7_1_5-a "False positive: Functions use trailing return type, not auto"
727
728/// @brief Return the physical index of the logical element one step forward in the container (i.e. toward the back)
729/// @param indices Current physical indices of iteration over a deque
730/// @return The physical index of the element which is one logical step after @c indices.current
731/// @note This function takes all parameters as runtime arguments so that all branches can be covered
732constexpr auto step_logical_index_forward(physical_indices const& indices) noexcept -> std::size_t {
733 // Stepping forward from the logical back falls off the edge of the logical indices, going to the special end index.
734 if (indices.current == indices.back) {
735 return indices.logical_end;
736 }
737
738 // Stepping forward from the physical back requires wrapping to the physical front.
739 if (indices.current == indices.capacity - 1U) {
740 return std::size_t{};
741 }
742
743 // If the current index is neither the physical nor logical back, then just increment it.
744 return indices.current + 1U;
745}
746
747/// @brief Return the physical index of the logical element one step backward in the container (i.e. toward the front)
748/// @param indices Current physical indices of iteration over a deque
749/// @return The physical index of the element which is one logical step before @c indices.current
750/// @note This function takes all parameters as runtime arguments so that all branches can be covered
751constexpr auto step_logical_index_backward(physical_indices const& indices) noexcept -> std::size_t {
752 // Stepping backward from the special end index enters the deque at the current logical back.
753 if (indices.current == indices.logical_end) {
754 return indices.back;
755 }
756
757 // Stepping backward from the physical front requires wrapping to the physical back.
758 if (indices.current == std::size_t{}) {
759 return indices.capacity - 1U;
760 }
761
762 // If the current index is neither the physical nor logical front, then just decrement it.
763 return indices.current - 1U;
764}
765
766/// @brief Return the current logical index corresponding to the given physical index
767/// @param indices Current physical indices of iteration over a deque
768/// @return The logical index corresponding to <c>indices.current</c>, where @c indices.front is logical 0
769/// @note This function takes all parameters as runtime arguments so that all branches can be covered
770constexpr auto get_logical_index_impl(physical_indices const& indices) noexcept -> std::ptrdiff_t {
771 std::size_t const shifted_idx{
772 indices.front <= indices.current ? indices.current : indices.current + indices.capacity
773 };
774 return static_cast<std::ptrdiff_t>(shifted_idx) - static_cast<std::ptrdiff_t>(indices.front);
775}
776
777/// @brief Policy struct required by @c inline_container::detail::try_construct_interface to fill in basic information
778/// @tparam T Value type parameter of an @c inline_deque
779/// @tparam Capacity Capacity parameter of an @c inline_deque
780template <class T, std::size_t Capacity>
781class inline_deque_try_construct_policy {
782 public:
783 /// @brief The @c size_type of the corresponding @c inline_deque
784 using size_type = std::size_t;
785 /// @brief The @c value_type of the corresponding @c inline_deque
786 using value_type = T;
787 /// @brief A function to get the capacity of the corresponding @c inline_deque
788 /// @return The static capacity of the corresponding @c inline_deque
789 static constexpr auto capacity_of() noexcept -> size_type { return Capacity; }
790};
791
792// parasoft-end-suppress AUTOSAR-A7_1_5-a
793
794// parasoft-begin-suppress AUTOSAR-A10_1_1-a "Multiple inheritance to provide mixin member function implementation"
795/// @brief A container with fixed capacity featuring constant time insertion and
796/// removal at opposite ends; i.e., with an interface similar to std::queue. The
797/// storage for the elements is held directly within the class.
798/// @tparam T The type of each element
799/// @tparam Capacity The maximum number of elements that can be stored
800/// @tparam AllowWrapping Whether index wraparound is allowed (true) or treated as a precondition violation (false)
801template <typename T, std::size_t Capacity, bool AllowWrapping>
802class inline_deque_impl
803 : private inline_deque_detail::inline_deque_internal_storage<T, Capacity, AllowWrapping>
804 , public inline_container::detail::range_interface<inline_deque_impl<T, Capacity, AllowWrapping>> {
805 private:
806 /// @brief Shorthand to the internal type containing the element storage
807 using storage_type = inline_deque_detail::inline_deque_internal_storage<T, Capacity, AllowWrapping>;
808
809 /// @brief Shorthand to the mixin type that synthesizes range functions based on the iterator defined below
810 using range_interface = inline_container::detail::range_interface<inline_deque_impl>;
811
812 // parasoft-begin-suppress AUTOSAR-A12_1_5-a "False positive: none of these constructors can be delegated"
813 /// @brief An iterator for an @c inline_deque_impl which automatically wraps at @c Capacity so that it stays in bounds
814 /// @tparam IsConst @c true if this is a <c>const_iterator</c>, @c false if it's a normal @c iterator
815 /// @note Iterators are stored referring to particular physical elements so that they remain valid even when other
816 /// elements are removed from the deque. This matches the invalidation characteristics of <c>std::deque</c>.
817 template <bool IsConst>
818 class cyclical_iterator : public inline_container_detail::iterator_interface<cyclical_iterator<IsConst>> {
819 private:
820 /// @brief Shorthand to the mixin type that synthesizes iterator functions based on the manually-defined ones below
821 using iterator_interface = inline_container_detail::iterator_interface<cyclical_iterator<IsConst>>;
822
823 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "Friendship allows conversion from non-const iterator to const iterator
824 // without exposing implementation details."
825 friend cyclical_iterator<true>;
826 // parasoft-end-suppress AUTOSAR-A11_3_1-a
827
828 public:
829 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False Positive: identifiers at class/namespace scope are exempt"
830 /// @brief The value type of the iterator; same as the @c inline_deque_impl itself
831 using value_type = T;
832 /// @brief The pointer type of the iterator; given as a template parameter
833 using pointer = conditional_t<IsConst, T const*, T*>;
834 /// @brief The reference type of the iterator; determined by the pointer type
835 using reference = decltype(*std::declval<pointer>());
836 /// @brief The difference type of the iterator; determined by the pointer type
837 using difference_type = decltype(std::declval<pointer>() - std::declval<pointer>());
838 /// @brief The iterator category; random access because the logical space is effectively a flat array
839 using iterator_category = std::random_access_iterator_tag;
840 // parasoft-end-suppress AUTOSAR-A2_10_1-e
841
842 // The size of the logical space spanned by these iterators is one larger than the size of the deque, so the type
843 // used to represent capacity must have room to be incremented once, and this must be representable as a difference.
844 // parasoft-begin-suppress CERT_C-PRE31-c-3 "False positive: static_assert can have no side-effects"
845 static_assert(
846 Capacity <= std::numeric_limits<std::size_t>::max(),
847 "inline_deque capacity() + 1U must be representable using the type of capacity()"
848 );
849 static_assert(
850 cmp_less_equal(Capacity + 1U, std::numeric_limits<difference_type>::max()),
851 "inline_deque capacity must be expressable as its iterator's difference_type"
852 );
853 // parasoft-end-suppress CERT_C-PRE31-c-3
854
855 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "False positive: this is not 'member data', it is a public property"
856 /// @brief The sentinel index used to distinguish the "end" iterator from any valid iterator pointing to an element
857 /// @note This special value is necessary because otherwise there would be no way to distinguish between @c begin()
858 /// and @c end() for a full @c inline_deque_impl
859 static constexpr std::integral_constant<std::size_t, std::numeric_limits<std::size_t>::max()> end_index{};
860 // parasoft-end-suppress AUTOSAR-M11_0_1-a
861
862 /// @brief Default-construct an iterator pointing to no queue in particular
863 /// @note Using this iterator will never result in undefined behaviour, but it's also not very useful.
864 /// It will crash when dereferenced or incremented, and will never compare equal to non-default iterators.
865 /// The existence of a default constructor is required in order to satisfy the requirements of a forward (or higher)
866 /// iterator.
867 constexpr cyclical_iterator() noexcept
868 : iterator_interface(),
869 deque_(nullptr),
870 idx_(end_index) {}
871
872 /// @brief Construct a @c cyclical_iterator pointing to a given element of a given deque
873 /// @param deque A reference to the @c inline_deque_impl instance which is creating this iterator; will be saved
874 /// @param idx The starting index of this iterator *within the physical buffer, not within the deque*
875 constexpr cyclical_iterator(
876 conditional_t<IsConst, inline_deque_impl const&, inline_deque_impl&> deque,
877 std::size_t idx
878 ) noexcept
879 : iterator_interface(),
880 deque_(&deque),
881 idx_(idx) {}
882
883 /// @brief Implicit converting constructor for turning a non-const iterator into a const one
884 /// @tparam Enable Dummy template parameter to enable SFINAE; this constructor only exists for mutable -> const
885 /// @param non_const A non-const iterator for the same underlying deque type
886 template <bool Enable = IsConst, constraints<std::enable_if_t<Enable>> = nullptr>
887 // NOLINTNEXTLINE(hicpp-explicit-conversions) This must be implicit to comply with [container.reqmts]
888 constexpr cyclical_iterator(cyclical_iterator<!Enable> non_const) noexcept
889 : iterator_interface(),
890 deque_(non_const.deque_),
891 idx_(non_const.idx_) {}
892
893 // parasoft-begin-suppress AUTOSAR-M9_3_1-a "False positive: returned reference is not to member data of this class"
894 /// @brief Dereference the iterator
895 /// @return A reference to the currently pointed-to element
896 /// @pre @c *this is not the end iterator, otherwise @c ARENE_PRECONDITION violation
897 /// @pre @c *this has not been invalidated (e.g. by popping its element), otherwise the behaviour is undefined
898 constexpr auto operator*() const noexcept -> reference {
899 // Like in wrapped_iterator, we enforce the relatively cheap precondition that this isn't the end iterator,
900 // but do not enforce the expensive-to-check precondition that the iterator is currently in bounds of the deque.
901 ARENE_PRECONDITION(idx_ != end_index);
902 return deque_->at_buffer_idx(idx_);
903 }
904 // parasoft-end-suppress AUTOSAR-M9_3_1-a
905
906 /// @brief Shift the iterator by a given signed distance
907 /// @param diff Signed distance by which to shift the current iterator
908 /// @return A reference to the current iterator
909 /// @pre Applying @c step_forward @c diff times (if <c>diff > 0</c>) or applying @c step_backward @c -diff times
910 /// (if <c>diff < 0</c>) results in a valid iterator, otherwise the behaviour is undefined
911 constexpr auto operator+=(difference_type diff) noexcept -> cyclical_iterator& {
912 // Increments are computed in the logical index space of size deque_->size() + 1.
913
914 set_logical_index(get_logical_index() + diff);
915
916 return *this;
917 }
918
919 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "Hidden friends permitted by A11-3-1 Permit #2 v1.0.0"
920 // parasoft-begin-suppress AUTOSAR-A0_1_3-a "False positive: Function is public and used in other translation units"
921 // parasoft-begin-suppress AUTOSAR-A7_1_5-a "False positive: Function uses trailing return type, not auto"
922 /// @brief Compute the difference between two iterators
923 /// @param lhs The left of the two iterators
924 /// @param rhs The right of the two iterators
925 /// @return The difference between the iterators, i.e. a signed number @c n such that <c>lhs == rhs + n</c>
926 /// @pre The two iterators must refer to the same <c>inline_deque_impl</c>, else precondition violation
927 friend constexpr auto operator-(cyclical_iterator const& lhs, cyclical_iterator const& rhs) noexcept
928 -> difference_type {
929 ARENE_PRECONDITION(lhs.deque_ == rhs.deque_);
930
931 // This operation needs to take place in the logical index space of size deque_->size() + 1.
932
933 difference_type const logical_lhs_idx{lhs.get_logical_index()};
934 difference_type const logical_rhs_idx{rhs.get_logical_index()};
935
936 return logical_lhs_idx - logical_rhs_idx;
937 }
938
939 /// @brief Compare two iterators for equality
940 /// @param lhs The left iterator to compare
941 /// @param rhs The right iterator to compare
942 /// @return @c true if both iterators refer to the same element of the same deque, otherwise @c false
943 /// @note We use this manually-defined equality operator instead of the one synthesized by the mixin so that two
944 /// iterators from different deques compare unequal, rather than causing a precondition violation. The ordered
945 /// comparisons use the synthesized <c> operator< </c> and therefore crash if the deque doesn't match.
946 friend constexpr auto operator==(cyclical_iterator const& lhs, cyclical_iterator const& rhs) noexcept -> bool {
947 return (lhs.deque_ == rhs.deque_) && (lhs.idx_ == rhs.idx_);
948 }
949 // parasoft-end-suppress AUTOSAR-A11_3_1-a
950 // parasoft-end-suppress AUTOSAR-A0_1_3-a
951 // parasoft-end-suppress AUTOSAR-A7_1_5-a
952
953 /// @brief Get the current physical index of this iterator
954 /// @return The current physical index within the underlying buffer of the element pointed to by this iterator
955 constexpr auto physical_index() const noexcept -> std::size_t { return idx_; }
956
957 private:
958 /// @brief Get the current size of the logical index space for the pointed-to @c deque_
959 /// @return The size of the pointed-to @c deque_ plus one for the end index
960 constexpr auto logical_space_size() const noexcept -> difference_type {
961 return static_cast<difference_type>(deque_->size() + 1U);
962 }
963
964 /// @brief Get the current logical index of this iterator
965 /// @return The logical index, i.e. the distance from the current @c front() to the pointed-to element
966 constexpr auto get_logical_index() const noexcept -> difference_type {
967 if (idx_ == end_index()) {
968 ARENE_PRECONDITION(deque_ != nullptr);
969 return static_cast<difference_type>(deque_->size());
970 }
971
972 // It's impossible to form a non-end iterator to a null deque_, so we don't need to check for null here.
973 // The logical index is the distance from the front to the current idx_, counted cyclically in physical space.
974 return inline_deque_detail::get_logical_index_impl(deque_->get_physical_indices(idx_));
975 }
976
977 /// @brief Set the current logical index of this iterator to a given value
978 /// @param logical_idx The new logical index, i.e. the distance from the current @c front() to the element
979 /// @pre <c>logical_idx >= 0 && logical_idx <= logical_space_size()</c> (note: less than *or equal to*), otherwise
980 /// the behaviour is undefined
981 constexpr auto set_logical_index(difference_type logical_idx) noexcept -> void {
982 if (logical_idx + 1 == logical_space_size()) {
983 idx_ = end_index();
984 } else {
985 idx_ = inline_deque_detail::constrained_modulo(
986 deque_->front_index() + static_cast<std::size_t>(logical_idx),
987 capacity()
988 );
989 }
990 }
991
992 /// @brief Customization point used by @c iterator_interface to increment the iterator by 1 step
993 /// @pre @c *this points to a valid, non-empty deque, otherwise the behaviour is undefined
994 /// @pre @c *this is not an end iterator, otherwise the behaviour is undefined
995 /// @post @c *this is shifted forward to the next valid element, or becomes the end iterator if there are no more
996 /// valid elements.
997 constexpr auto do_step_forward() noexcept -> void {
998 idx_ = inline_deque_detail::step_logical_index_forward(deque_->get_physical_indices(idx_));
999 }
1000
1001 /// @brief Customization point used by @c iterator_interface to decrement the iterator by 1 step
1002 /// @pre @c *this points to a valid, non-empty deque, otherwise the behaviour is undefined
1003 /// @pre @c *this does not point to the front element, otherwise the behaviour is undefined
1004 /// @post @c *this is shifted backward to the next valid element. If @c this is an end iterator before stepping, it
1005 /// now points to the last (back) element.
1006 constexpr auto do_step_backward() noexcept -> void {
1007 idx_ = inline_deque_detail::step_logical_index_backward(deque_->get_physical_indices(idx_));
1008 }
1009
1010 // parasoft-begin-suppress AUTOSAR-A11_3_1-a "Use of a friend function with passkey improves encapsulation. It
1011 // allows data members to remain private and does not unnecessarily expose a public member function."
1012 // parasoft-begin-suppress AUTOSAR-A0_1_3-a "False positive: Function is public and used in other translation units"
1013 // parasoft-begin-suppress AUTOSAR-A7_1_1-a "Declaring 'iter' as reference to const changes semantics"
1014 // parasoft-begin-suppress AUTOSAR-M7_1_2-c "Declaring 'iter' as reference to const changes semantics"
1015 // parasoft-begin-suppress AUTOSAR-A8_4_9-a "Declaring 'iter' as reference to const changes semantics"
1016 // parasoft-begin-suppress AUTOSAR-A7_1_5-a "False positive: Function uses trailing return type, not auto"
1017
1018 /// @brief Customization point used by @c iterator_interface to increment the iterator by 1 step
1019 /// @param self The iterator to be incremented
1020 /// @pre @c *this is not an end iterator, otherwise the behaviour is undefined
1021 /// @post @c *this is shifted forward to the next valid element, or becomes the end iterator if there are no more
1022 /// valid elements.
1023 /// @note The logic can't be in this function because GCC thinks it can't access private members of @c inline_deque
1024 friend constexpr auto
1025 step_forward(inline_container_detail::iterator_interface_tag, cyclical_iterator& self) noexcept -> void {
1026 self.do_step_forward();
1027 }
1028
1029 /// @brief Customization point used by @c iterator_interface to decrement the iterator by 1 step
1030 /// @param self The iterator to be decremented
1031 /// @pre @c *this does not point to the front element, otherwise the behaviour is undefined
1032 /// @post @c *this is shifted backward to the next valid element, or becomes the end iterator if there are no more
1033 /// valid elements. If @c this is an end iterator, it becomes the last element.
1034 /// @note The logic can't be in this function because GCC thinks it can't access private members of @c inline_deque
1035 friend constexpr auto
1036 step_backward(inline_container_detail::iterator_interface_tag, cyclical_iterator& self) noexcept -> void {
1037 self.do_step_backward();
1038 }
1039
1040 // parasoft-end-suppress AUTOSAR-A11_3_1-a
1041 // parasoft-end-suppress AUTOSAR-A0_1_3-a
1042 // parasoft-end-suppress AUTOSAR-A7_1_1-a
1043 // parasoft-end-suppress AUTOSAR-M7_1_2-c
1044 // parasoft-end-suppress AUTOSAR-A8_4_9-a
1045 // parasoft-end-suppress AUTOSAR-A7_1_5-a
1046
1047 /// @brief A pointer to the inline_deque that the iterator came from so that it can query the current bounds
1048 conditional_t<IsConst, inline_deque_impl const*, inline_deque_impl*> deque_;
1049
1050 /// @brief The current index of the iterator *within the physical buffer backing <c>deque_</c>*
1051 std::size_t idx_;
1052 };
1053 // parasoft-end-suppress AUTOSAR-A12_1_5-a
1054
1055 public:
1056 // parasoft-begin-suppress AUTOSAR-A2_10_1-e "False Positive: identifiers at class/namespace scope are exempt"
1057 /// @brief The type used to hold the size
1058 using size_type = typename storage_type::size_type;
1059 /// @brief The type of a value stored
1060 using value_type = T;
1061 // parasoft-end-suppress AUTOSAR-A2_10_1-e
1062 /// @brief The type of a reference to a value stored
1063 using reference = value_type&;
1064 /// @brief The type of a const reference to a value stored
1065 using const_reference = value_type const&;
1066 /// @brief The type of a mutable iterator
1067 using iterator = cyclical_iterator<false>;
1068 /// @brief The type of a const iterator
1069 using const_iterator = cyclical_iterator<true>;
1070
1071 // parasoft-begin-suppress AUTOSAR-M11_0_1-a "False positive: this is not 'member data', it is a public property"
1072 /// @brief Get the maximum number of elements in the deque, @c Capacity
1073 static constexpr std::integral_constant<size_type, Capacity> capacity{};
1074
1075 /// @brief Whether wrapping is allowed with the current instantiation; if false, wrapping is a precondition violation
1076 static constexpr std::integral_constant<bool, AllowWrapping> wrapping_allowed{};
1077 // parasoft-end-suppress AUTOSAR-M11_0_1-a
1078
1079 // parasoft-begin-suppress AUTOSAR-A12_7_1-a "False positive: range_interface is not default-constructed"
1080 /// @brief Construct an empty deque
1081 constexpr inline_deque_impl() noexcept
1082 : storage_type(),
1083 range_interface(this) {}
1084 // parasoft-end-suppress AUTOSAR-A12_7_1-a
1085
1086 /// @brief Construct a deque from a range of elements, taken to be in front -> back order
1087 /// @tparam Iterator The type of the iterators to construct from
1088 /// @param in_begin An iterator to the beginning (front) of the input range
1089 /// @param in_end An iterator to the end (back+1) of the input range
1090 /// @pre <c>distance(in_begin, in_end) >= 0</c> and <c><= capacity()</c>, otherwise @c ARENE_PRECONDITION violation
1091 /// @pre If the behaviour of <c>distance(in_begin, in_end)</c> is undefined, then this function's behaviour is too
1092 template <
1093 typename Iterator,
1094 constraints<
1095 std::enable_if_t<arene::base::is_forward_iterator_v<Iterator>>,
1096 std::enable_if_t<
1097 std::is_constructible<value_type, typename std::iterator_traits<Iterator>::reference>::value>> = nullptr>
1098 constexpr inline_deque_impl(Iterator in_begin, Iterator in_end) noexcept(
1099 noexcept(::arene::base::distance(in_begin, in_end)) &&
1100 std::is_nothrow_constructible<value_type, typename std::iterator_traits<Iterator>::reference>::value
1101 )
1102 : storage_type(in_begin, in_end),
1103 range_interface(this) {}
1104
1105 /// @copydoc storage_type::empty
1106 using storage_type::empty;
1107
1108 // parasoft-begin-suppress AUTOSAR-A10_2_1-a "False positive: redefines member of a privately inherited class"
1109 /// @brief Get an iterator pointing to the front element
1110 /// @return An iterator which, when dereferenced, yields @c front()
1111 constexpr auto begin() const noexcept -> const_iterator {
1112 if (this->empty()) {
1113 return this->end();
1114 }
1115 return {*this, this->front_index()};
1116 }
1117
1118 /// @brief Get an iterator pointing to the front element
1119 /// @return An iterator which, when dereferenced, yields @c front()
1120 constexpr auto begin() noexcept -> iterator {
1121 if (this->empty()) {
1122 return this->end();
1123 }
1124 return {*this, this->front_index()};
1125 }
1126
1127 /// @brief Get an iterator signifying the end of forward iteration
1128 /// @return An iterator which will compare equal to an element iterator which has finished its iteration
1129 constexpr auto end() const noexcept -> const_iterator { return {*this, const_iterator::end_index}; }
1130
1131 /// @brief Get an iterator signifying the end of forward iteration
1132 /// @return An iterator which will compare equal to an element iterator which has finished its iteration
1133 constexpr auto end() noexcept -> iterator { return {*this, iterator::end_index}; }
1134 // parasoft-end-suppress AUTOSAR-A10_2_1-a
1135
1136 // All of the functions provided by range_interface conflict with ones provided by storage_type, so we need to
1137 // explicitly expose the ones that we want from each base class.
1138
1139 /// @copydoc range_interface::cbegin
1140 using range_interface::cbegin;
1141 /// @copydoc range_interface::cend
1142 using range_interface::cend;
1143
1144 /// @copydoc range_interface::rbegin
1145 using range_interface::rbegin;
1146 /// @copydoc range_interface::rend
1147 using range_interface::rend;
1148
1149 /// @copydoc range_interface::crbegin
1150 using range_interface::crbegin;
1151 /// @copydoc range_interface::crend
1152 using range_interface::crend;
1153
1154 /// @copydoc range_interface::front
1155 using range_interface::front;
1156 /// @copydoc range_interface::back
1157 using range_interface::back;
1158 /// @copydoc range_interface::operator[]
1159 using range_interface::operator[];
1160
1161 /// @brief Get the current number of alive elements
1162 /// @return the size
1163 using storage_type::size;
1164
1165 /// @brief Emplace a new element at the front of the deque
1166 /// @param value The value to copy or to move from
1167 /// @pre <c>size() < Capacity</c>, otherwise @c ARENE_PRECONDITION violation
1168 using storage_type::emplace_front;
1169
1170 /// @brief Emplace a new element at the back of the deque
1171 /// @param value The value to copy or to move from
1172 /// @pre <c>size() < Capacity</c>, otherwise @c ARENE_PRECONDITION violation
1173 using storage_type::emplace_back;
1174
1175 /// @brief Copy a new element on to the front of the deque
1176 /// @param arg The argument to copy from
1177 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
1178 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c back() is removed and iterators
1179 /// pointing to it are invalidated.
1180 constexpr auto push_front(value_type const& arg) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
1181 -> void {
1182 std::ignore = this->emplace_front(arg);
1183 }
1184
1185 /// @brief Move a new element on to the front of the deque
1186 /// @param arg The argument to move from
1187 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
1188 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c back() is removed and iterators
1189 /// pointing to it are invalidated.
1190 constexpr auto push_front(value_type&& arg) noexcept(std::is_nothrow_move_constructible<value_type>::value) -> void {
1191 std::ignore = this->emplace_front(std::move(arg));
1192 }
1193
1194 /// @brief Copy a new element on to the back of the deque
1195 /// @param arg The argument to copy from
1196 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
1197 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c front() is removed and iterators
1198 /// pointing to it are invalidated.
1199 constexpr auto push_back(value_type const& arg) noexcept(std::is_nothrow_copy_constructible<value_type>::value)
1200 -> void {
1201 std::ignore = this->emplace_back(arg);
1202 }
1203
1204 /// @brief Move a new element on to the back of the deque
1205 /// @param arg The argument to move from
1206 /// @pre If wrapping is not allowed, <c>size() < capacity()</c>, otherwise @c ARENE_PRECONDITION violation
1207 /// @note If wrapping is allowed and <c>size() == capacity()</c>, the element at @c front() is removed and iterators
1208 /// pointing to it are invalidated.
1209 constexpr auto push_back(value_type&& arg) noexcept(std::is_nothrow_move_constructible<value_type>::value) -> void {
1210 std::ignore = this->emplace_back(std::move(arg));
1211 }
1212
1213 private:
1214 /// @brief Perform an insertion of a single value at the front of the deque as part of an @c insert call
1215 /// @tparam U Type of the value to insert
1216 /// @tparam Wrap Whether or not wrapping is allowed; redefined here to delay evaluation for SFINAE
1217 /// @param value Value to insert
1218 /// @return A new iterator pointing to the inserted value if it was inserted; otherwise, @c begin()
1219 /// @pre The deque is not currently full or wrapping is allowed, otherwise @c ARENE_PRECONDITION violation
1220 /// @post @c value is inserted before the beginning, unless the queue is full and wrapping is allowed; in that case,
1221 /// @c value is not inserted. Logically, it is inserted at the front and then immediately popped for space.
1222 template <typename U, bool Wrap = wrapping_allowed, constraints<std::enable_if_t<Wrap>> = nullptr>
1223 constexpr auto internal_insert_at_front(U&& value) noexcept(std::is_nothrow_constructible<value_type, U&&>::value)
1224 -> inline_deque_impl::iterator {
1225 if (this->size() < this->capacity()) {
1226 std::ignore = this->emplace_front(std::forward<U>(value));
1227 }
1228
1229 return this->begin();
1230 }
1231
1232 /// @brief Perform an insertion of a single value at the front of the deque as part of an @c insert call
1233 /// @tparam U Type of the value to insert
1234 /// @tparam Wrap Whether or not wrapping is allowed; redefined here to delay evaluation for SFINAE
1235 /// @param value Value to insert
1236 /// @return A new iterator pointing to the inserted value if it was inserted; otherwise, @c begin()
1237 /// @pre The deque is not currently full or wrapping is allowed, otherwise @c ARENE_PRECONDITION violation
1238 /// @post @c value is inserted before the beginning, unless the queue is full and wrapping is allowed; in that case,
1239 /// @c value is not inserted. Logically, it is inserted at the front and then immediately popped for space.
1240 template <typename U, bool Wrap = wrapping_allowed, constraints<std::enable_if_t<!Wrap>> = nullptr>
1241 constexpr auto internal_insert_at_front(U&& value) noexcept(std::is_nothrow_constructible<value_type, U&&>::value)
1242 -> inline_deque_impl::iterator {
1243 std::ignore = this->emplace_front(std::forward<U>(value));
1244 return this->begin();
1245 }
1246
1247 /// @brief Perform an insertion of a single value at the back of the deque as part of an @c insert call
1248 /// @tparam U Type of the value to insert
1249 /// @param value Value to insert
1250 /// @return A new iterator pointing to the inserted value
1251 /// @pre Either the deque is not currently full or wrapping is allowed, otherwise @c ARENE_PRECONDITION violation
1252 template <typename U>
1253 constexpr auto internal_insert_at_back(U&& value) noexcept(std::is_nothrow_constructible<value_type, U&&>::value)
1254 -> inline_deque_impl::iterator {
1255 // If wrapping is allowed, this will automatically pop the front element to make space; otherwise it crashes.
1256 std::ignore = this->emplace_back(std::forward<U>(value));
1257 return inline_deque_impl::iterator(*this, this->back_index());
1258 }
1259
1260 /// @brief Perform an insertion of a single value in the middle of the deque as part of an @c insert call
1261 /// @tparam U Type of the value to insert
1262 /// @param pos Position at which to insert
1263 /// @param value Value to insert
1264 /// @return A new iterator pointing to the inserted value
1265 /// @pre Either the deque is not currently full or wrapping is allowed, otherwise @c ARENE_PRECONDITION violation
1266 /// @pre @c pos is an iterator pointing to a valid position in this deque, otherwise the behaviour is undefined
1267 /// @post If the return value is <c>r</c>, then @c *(++r) refers to the element previously referred to by @c pos
1268 template <typename U>
1269 constexpr auto internal_insert_in_middle(inline_deque_impl::const_iterator pos, U&& value) noexcept(
1270 std::is_nothrow_constructible<value_type, U&&>::value && std::is_nothrow_move_assignable<value_type>::value &&
1271 std::is_nothrow_move_constructible<value_type>::value
1272 ) -> inline_deque_impl::iterator {
1273 // Even if elements are not actually inserted at the back, this has the right behaviour for making space/crashing.
1274 this->ensure_space_at_back();
1275
1276 // parasoft-begin-suppress AUTOSAR-M14_6_1-a "False positive: inline_deque_impl::iterator is a qualified-id"
1277 auto mutable_pos = inline_deque_impl::iterator(*this, pos.physical_index());
1278 inline_deque_impl::iterator insertion_target;
1279 // parasoft-end-suppress AUTOSAR-M14_6_1-a
1280
1281 // parasoft-begin-suppress AUTOSAR-A5_1_1-a "Simple arithmetic constants permitted by A5-1-1 Permit #1"
1282
1283 // Shift the physical storage toward whichever side is closer; the final logical order is the same either way.
1284 if (static_cast<size_type>(distance(this->cbegin(), pos)) < (this->capacity() / 2U)) {
1285 // The front is closer, so add an element at the front and shift the physical storage toward it.
1286 std::ignore = this->emplace_front(std::forward<U>(value));
1287
1288 insertion_target = rotate(this->begin(), next(this->begin()), mutable_pos);
1289 } else {
1290 // The back is closer, so add an element at the back and shift the physical storage toward it.
1291 std::ignore = this->emplace_back(std::forward<U>(value));
1292
1293 std::ignore = rotate(mutable_pos, inline_deque_impl::iterator(*this, this->back_index()), this->end());
1294 insertion_target = mutable_pos;
1295 }
1296
1297 // parasoft-end-suppress AUTOSAR-A5_1_1-a
1298
1299 return insertion_target;
1300 }
1301
1302 /// @brief Perform an insertion of a single value at the indicated position
1303 /// @tparam U Type of the value to insert
1304 /// @param pos Position at which to insert
1305 /// @param value Value to insert
1306 /// @return A new iterator pointing to the inserted value if it was inserted; otherwise, @c begin()
1307 /// @pre If wrapping is disabled: the queue is not full, otherwise @c ARENE_PRECONDITION violation
1308 /// @pre @c pos is an iterator pointing to a valid position in this deque, otherwise the behaviour is undefined
1309 /// @post If wrapping is enabled, the queue is full, and @c pos is <c>begin</c>, then no insertion is performed.
1310 /// Otherwise, let the return value be <c>r</c>; then @c *r holds @c value and @c *(++r) refers to the element
1311 /// previously referred to by @c pos
1312 /// @note All existing iterators are invalidated if an insertion is performed.
1313 template <typename U>
1314 constexpr auto internal_insert(inline_deque_impl::const_iterator pos, U&& value) noexcept(noexcept(
1315 std::declval<inline_deque_impl>().internal_insert_at_front(std::forward<U>(value))
1316 ) && noexcept(std::declval<inline_deque_impl>().internal_insert_at_back(std::forward<U>(value))
1317 ) && noexcept(std::declval<inline_deque_impl>().internal_insert_in_middle(pos, std::forward<U>(value))))
1318 -> inline_deque_impl::iterator {
1319 if (pos == this->cbegin()) {
1320 return internal_insert_at_front(std::forward<U>(value));
1321 }
1322 if (pos == this->cend()) {
1323 return internal_insert_at_back(std::forward<U>(value));
1324 }
1325
1326 return internal_insert_in_middle(pos, std::forward<U>(value));
1327 }
1328
1329 public:
1330 /// @brief Copy-insert a single value at the indicated position
1331 /// @param pos Position at which to insert
1332 /// @param value Value to insert
1333 /// @return A new iterator pointing to the inserted value if it was inserted; otherwise, @c begin()
1334 /// @pre If wrapping is disabled: the queue is not full, otherwise @c ARENE_PRECONDITION violation
1335 /// @pre @c pos is an iterator pointing to a valid position in this deque, otherwise the behaviour is undefined
1336 /// @post If wrapping is enabled, the queue was full prior to this call, and @c pos is <c>begin()</c>, then no
1337 /// insertion is performed. Otherwise, let the return value be <c>r</c>; then @c *r holds @c value and @c *(++r)
1338 /// refers to the element previously referred to by <c>pos</c>.
1339 /// @note All existing iterators are invalidated if an insertion is performed.
1340 /// @note Complexity: O(x), where x is the distance from @c pos to the nearer of @c begin() or <c>end()</c>. This
1341 /// means that inserting at the beginning or end is constant complexity regardless of current size.
1342 template <
1343 typename U = value_type,
1344 constraints<
1345 std::enable_if_t<std::is_same<U, value_type>::value>,
1346 std::enable_if_t<std::is_copy_assignable<U>::value>,
1347 std::enable_if_t<std::is_move_assignable<U>::value>,
1348 std::enable_if_t<std::is_move_constructible<U>::value>> = nullptr>
1349 constexpr auto insert(inline_deque_impl::const_iterator pos, value_type const& value) noexcept(
1350 noexcept(std::declval<inline_deque_impl>().internal_insert(pos, value))
1351 ) -> inline_deque_impl::iterator {
1352 return this->internal_insert(pos, value);
1353 }
1354
1355 /// @brief Move-insert a single value at the indicated position
1356 /// @param pos Position at which to insert
1357 /// @param value Value to insert
1358 /// @return A new iterator pointing to the inserted value if it was inserted; otherwise, @c begin()
1359 /// @pre If wrapping is disabled: the queue is not full, otherwise @c ARENE_PRECONDITION violation
1360 /// @pre @c pos is an iterator pointing to a valid position in this deque, otherwise the behaviour is undefined
1361 /// @post If wrapping is enabled, the queue was full prior to this call, and @c pos is <c>begin()</c>, then no
1362 /// insertion is performed. Otherwise, let the return value be <c>r</c>; then @c *r holds @c value and @c *(++r)
1363 /// refers to the element previously referred to by <c>pos</c>.
1364 /// @note All existing iterators are invalidated if an insertion is performed.
1365 /// @note Complexity: O(x), where x is the distance from @c pos to the nearer of @c begin() or <c>end()</c>. This
1366 /// means that inserting at the beginning or end is constant complexity regardless of current size.
1367 template <
1368 typename U = value_type,
1369 constraints<
1370 std::enable_if_t<std::is_same<U, value_type>::value>,
1371 std::enable_if_t<std::is_move_assignable<U>::value>,
1372 std::enable_if_t<std::is_move_constructible<U>::value>> = nullptr>
1373 constexpr auto insert(inline_deque_impl::const_iterator pos, value_type&& value) noexcept(
1374 noexcept(std::declval<inline_deque_impl>().internal_insert(pos, std::move(value)))
1375 ) -> inline_deque_impl::iterator {
1376 return this->internal_insert(pos, std::move(value));
1377 }
1378
1379 /// @brief Remove the element at the front
1380 /// @pre <c>empty() == false</c>, otherwise @c ARENE_PRECONDITION violation
1381 using storage_type::pop_front;
1382
1383 /// @brief Remove the element at the back
1384 /// @pre <c>empty() == false</c>, otherwise @c ARENE_PRECONDITION violation
1385 using storage_type::pop_back;
1386};
1387// parasoft-end-suppress AUTOSAR-A10_1_1-a
1388
1389template <typename T, std::size_t Capacity, bool AllowWrapping>
1390constexpr std::integral_constant<typename inline_deque_impl<T, Capacity, AllowWrapping>::size_type, Capacity>
1391 inline_deque_impl<T, Capacity, AllowWrapping>::capacity;
1392
1393template <typename T, std::size_t Capacity, bool AllowWrapping>
1394constexpr std::integral_constant<bool, AllowWrapping> inline_deque_impl<T, Capacity, AllowWrapping>::wrapping_allowed;
1395
1396template <typename T, std::size_t Capacity, bool AllowWrapping>
1397template <bool IsConst>
1398constexpr std::integral_constant<std::size_t, std::numeric_limits<std::size_t>::max()>
1399 inline_deque_impl<T, Capacity, AllowWrapping>::cyclical_iterator<IsConst>::end_index;
1400
1401} // namespace inline_deque_detail
1402
1403/// @brief A container with fixed capacity featuring constant time insertion and
1404/// removal at opposite ends; i.e., with an interface similar to std::deque. The
1405/// storage for the elements is held directly within the class. Any attempt to
1406/// store more than @c Capacity elements is an @c ARENE_PRECONDITION violation
1407/// @tparam T The type of each element
1408/// @tparam Capacity The maximum number of elements that can be stored
1409// parasoft-begin-suppress AUTOSAR-A10_1_1-a "False positive: try_construct_interface is an interface"
1410template <typename T, std::size_t Capacity>
1412 : private inline_deque_detail::inline_deque_impl<T, Capacity, false>
1416 /// @brief The implementation class, separate to share implementations with other similar queues
1417 using impl = inline_deque_detail::inline_deque_impl<T, Capacity, false>;
1418
1419 /// @brief Shorthand to the mixin type that synthesizes @c try_construct functions based on the normal constructors
1423
1424 public:
1425 /// @copydoc impl::const_iterator
1426 using typename impl::const_iterator;
1427 /// @copydoc impl::const_reference
1428 using typename impl::const_reference;
1429 /// @copydoc impl::iterator
1430 using typename impl::iterator;
1431 /// @copydoc impl::reference
1432 using typename impl::reference;
1433 /// @copydoc impl::size_type
1434 using typename impl::size_type;
1435 /// @copydoc impl::value_type
1436 using typename impl::value_type;
1437
1438 /// @copydoc impl::wrapping_allowed
1439 using impl::wrapping_allowed;
1440
1441 // parasoft-begin-suppress AUTOSAR-A12_7_1-a "False positive: can not be defaulted by it needs to pass this pointer"
1442 /// @brief Construct an empty queue
1443 constexpr inline_deque() noexcept
1444 : impl(),
1446 // parasoft-end-suppress AUTOSAR-A12_7_1-a
1447
1448 /// @brief Construct a queue from a range of elements, taken to be in front -> back order
1449 /// @tparam Iterator The type of the iterators to construct from
1450 /// @param in_begin An iterator to the beginning (front) of the input range
1451 /// @param in_end An iterator to the end (back+1) of the input range
1452 /// @pre <c>distance(in_begin, in_end) >= 0</c> and <c><= capacity()</c>, otherwise @c ARENE_PRECONDITION violation
1453 /// @pre If the behaviour of <c>distance(in_begin, in_end)</c> is undefined, then this function's behaviour is too
1454 template <
1455 typename Iterator,
1466
1467 /// @brief Construct a deque by copying from an initializer list of elements, taken to be in front -> back order
1468 /// @param init An initializer list of the value type
1469 /// @pre <c>init.size() <= capacity()</c>, otherwise @c ARENE_PRECONDITION violation
1470 template <typename U = value_type, constraints<std::enable_if_t<std::is_copy_constructible<U>::value>> = nullptr>
1472 ) noexcept(noexcept(inline_deque(init.begin(), init.end())))
1473 : inline_deque(init.begin(), init.end()) {}
1474
1475 /// @copydoc impl::capacity
1476 using impl::capacity;
1477 /// @copydoc impl::empty
1478 using impl::empty;
1479 /// @copydoc impl::size
1480 using impl::size;
1481
1482 /// @copydoc impl::begin
1483 using impl::begin;
1484 /// @copydoc impl::cbegin
1485 using impl::cbegin;
1486 /// @copydoc impl::cend
1487 using impl::cend;
1488 /// @copydoc impl::crbegin
1489 using impl::crbegin;
1490 /// @copydoc impl::crend
1491 using impl::crend;
1492 /// @copydoc impl::end
1493 using impl::end;
1494 /// @copydoc impl::rbegin
1495 using impl::rbegin;
1496 /// @copydoc impl::rend
1497 using impl::rend;
1498
1499 /// @copydoc impl::back
1500 using impl::back;
1501 /// @copydoc impl::front
1502 using impl::front;
1503 /// @copydoc impl::operator[]
1504 using impl::operator[];
1505
1506 /// @copydoc impl::emplace_back
1507 using impl::emplace_back;
1508 /// @copydoc impl::emplace_front
1509 using impl::emplace_front;
1510 /// @copydoc impl::pop_back
1511 using impl::pop_back;
1512 /// @copydoc impl::pop_front
1513 using impl::pop_front;
1514 /// @copydoc impl::push_back
1515 using impl::push_back;
1516 /// @copydoc impl::push_front
1517 using impl::push_front;
1518 /// @copydoc impl::insert
1519 using impl::insert;
1520};
1521// parasoft-end-suppress AUTOSAR-A10_1_1-a
1522
1523} // namespace base
1524} // namespace arene
1525
1526// parasoft-end-suppress AUTOSAR-M2_10_1-a-2
1527
1528#endif // INCLUDE_GUARD_ARENE_BASE_ARENE_BASE_INLINE_CONTAINER_DEQUE_HPP_
A container with fixed capacity featuring constant time insertion and removal at opposite ends; i....
Definition deque.hpp:1415
constexpr inline_deque() noexcept
Construct an empty queue.
Definition deque.hpp:1443
Definition array_exceptions_disabled.cpp:11
Copyright 2026, Toyota Motor Corporation.
Definition array_exceptions_disabled.cpp:10