FastLED 3.9.15
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 (*destroy)(void* ptr);
25 void (*default_construct)(void* ptr);
26 void (*swap_elements)(void* a, void* b);
27
29 void (*uninitialized_move_n)(void* dst, void* src, fl::size count);
30
32 void (*destroy_n)(void* first, fl::size count);
33};
34
40 public:
41 // ======= CAPACITY =======
42 fl::size size() const FL_NOEXCEPT { return mSize; }
43 bool empty() const FL_NOEXCEPT { return mSize == 0; }
44 fl::size capacity() const FL_NOEXCEPT { return mCapacity; }
45 bool full() const FL_NOEXCEPT { return mSize >= mCapacity; }
46 fl::size element_size() const FL_NOEXCEPT { return mElementSize; }
47
48 // ======= RAW DATA ACCESS =======
49 void* data_raw() FL_NOEXCEPT { return mArray; }
50 const void* data_raw() const FL_NOEXCEPT { return mArray; }
51
52 // ======= MEMORY MANAGEMENT =======
53 void reserve_impl(fl::size n) FL_NOEXCEPT;
55
56 // ======= ELEMENT OPERATIONS =======
57 void push_back_copy_impl(const void* element) FL_NOEXCEPT;
58 void push_back_move_impl(void* element) FL_NOEXCEPT;
61
63 void erase_impl(fl::size index) FL_NOEXCEPT;
64
66 void erase_range_impl(fl::size first_index, fl::size count) FL_NOEXCEPT;
67
69 void insert_copy_impl(fl::size index, const void* element) FL_NOEXCEPT;
70
72 void insert_move_impl(fl::size index, void* element) FL_NOEXCEPT;
73
76
78 void resize_value_impl(fl::size n, const void* value) FL_NOEXCEPT;
79
82
83 // ======= DESTRUCTOR =======
85
86 protected:
87 // ======= CONSTRUCTION (only callable by vector<T>) =======
88
90 vector_basic(fl::size elementSize, memory_resource* resource,
92 : mElementSize(elementSize)
93 , mResource(resource)
94 , mOps(ops)
95 , mInlineOffset(0)
96 , mInlineCapacity(0) {}
97
99 vector_basic(void* inlineBuffer, fl::size inlineCapacity,
100 fl::size elementSize, memory_resource* resource,
101 const vector_element_ops* ops)
102 FL_NOEXCEPT : mElementSize(elementSize)
103 , mResource(resource)
104 , mOps(ops)
105 , mInlineOffset(static_cast<fl::size>(
106 static_cast<char*>(inlineBuffer) -
107 static_cast<char*>(static_cast<void*>(this))))
108 , mInlineCapacity(inlineCapacity) {
109 // Start with data in inline buffer
110 mArray = inlineBuffer;
111 mCapacity = inlineCapacity;
112 }
113
114 // Deleted copy/move — vector<T> handles these
117 vector_basic& operator=(const vector_basic&) FL_NOEXCEPT = delete;
118 vector_basic& operator=(vector_basic&&) FL_NOEXCEPT = delete;
119
120 // ======= HELPERS FOR DERIVED CLASSES =======
121
123 void copy_from(const vector_basic& other) FL_NOEXCEPT;
124
127
130
131 // ======= DATA MEMBERS =======
132 void* mArray = nullptr;
137 const vector_element_ops* mOps; // nullptr → trivially copyable
138
139 // Inline buffer support (offset trick from basic_string).
140 // Store offset from `this` to the inline buffer, not a raw pointer.
141 // This survives trivial relocation (bitwise copy by containers) because
142 // the offset is relative to `this` which updates with the object.
144 fl::size mInlineCapacity; // 0 = no inline buffer
145
146 // ======= HELPER METHODS =======
147
150 return static_cast<char*>(static_cast<void*>(this)) + mInlineOffset;
151 }
152 const void* inlineBufferPtr() const FL_NOEXCEPT {
153 return static_cast<const char*>(static_cast<const void*>(this)) + mInlineOffset;
154 }
155
157 bool isInline() const FL_NOEXCEPT {
158 return mInlineCapacity > 0 && mArray == inlineBufferPtr();
159 }
160
163 return mInlineCapacity > 0;
164 }
165
167 void* element_ptr(fl::size index) FL_NOEXCEPT {
168 return static_cast<char*>(mArray) + index * mElementSize;
169 }
170 const void* element_ptr(fl::size index) const FL_NOEXCEPT {
171 return static_cast<const char*>(mArray) + index * mElementSize;
172 }
173
174 private:
176 void ensure_capacity(fl::size n) FL_NOEXCEPT;
177
179 void grow_to(fl::size new_capacity) FL_NOEXCEPT;
180
181 // ======= TRIVIAL ELEMENT HELPERS (memcpy/memmove) =======
182 void trivial_copy(void* dst, const void* src, fl::size count) const FL_NOEXCEPT;
183 void trivial_move_left(void* dst, const void* src, fl::size count) const FL_NOEXCEPT;
184 void trivial_default_construct(void* ptr, fl::size count) const FL_NOEXCEPT;
185 void trivial_swap(void* a, void* b) const FL_NOEXCEPT;
186};
187
188// ======= OPS TABLE HELPERS =======
189
190namespace detail {
191
192// SFINAE: detect if T is default-constructible
193template <typename T, typename = void>
195
196template <typename T>
197struct has_default_ctor<T, decltype(void(T()))> : fl::true_type {};
198
199// SFINAE: detect if T is copy-constructible
200template <typename T, typename = void>
202
203template <typename T>
204struct has_copy_ctor<T, decltype(void(T(fl::declval<const T&>())))> : fl::true_type {};
205
206// Default construct: available when T has default ctor
207template <typename T>
210 return [](void* ptr) FL_NOEXCEPT { new (ptr) T(); };
211}
212
213// Default construct: nullptr when T has no default ctor
214template <typename T>
217 return nullptr;
218}
219
220// Copy construct: available when T has copy ctor
221template <typename T>
222typename fl::enable_if<has_copy_ctor<T>::value, void(*)(void*, const void*) FL_NOEXCEPT>::type
224 return [](void* dst, const void* src) FL_NOEXCEPT {
225 new (dst) T(*static_cast<const T*>(src));
226 };
227}
228
229// Copy construct: nullptr when T is not copyable
230template <typename T>
231typename fl::enable_if<!has_copy_ctor<T>::value, void(*)(void*, const void*) FL_NOEXCEPT>::type
233 return nullptr;
234}
235
236// SFINAE: detect if T is move-constructible
237template <typename T, typename = void>
239
240template <typename T>
241struct has_move_ctor<T, decltype(void(T(fl::declval<T&&>())))> : fl::true_type {};
242
243// SFINAE: detect if T is swappable (needs move-constructible + move-assignable)
244template <typename T, typename = void>
246
247template <typename T>
248struct is_swappable<T, decltype(void(
249 fl::declval<T&>() = fl::declval<T&&>()
250))> : has_move_ctor<T> {};
251
252// Move construct: available
253template <typename T>
254typename fl::enable_if<has_move_ctor<T>::value, void(*)(void*, void*) FL_NOEXCEPT>::type
256 return [](void* dst, void* src) FL_NOEXCEPT {
257 new (dst) T(static_cast<T&&>(*static_cast<T*>(src)));
258 };
259}
260
261template <typename T>
262typename fl::enable_if<!has_move_ctor<T>::value, void(*)(void*, void*) FL_NOEXCEPT>::type
264 return nullptr;
265}
266
267// Swap: available when swappable
268template <typename T>
269typename fl::enable_if<is_swappable<T>::value, void(*)(void*, void*) FL_NOEXCEPT>::type
271 return [](void* a, void* b) FL_NOEXCEPT {
272 T& ta = *static_cast<T*>(a);
273 T& tb = *static_cast<T*>(b);
274 T tmp(static_cast<T&&>(ta));
275 ta = static_cast<T&&>(tb);
276 tb = static_cast<T&&>(tmp);
277 };
278}
279
280template <typename T>
281typename fl::enable_if<!is_swappable<T>::value, void(*)(void*, void*) FL_NOEXCEPT>::type
283 return nullptr;
284}
285
286// Uninitialized move N: available when move-constructible
287template <typename T>
288typename fl::enable_if<has_move_ctor<T>::value, void(*)(void*, void*, fl::size) FL_NOEXCEPT>::type
290 return [](void* dst, void* src, fl::size count) FL_NOEXCEPT {
291 T* d = static_cast<T*>(dst);
292 T* s = static_cast<T*>(src);
293 for (fl::size i = 0; i < count; ++i) {
294 new (&d[i]) T(static_cast<T&&>(s[i]));
295 }
296 };
297}
298
299template <typename T>
300typename fl::enable_if<!has_move_ctor<T>::value, void(*)(void*, void*, fl::size) FL_NOEXCEPT>::type
302 return nullptr;
303}
304
305} // namespace detail
306
307// ======= OPS TABLE GENERATOR =======
308
311template <typename T>
313 // Trivially copyable types use the fast path (mOps == nullptr)
315 return nullptr;
316 }
317
318 static const vector_element_ops ops = {
319 detail::get_copy_construct_fn<T>(), // copy_construct
320 detail::get_move_construct_fn<T>(), // move_construct
321 [](void* ptr) { static_cast<T*>(ptr)->~T(); }, // destroy
322 detail::get_default_construct_fn<T>(), // default_construct
323 detail::get_swap_fn<T>(), // swap_elements
324 detail::get_uninitialized_move_n_fn<T>(), // uninitialized_move_n
325 // destroy_n
326 [](void* first, fl::size count) FL_NOEXCEPT {
327 T* p = static_cast<T*>(first);
328 for (fl::size i = 0; i < count; ++i) {
329 p[i].~T();
330 }
331 }
332 };
333 return &ops;
334}
335
336} // namespace fl
Polymorphic memory resource base class (PMR-style).
void resize_value_impl(fl::size n, const void *value) FL_NOEXCEPT
Resize to n elements. New elements are copy-constructed from value.
void resize_impl(fl::size n) FL_NOEXCEPT
Resize to n elements. New elements are default-constructed (zeroed for trivial).
void grow_to(fl::size new_capacity) FL_NOEXCEPT
Grow to new_capacity. Moves existing elements.
const void * element_ptr(fl::size index) const FL_NOEXCEPT
const void * inlineBufferPtr() const FL_NOEXCEPT
void erase_impl(fl::size index) FL_NOEXCEPT
Erase element at index. Shifts subsequent elements left.
const vector_element_ops * mOps
void reserve_impl(fl::size n) FL_NOEXCEPT
bool hasInlineBuffer() const FL_NOEXCEPT
Does this vector have an inline buffer at all?
void trivial_default_construct(void *ptr, fl::size count) const FL_NOEXCEPT
void push_back_move_impl(void *element) FL_NOEXCEPT
void shrink_to_fit_impl() FL_NOEXCEPT
bool isInline() const FL_NOEXCEPT
Is data currently in the inline buffer?
void insert_move_impl(fl::size index, void *element) FL_NOEXCEPT
Insert element at index by move. Shifts subsequent elements right.
fl::size mElementSize
vector_basic(void *inlineBuffer, fl::size inlineCapacity, fl::size elementSize, memory_resource *resource, const vector_element_ops *ops) FL_NOEXCEPT
Vector with inline buffer (for VectorN).
memory_resource * mResource
void trivial_swap(void *a, void *b) const FL_NOEXCEPT
void move_from(vector_basic &other) FL_NOEXCEPT
Move-steal contents from another vector_basic.
void trivial_copy(void *dst, const void *src, fl::size count) const FL_NOEXCEPT
vector_basic(fl::size elementSize, memory_resource *resource, const vector_element_ops *ops) FL_NOEXCEPT
Heap-only vector (no inline buffer).
const void * data_raw() const FL_NOEXCEPT
fl::size size() const FL_NOEXCEPT
void ensure_capacity(fl::size n) FL_NOEXCEPT
Ensure capacity for at least n elements. Grows if needed.
fl::size mInlineOffset
void insert_copy_impl(fl::size index, const void *element) FL_NOEXCEPT
Insert element at index by copy. Shifts subsequent elements right.
void move_assign(vector_basic &other) FL_NOEXCEPT
Move-assign from another vector_basic (clears this first).
void * element_ptr(fl::size index) FL_NOEXCEPT
Pointer to element at index (byte arithmetic).
vector_basic(vector_basic &&) FL_NOEXCEPT=delete
fl::size mInlineCapacity
bool full() const FL_NOEXCEPT
void * inlineBufferPtr() FL_NOEXCEPT
Compute inline buffer pointer from offset.
void * data_raw() FL_NOEXCEPT
void copy_from(const vector_basic &other) FL_NOEXCEPT
Copy all elements from another vector_basic.
fl::size element_size() const FL_NOEXCEPT
void clear_impl() FL_NOEXCEPT
void trivial_move_left(void *dst, const void *src, fl::size count) const FL_NOEXCEPT
bool empty() const FL_NOEXCEPT
fl::size capacity() const FL_NOEXCEPT
vector_basic(const vector_basic &) FL_NOEXCEPT=delete
void pop_back_impl() FL_NOEXCEPT
void push_back_copy_impl(const void *element) FL_NOEXCEPT
void erase_range_impl(fl::size first_index, fl::size count) FL_NOEXCEPT
Erase range [first_index, first_index + count).
Type-erased vector base class.
PMR-style polymorphic memory resource for type-erased allocation.
fl::enable_if< is_swappable< T >::value, void(*)(void *, void *) FL_NOEXCEPT >::type get_swap_fn() FL_NOEXCEPT
fl::enable_if< has_move_ctor< T >::value, void(*)(void *, void *) FL_NOEXCEPT >::type get_move_construct_fn() FL_NOEXCEPT
fl::enable_if< has_copy_ctor< T >::value, void(*)(void *, constvoid *) FL_NOEXCEPT >::type get_copy_construct_fn() FL_NOEXCEPT
fl::enable_if< has_default_ctor< T >::value, void(*)(void *) FL_NOEXCEPT >::type get_default_construct_fn() FL_NOEXCEPT
fl::enable_if< has_move_ctor< T >::value, void(*)(void *, void *, fl::size) FL_NOEXCEPT >::type get_uninitialized_move_n_fn() FL_NOEXCEPT
integral_constant< bool, true > true_type
Definition s16x16x4.h:27
add_rvalue_reference< T >::type declval() FL_NOEXCEPT
integral_constant< bool, false > false_type
Definition s16x16x4.h:28
constexpr int type_rank< T >::value
add_rvalue_reference< T >::type declval() FL_NOEXCEPT
const vector_element_ops * vector_element_ops_for() FL_NOEXCEPT
Generate a static ops table for type T.
Base definition for an LED controller.
Definition crgb.hpp:179
void(* default_construct)(void *ptr)
void(* destroy)(void *ptr)
void(* swap_elements)(void *a, void *b)
void(* uninitialized_move_n)(void *dst, void *src, fl::size count)
Move-construct count elements from src to dst (non-overlapping, dst uninitialized).
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.
Function pointer table for type-specific element operations.
#define FL_NOEXCEPT