FastLED 3.10.9
Loading...
Searching...
No Matches
basic_vector.h
Go to the documentation of this file.
1#pragma once
2
9
10#include "fl/stl/int.h"
11#include "fl/stl/cstring.h"
14#include "fl/stl/noexcept.h"
15
16namespace fl {
17
22 void (*copy_construct)(void* dst, const void* src);
23 void (*move_construct)(void* dst, void* src);
24 void (*default_construct)(void* ptr);
25 void (*swap_elements)(void* a, void* b);
26
29 void (*destroy_n)(void* first, fl::size count);
30};
31
37 public:
38 // ======= CAPACITY =======
39 fl::size size() const FL_NO_EXCEPT { return mSize; }
40 bool empty() const FL_NO_EXCEPT { return mSize == 0; }
41 fl::size capacity() const FL_NO_EXCEPT { return mCapacity; }
42 bool full() const FL_NO_EXCEPT { return mSize >= mCapacity; }
43 fl::size element_size() const FL_NO_EXCEPT { return mElementSize; }
44
45 // ======= RAW DATA ACCESS =======
46 void* data_raw() FL_NO_EXCEPT { return mArray; }
47 const void* data_raw() const FL_NO_EXCEPT { return mArray; }
48
49 // ======= MEMORY MANAGEMENT =======
50 void reserve_impl(fl::size n) FL_NO_EXCEPT;
52
53 // ======= ELEMENT OPERATIONS =======
54 void push_back_copy_impl(const void* element) FL_NO_EXCEPT;
55 void push_back_move_impl(void* element) FL_NO_EXCEPT;
58
60 void erase_impl(fl::size index) FL_NO_EXCEPT;
61
63 void erase_range_impl(fl::size first_index, fl::size count) FL_NO_EXCEPT;
64
66 void insert_copy_impl(fl::size index, const void* element) FL_NO_EXCEPT;
67
69 void insert_move_impl(fl::size index, void* element) FL_NO_EXCEPT;
70
73
75 void resize_value_impl(fl::size n, const void* value) FL_NO_EXCEPT;
76
79
80 // ======= DESTRUCTOR =======
82
83 protected:
84 // ======= CONSTRUCTION (only callable by vector<T>) =======
85
87 vector_basic(fl::size elementSize, memory_resource* resource,
89 : mElementSize(elementSize)
90 , mResource(resource)
91 , mOps(ops)
92 , mInlineOffset(0)
93 , mInlineCapacity(0) {}
94
96 vector_basic(void* inlineBuffer, fl::size inlineCapacity,
97 fl::size elementSize, memory_resource* resource,
98 const vector_element_ops* ops)
99 FL_NO_EXCEPT : mElementSize(elementSize)
100 , mResource(resource)
101 , mOps(ops)
102 , mInlineOffset(static_cast<fl::size>(
103 static_cast<char*>(inlineBuffer) -
104 static_cast<char*>(static_cast<void*>(this))))
105 , mInlineCapacity(inlineCapacity) {
106 // Start with data in inline buffer
107 mArray = inlineBuffer;
108 mCapacity = inlineCapacity;
109 }
110
111 // Deleted copy/move — vector<T> handles these
114 vector_basic& operator=(const vector_basic&) FL_NO_EXCEPT = delete;
115 vector_basic& operator=(vector_basic&&) FL_NO_EXCEPT = delete;
116
117 // ======= HELPERS FOR DERIVED CLASSES =======
118
120 void copy_from(const vector_basic& other) FL_NO_EXCEPT;
121
124
127
128 // ======= DATA MEMBERS =======
129 void* mArray = nullptr;
134 const vector_element_ops* mOps; // nullptr → trivially copyable
135
136 // Inline buffer support (offset trick from basic_string).
137 // Store offset from `this` to the inline buffer, not a raw pointer.
138 // This survives trivial relocation (bitwise copy by containers) because
139 // the offset is relative to `this` which updates with the object.
141 fl::size mInlineCapacity; // 0 = no inline buffer
142
143 // ======= HELPER METHODS =======
144
147 return static_cast<char*>(static_cast<void*>(this)) + mInlineOffset;
148 }
149 const void* inlineBufferPtr() const FL_NO_EXCEPT {
150 return static_cast<const char*>(static_cast<const void*>(this)) + mInlineOffset;
151 }
152
154 bool isInline() const FL_NO_EXCEPT {
155 return mInlineCapacity > 0 && mArray == inlineBufferPtr();
156 }
157
160 return mInlineCapacity > 0;
161 }
162
164 void* element_ptr(fl::size index) FL_NO_EXCEPT {
165 return static_cast<char*>(mArray) + index * mElementSize;
166 }
167 const void* element_ptr(fl::size index) const FL_NO_EXCEPT {
168 return static_cast<const char*>(mArray) + index * mElementSize;
169 }
170
171 private:
173 void ensure_capacity(fl::size n) FL_NO_EXCEPT;
174
176 void grow_to(fl::size new_capacity) FL_NO_EXCEPT;
177 void uninitialized_move_n_impl(void* dst, void* src, fl::size count) const FL_NO_EXCEPT;
178
179 // ======= TRIVIAL ELEMENT HELPERS (memcpy/memmove) =======
180 void trivial_copy(void* dst, const void* src, fl::size count) const FL_NO_EXCEPT;
181 void trivial_move_left(void* dst, const void* src, fl::size count) const FL_NO_EXCEPT;
182 void trivial_default_construct(void* ptr, fl::size count) const FL_NO_EXCEPT;
183 void trivial_swap(void* a, void* b) const FL_NO_EXCEPT;
184};
185
186// ======= OPS TABLE HELPERS =======
187
188namespace detail {
189
190// SFINAE: detect if T is default-constructible
191template <typename T, typename = void>
193
194template <typename T>
195struct has_default_ctor<T, decltype(void(T()))> : fl::true_type {};
196
197// SFINAE: detect if T is copy-constructible
198template <typename T, typename = void>
200
201template <typename T>
202struct has_copy_ctor<T, decltype(void(T(fl::declval<const T&>())))> : fl::true_type {};
203
204// Default construct: available when T has default ctor
205template <typename T>
207 new (ptr) T();
208}
209
210template <typename T>
211constexpr typename fl::enable_if<has_default_ctor<T>::value, void(*)(void*)>::type
215
216// Default construct: nullptr when T has no default ctor
217template <typename T>
218constexpr typename fl::enable_if<!has_default_ctor<T>::value, void(*)(void*)>::type
220 return nullptr;
221}
222
223// Copy construct: available when T has copy ctor
224template <typename T>
225void vector_copy_construct(void* dst, const void* src) FL_NO_EXCEPT {
226 new (dst) T(*static_cast<const T*>(src));
227}
228
229template <typename T>
230constexpr typename fl::enable_if<has_copy_ctor<T>::value, void(*)(void*, const void*)>::type
234
235// Copy construct: nullptr when T is not copyable
236template <typename T>
237constexpr typename fl::enable_if<!has_copy_ctor<T>::value, void(*)(void*, const void*)>::type
239 return nullptr;
240}
241
242// SFINAE: detect if T is move-constructible
243template <typename T, typename = void>
245
246template <typename T>
247struct has_move_ctor<T, decltype(void(T(fl::declval<T&&>())))> : fl::true_type {};
248
249// SFINAE: detect if T is swappable (needs move-constructible + move-assignable)
250template <typename T, typename = void>
252
253template <typename T>
254struct is_swappable<T, decltype(void(
255 fl::declval<T&>() = fl::declval<T&&>()
256))> : has_move_ctor<T> {};
257
258// Move construct: available
259template <typename T>
260void vector_move_construct(void* dst, void* src) FL_NO_EXCEPT {
261 new (dst) T(static_cast<T&&>(*static_cast<T*>(src)));
262}
263
264template <typename T>
265constexpr typename fl::enable_if<has_move_ctor<T>::value, void(*)(void*, void*)>::type
269
270template <typename T>
271constexpr typename fl::enable_if<!has_move_ctor<T>::value, void(*)(void*, void*)>::type
273 return nullptr;
274}
275
276// Swap: available when swappable
277template <typename T>
278void vector_swap_elements(void* a, void* b) FL_NO_EXCEPT {
279 T& ta = *static_cast<T*>(a);
280 T& tb = *static_cast<T*>(b);
281 T tmp(static_cast<T&&>(ta));
282 ta = static_cast<T&&>(tb);
283 tb = static_cast<T&&>(tmp);
284}
285
286template <typename T>
287constexpr typename fl::enable_if<is_swappable<T>::value, void(*)(void*, void*)>::type
291
292template <typename T>
293constexpr typename fl::enable_if<!is_swappable<T>::value, void(*)(void*, void*)>::type
295 return nullptr;
296}
297
298template <typename T>
299void vector_destroy_n(void* first, fl::size count) FL_NO_EXCEPT {
300 T* p = static_cast<T*>(first);
301 for (fl::size i = 0; i < count; ++i) {
302 p[i].~T();
303 }
304}
305
306} // namespace detail
307
308// ======= OPS TABLE GENERATOR =======
309
312template <typename T>
314 // Trivially copyable types use the fast path (mOps == nullptr)
316 return nullptr;
317 }
318
319 static constexpr vector_element_ops ops = {
320 detail::get_copy_construct_fn<T>(), // copy_construct
321 detail::get_move_construct_fn<T>(), // move_construct
322 detail::get_default_construct_fn<T>(), // default_construct
323 detail::get_swap_fn<T>(), // swap_elements
324 &detail::vector_destroy_n<T> // destroy_n
325 };
326 return &ops;
327}
328
329} // namespace fl
Polymorphic memory resource base class (PMR-style).
void move_assign(vector_basic &other) FL_NO_EXCEPT
Move-assign from another vector_basic (clears this first).
fl::size capacity() const FL_NO_EXCEPT
bool hasInlineBuffer() const FL_NO_EXCEPT
Does this vector have an inline buffer at all?
const vector_element_ops * mOps
void trivial_swap(void *a, void *b) const FL_NO_EXCEPT
void trivial_copy(void *dst, const void *src, fl::size count) const FL_NO_EXCEPT
const void * element_ptr(fl::size index) const FL_NO_EXCEPT
void ensure_capacity(fl::size n) FL_NO_EXCEPT
Ensure capacity for at least n elements. Grows if needed.
void * element_ptr(fl::size index) FL_NO_EXCEPT
Pointer to element at index (byte arithmetic).
fl::size size() const FL_NO_EXCEPT
void * inlineBufferPtr() FL_NO_EXCEPT
Compute inline buffer pointer from offset.
void resize_impl(fl::size n) FL_NO_EXCEPT
Resize to n elements. New elements are default-constructed (zeroed for trivial).
void resize_value_impl(fl::size n, const void *value) FL_NO_EXCEPT
Resize to n elements. New elements are copy-constructed from value.
const void * inlineBufferPtr() const FL_NO_EXCEPT
void push_back_move_impl(void *element) FL_NO_EXCEPT
bool isInline() const FL_NO_EXCEPT
Is data currently in the inline buffer?
void shrink_to_fit_impl() FL_NO_EXCEPT
fl::size mElementSize
void push_back_copy_impl(const void *element) FL_NO_EXCEPT
void grow_to(fl::size new_capacity) FL_NO_EXCEPT
Grow to new_capacity. Moves existing elements.
void insert_move_impl(fl::size index, void *element) FL_NO_EXCEPT
Insert element at index by move. Shifts subsequent elements right.
void copy_from(const vector_basic &other) FL_NO_EXCEPT
Copy all elements from another vector_basic.
vector_basic(vector_basic &&) FL_NO_EXCEPT=delete
memory_resource * mResource
void trivial_default_construct(void *ptr, fl::size count) const FL_NO_EXCEPT
vector_basic(const vector_basic &) FL_NO_EXCEPT=delete
const void * data_raw() const FL_NO_EXCEPT
vector_basic(void *inlineBuffer, fl::size inlineCapacity, fl::size elementSize, memory_resource *resource, const vector_element_ops *ops) FL_NO_EXCEPT
Vector with inline buffer (for VectorN).
void uninitialized_move_n_impl(void *dst, void *src, fl::size count) const FL_NO_EXCEPT
void trivial_move_left(void *dst, const void *src, fl::size count) const FL_NO_EXCEPT
fl::size mInlineOffset
vector_basic(fl::size elementSize, memory_resource *resource, const vector_element_ops *ops) FL_NO_EXCEPT
Heap-only vector (no inline buffer).
bool empty() const FL_NO_EXCEPT
void clear_impl() FL_NO_EXCEPT
void reserve_impl(fl::size n) FL_NO_EXCEPT
fl::size mInlineCapacity
void erase_impl(fl::size index) FL_NO_EXCEPT
Erase element at index. Shifts subsequent elements left.
void erase_range_impl(fl::size first_index, fl::size count) FL_NO_EXCEPT
Erase range [first_index, first_index + count).
void move_from(vector_basic &other) FL_NO_EXCEPT
Move-steal contents from another vector_basic.
void pop_back_impl() FL_NO_EXCEPT
bool full() const FL_NO_EXCEPT
fl::size element_size() const FL_NO_EXCEPT
void insert_copy_impl(fl::size index, const void *element) FL_NO_EXCEPT
Insert element at index by copy. Shifts subsequent elements right.
void * data_raw() FL_NO_EXCEPT
Type-erased vector base class.
PMR-style polymorphic memory resource for type-erased allocation.
constexpr fl::enable_if< has_default_ctor< T >::value, void(*)(void *)>::type get_default_construct_fn() FL_NO_EXCEPT
void vector_default_construct(void *ptr) FL_NO_EXCEPT
constexpr fl::enable_if< has_copy_ctor< T >::value, void(*)(void *, constvoid *)>::type get_copy_construct_fn() FL_NO_EXCEPT
constexpr fl::enable_if< is_swappable< T >::value, void(*)(void *, void *)>::type get_swap_fn() FL_NO_EXCEPT
void vector_move_construct(void *dst, void *src) FL_NO_EXCEPT
void vector_copy_construct(void *dst, const void *src) FL_NO_EXCEPT
void vector_swap_elements(void *a, void *b) FL_NO_EXCEPT
constexpr fl::enable_if< has_move_ctor< T >::value, void(*)(void *, void *)>::type get_move_construct_fn() FL_NO_EXCEPT
void vector_destroy_n(void *first, fl::size count) FL_NO_EXCEPT
integral_constant< bool, true > true_type
Definition s16x16x4.h:28
add_rvalue_reference< T >::type declval() FL_NO_EXCEPT
integral_constant< bool, false > false_type
Definition s16x16x4.h:29
u8 u8 fract8 blur_amount FL_NO_EXCEPT
Definition blur.h:186
constexpr int type_rank< T >::value
add_rvalue_reference< T >::type declval() FL_NO_EXCEPT
const vector_element_ops * vector_element_ops_for() FL_NO_EXCEPT
Generate a static ops table for type T.
Base definition for an LED controller.
void(* default_construct)(void *ptr)
void(* swap_elements)(void *a, void *b)
void(* copy_construct)(void *dst, const void *src)
void(* move_construct)(void *dst, void *src)
void(* destroy_n)(void *first, fl::size count)
Destroy count elements starting at first (count == 1 for a single element: one destroy thunk per type...
Function pointer table for type-specific element operations.