opynsim
Unofficial C++ Documentation
Loading...
Searching...
No Matches
variable_length_array.h
Go to the documentation of this file.
1#pragma once
2
3#include <array>
4#include <concepts>
5#include <cstddef>
6#include <initializer_list>
7#include <iterator>
8#include <memory>
9#include <memory_resource>
10#include <utility>
11#include <vector>
12
13namespace osc
14{
15 // Provides a container that behaves as an on-stack/on-heap hybrid array that:
16 //
17 // - Allocates up to `N` elements on the stack without using a memory allocator.
18 // - Once the number of elements exceeds `N`, allocates all elements (incl. existing
19 // elements, which are moved) via an upstream memory resource, which defaults to
20 // a `std::pmr::new_delete_resource`
21 //
22 // This is handy when the caller believes that there's likely to be a (low) upper
23 // bound on the number of elements in the container, but they cannot be 100 %
24 // certain that the number of elements will never exceed that bound. E.g. it might
25 // be fair to assume that a tree loaded from a data file never exceeds 16 levels
26 // of depth for reasonable inputs, but there might exist unreasonable ones, so
27 // having a safe fallback to an upstream allocator is useful.
28 template<typename T, size_t N>
30 private:
31 using underlying_vector = std::pmr::vector<T>;
32 public:
33 using value_type = typename underlying_vector::value_type;
34 using allocator_type = typename underlying_vector::allocator_type;
35 using size_type = typename underlying_vector::size_type;
36 using difference_type = typename underlying_vector::difference_type;
37 using reference = typename underlying_vector::reference;
38 using const_reference = typename underlying_vector::const_reference;
39 using pointer = typename underlying_vector::pointer;
40 using const_pointer = typename underlying_vector::const_pointer;
41 using iterator = typename underlying_vector::iterator;
42 using const_iterator = typename underlying_vector::const_iterator;
43 using reverse_iterator = typename underlying_vector::reverse_iterator;
44 using const_reverse_iterator = typename underlying_vector::const_reverse_iterator;
45
46 explicit VariableLengthArray(std::pmr::memory_resource* upstream_allocator = std::pmr::new_delete_resource()) :
47 pool{stack_data_.data(), stack_data_.size(), upstream_allocator}
48 {
49 vector_.reserve(N); // reserve the stack as one unit of allocation
50 }
51
53 requires std::copy_constructible<T> :
54 pool{stack_data_.data(), stack_data_.size(), other.pool.upstream_resource()}
55 {
56 vector_.reserve(N); // reserve the stack as one unit of allocation
57 vector_.assign(other.vector_.begin(), other.vector_.end());
58 }
59
61 requires std::move_constructible<T> :
62 pool{stack_data_.data(), stack_data_.size(), other.pool.upstream_resource()}
63 {
64 vector_.reserve(N); // reserve the stack as one unit of allocation
65 vector_.assign(std::make_move_iterator(other.vector_.begin()), std::make_move_iterator(other.vector_.end()));
66 }
67
69 std::initializer_list<T> init,
70 std::pmr::memory_resource* upstream_allocator = std::pmr::new_delete_resource())
71 requires std::copy_constructible<T> :
72 pool{stack_data_.data(), stack_data_.size(), upstream_allocator}
73 {
74 vector_.reserve(N); // reserve the stack as one unit of allocation
75 vector_.assign(init.begin(), init.end());
76 }
77
79 requires std::is_copy_assignable_v<T>
80 {
81 vector_.assign(other.begin(), other.end());
82 return *this;
83 }
84
86 requires std::is_move_assignable_v<T>
87 {
88 vector_.assign(std::make_move_iterator(other.vector_.begin()), std::make_move_iterator(other.vector_.end()));
89 return *this;
90 }
91
92 reference operator[](size_type pos) { return vector_[pos]; }
93 const_reference operator[](size_type pos) const { return vector_[pos]; }
94
95 reference front() { return vector_.front(); }
96 const_reference front() const { return vector_.front(); }
97
98 iterator begin() noexcept { return vector_.begin(); }
99 const_iterator begin() const noexcept { return vector_.begin(); }
100 const_iterator cbegin() const noexcept { return vector_.cbegin(); }
101 iterator end() noexcept { return vector_.end(); }
102 const_iterator end() const noexcept { return vector_.end(); }
103 const_iterator cend() const noexcept { return vector_.cend(); }
104 reverse_iterator rbegin() noexcept { return vector_.rbegin(); }
105 const_reverse_iterator rbegin() const noexcept { return vector_.rbegin(); }
106 const_reverse_iterator crbegin() const noexcept { return vector_.crbegin(); }
107 reverse_iterator rend() noexcept { return vector_.rend(); }
108 const_reverse_iterator rend() const noexcept { return vector_.rend(); }
109 const_reverse_iterator crend() const noexcept { return vector_.crend(); }
110
111 [[nodiscard]] bool empty() const noexcept { return vector_.empty(); }
112 size_type size() const noexcept { return vector_.size(); }
113
114 void clear() { vector_.clear(); }
115
116 void push_back(const T& value) { vector_.push_back(value); }
117 void push_back(T&& value) { vector_.push_back(std::move(value)); }
118
119 friend bool operator==(const VariableLengthArray& lhs, const VariableLengthArray& rhs) { return lhs.vector_ == rhs.vector_; }
120
121 private:
122// Fix debug ABI issue from MSVC: when compiling in debug mode, MSVC will allocate a
123// little container proxy at the start of the allocation unit (presumably, to track
124// allocations) and that causes problems when downstream code expects spillover to
125// occur at particular points (e.g. the test suite ensures this).
126//
127// see: https://developercommunity.visualstudio.com/t/debug-version-of-stl-is-not-excepion-safe-and-caus/77779
128#if defined(_MSC_VER) && _ITERATOR_DEBUG_LEVEL > 0
129 static inline constexpr size_t extra_bytes_ = []()
130 {
131 // from MSVC
132 constexpr size_t proxy_size = sizeof(std::_Container_proxy);
133 // ensure the extra bytes also account for the remainder of the buffer being used
134 // for over-aligned datastructures
135 constexpr size_t num_align_windows = (proxy_size + (alignof(T) - 1))/alignof(T);
136 return alignof(T) * num_align_windows;
137 }();
138#else
139 static inline constexpr size_t extra_bytes_ = 0;
140#endif
141
142 // The object representation of elements, stored on-stack when `size() <= N`
143 alignas(T) std::array<std::byte, N * sizeof(T) + extra_bytes_> stack_data_;
144
145 // A memory resource that uses `stack_data_` until `size() > N`, it then uses an upstream resource
146 std::pmr::monotonic_buffer_resource pool{stack_data_.data(), stack_data_.size(), std::pmr::new_delete_resource()};
147
148 // A vector that's backed by the above memory resource
149 underlying_vector vector_ = underlying_vector(&pool);
150 };
151}
Definition variable_length_array.h:29
void push_back(const T &value)
Definition variable_length_array.h:116
VariableLengthArray(VariableLengthArray &&other) noexcept
Definition variable_length_array.h:60
const_iterator cend() const noexcept
Definition variable_length_array.h:103
const_reference front() const
Definition variable_length_array.h:96
void push_back(T &&value)
Definition variable_length_array.h:117
VariableLengthArray(std::initializer_list< T > init, std::pmr::memory_resource *upstream_allocator=std::pmr::new_delete_resource())
Definition variable_length_array.h:68
typename underlying_vector::pointer pointer
Definition variable_length_array.h:39
typename underlying_vector::reference reference
Definition variable_length_array.h:37
const_reference operator[](size_type pos) const
Definition variable_length_array.h:93
size_type size() const noexcept
Definition variable_length_array.h:112
void clear()
Definition variable_length_array.h:114
const_reverse_iterator rbegin() const noexcept
Definition variable_length_array.h:105
typename underlying_vector::size_type size_type
Definition variable_length_array.h:35
typename underlying_vector::iterator iterator
Definition variable_length_array.h:41
friend bool operator==(const VariableLengthArray &lhs, const VariableLengthArray &rhs)
Definition variable_length_array.h:119
typename underlying_vector::difference_type difference_type
Definition variable_length_array.h:36
reference operator[](size_type pos)
Definition variable_length_array.h:92
typename underlying_vector::allocator_type allocator_type
Definition variable_length_array.h:34
iterator end() noexcept
Definition variable_length_array.h:101
const_reverse_iterator crbegin() const noexcept
Definition variable_length_array.h:106
typename underlying_vector::const_reference const_reference
Definition variable_length_array.h:38
const_reverse_iterator rend() const noexcept
Definition variable_length_array.h:108
const_iterator begin() const noexcept
Definition variable_length_array.h:99
const_iterator cbegin() const noexcept
Definition variable_length_array.h:100
reverse_iterator rend() noexcept
Definition variable_length_array.h:107
VariableLengthArray & operator=(const VariableLengthArray &other)
Definition variable_length_array.h:78
const_reverse_iterator crend() const noexcept
Definition variable_length_array.h:109
typename underlying_vector::reverse_iterator reverse_iterator
Definition variable_length_array.h:43
VariableLengthArray(std::pmr::memory_resource *upstream_allocator=std::pmr::new_delete_resource())
Definition variable_length_array.h:46
typename underlying_vector::const_pointer const_pointer
Definition variable_length_array.h:40
iterator begin() noexcept
Definition variable_length_array.h:98
bool empty() const noexcept
Definition variable_length_array.h:111
VariableLengthArray & operator=(VariableLengthArray &&other) noexcept
Definition variable_length_array.h:85
VariableLengthArray(const VariableLengthArray &other)
Definition variable_length_array.h:52
typename underlying_vector::value_type value_type
Definition variable_length_array.h:33
reverse_iterator rbegin() noexcept
Definition variable_length_array.h:104
typename underlying_vector::const_iterator const_iterator
Definition variable_length_array.h:42
const_iterator end() const noexcept
Definition variable_length_array.h:102
reference front()
Definition variable_length_array.h:95
typename underlying_vector::const_reverse_iterator const_reverse_iterator
Definition variable_length_array.h:44
Definition custom_decoration_generator.h:5
constexpr U to(T &&value)
Definition conversion.h:56