16#ifndef FASTLED_DEFAULT_SLAB_SIZE
17#define FASTLED_DEFAULT_SLAB_SIZE 8
23template <
typename Po
inter,
typename SizeType>
31template <
typename Allocator>
35 using pointer =
typename Allocator::pointer;
40 template <
typename A = Allocator,
typename =
void>
45 fl::declval<typename A::pointer>(),
46 fl::declval<typename A::size_type>(),
47 fl::declval<typename A::size_type>()
54 template <
typename A = Allocator,
typename =
void>
59 fl::declval<typename A::size_type>()
66#if defined(FASTLED_TESTING)
71 virtual void onMalloc(
void* ptr, fl::size size)
FL_NO_EXCEPT = 0;
76void SetMallocFreeHook(MallocFreeHook* hook)
FL_NO_EXCEPT;
111void* InternalAlloc(fl::size size);
112void* InternalRealloc(
void* ptr, fl::size size);
113void InternalFree(
void* ptr);
114void* DMAAlloc(fl::size size);
115void DMAFree(
void* ptr);
146 template <
typename U>
155 template <
typename U>
184 if (new_count == 0) {
197 T* new_ptr =
static_cast<T*
>(
result);
200 if (new_count > old_count) {
201 fl::memset(new_ptr + old_count, 0, (new_count - old_count) *
sizeof(T));
224 fl::size size =
sizeof(T) * n;
226 if (ptr ==
nullptr) {
230 return static_cast<T*
>(ptr);
242 template <
typename U,
typename... Args>
244 if (p ==
nullptr)
return;
249 template <
typename U>
251 if (p ==
nullptr)
return;
276 "allocator_realloc<T> requires T to be trivially copyable. "
277 "NOTE: This allocator is now redundant - fl::allocator<T> automatically "
278 "optimizes trivially copyable types. Just use fl::vector<T> instead.");
291 template <
typename U>
300 template <
typename U>
311 fl::size size =
sizeof(T) * n;
313 if (ptr ==
nullptr) {
317 return static_cast<T*
>(ptr);
330 template <
typename U,
typename... Args>
332 if (p ==
nullptr)
return;
337 template <
typename U>
339 if (p ==
nullptr)
return;
350 fl::size requested = (3 * n) / 2;
353 return {ptr, requested};
357 return {ptr, ptr ? n : 0};
364 if (new_count == 0) {
377 T* new_ptr =
static_cast<T*
>(
result);
380 if (new_count > old_count) {
381 fl::memset(new_ptr + old_count, 0, (new_count - old_count) *
sizeof(T));
400 template <
typename U>
409 template <
typename U>
427 template <
typename U,
typename... Args>
429 if (p ==
nullptr)
return;
434 template <
typename U>
436 if (p ==
nullptr)
return;
461template <
typename T, fl::size SLAB_SIZE = FASTLED_DEFAULT_SLAB_SIZE>
465 static constexpr fl::size
SLAB_BLOCK_SIZE =
sizeof(T) >
sizeof(
void*) ?
sizeof(T) : sizeof(void*);
519 for (
Slab* slab =
mSlabs; slab; slab = slab->next) {
547 fl::i32 start = slab->allocated_blocks.find_run(
false,
static_cast<fl::u32
>(n));
550 for (fl::size i = 0; i < n; ++i) {
551 slab->allocated_blocks.set(
static_cast<fl::u32
>(start + i),
true);
553 slab->allocated_count += n;
569 for (
Slab* slab =
mSlabs; slab; slab = slab->next) {
570 u8* slab_start = slab->memory;
574 if (block_ptr >= slab_start && block_ptr < slab_end) {
578 for (fl::size i = 0; i < n; ++i) {
580 slab->allocated_blocks.set(block_index + i,
false);
584 slab->allocated_count -= n;
607 other.mSlabs =
nullptr;
608 other.mTotalAllocated = 0;
609 other.mTotalDeallocated = 0;
613 if (
this != &other) {
618 other.mSlabs =
nullptr;
619 other.mTotalAllocated = 0;
620 other.mTotalDeallocated = 0;
642 return static_cast<T*
>(ptr);
646 ptr =
Malloc(
sizeof(T) * n);
650 return static_cast<T*
>(ptr);
660 bool found_in_slab =
false;
661 for (
Slab* slab =
mSlabs; slab; slab = slab->next) {
662 u8* slab_start = slab->memory;
666 if (block_ptr >= slab_start && block_ptr < slab_end) {
668 found_in_slab =
true;
673 if (!found_in_slab) {
687 for (
Slab* slab =
mSlabs; slab; slab = slab->next) {
708template <
typename T, fl::size SLAB_SIZE = FASTLED_DEFAULT_SLAB_SIZE>
721 template <
typename U>
745 template <
typename U>
758 constexpr fl::size block_size =
sizeof(T) >
sizeof(
void*) ?
sizeof(T) :
sizeof(
void*);
785 template <
typename U,
typename... Args>
787 if (p ==
nullptr)
return;
792 template <
typename U>
794 if (p ==
nullptr)
return;
812 return !(*
this == other);
818template <
typename T, fl::size N,
typename BaseAllocator = fl::allocator<T>>
848 template <
typename U>
875 if (
this != &other) {
896 template <
typename U>
923 fl::i32 free_slot =
mFreeBits.find_first(
false);
924 if (free_slot >= 0 &&
static_cast<fl::size
>(free_slot) < N) {
926 mFreeBits.set(
static_cast<fl::u32
>(free_slot),
true);
929 if (
static_cast<fl::size
>(free_slot) + 1 >
mInlinedUsed) {
952 T* inlined_end = inlined_start + N;
954 if (p >= inlined_start && p < inlined_end) {
956 fl::size slot_index = (p - inlined_start);
957 for (fl::size i = 0; i < n; ++i) {
958 if (slot_index + i < N) {
972 template <
typename U,
typename... Args>
974 if (p ==
nullptr)
return;
979 template <
typename U>
981 if (p ==
nullptr)
return;
1024 template<
typename U>
1027 template<
typename U>
1052 return !(*
this == other);
1057template <
typename T, fl::size N>
1061template <
typename T, fl::size N, fl::size SLAB_SIZE = 8>
1064template <
typename T, fl::size N>
Alignment macros and utilities for FastLED.
static T * Alloc(fl::size n) FL_NO_EXCEPT
static void Free(T *p) FL_NO_EXCEPT
Slab * createSlab() FL_NO_EXCEPT
static constexpr fl::size BLOCKS_PER_SLAB
T * allocate(fl::size n=1) FL_NO_EXCEPT
SlabAllocator & operator=(const SlabAllocator &) FL_NO_EXCEPT=delete
void cleanup() FL_NO_EXCEPT
SlabAllocator(const SlabAllocator &) FL_NO_EXCEPT=delete
SlabAllocator & operator=(SlabAllocator &&other) FL_NO_EXCEPT
fl::size mTotalDeallocated
void * findContiguousBlocks(Slab *slab, fl::size n) FL_NO_EXCEPT
fl::size getTotalDeallocated() const FL_NO_EXCEPT
static constexpr fl::size SLAB_MEMORY_SIZE
SlabAllocator() FL_NO_EXCEPT
static constexpr fl::size SLAB_BLOCK_SIZE
void * allocateFromSlab(fl::size n=1) FL_NO_EXCEPT
fl::size getActiveAllocations() const FL_NO_EXCEPT
void deallocate(T *ptr, fl::size n=1) FL_NO_EXCEPT
~SlabAllocator() FL_NO_EXCEPT
SlabAllocator(SlabAllocator &&other) FL_NO_EXCEPT
fl::size getTotalAllocated() const FL_NO_EXCEPT
fl::detail::slab_mutex mMutex
void deallocateToSlab(void *ptr, fl::size n=1) FL_NO_EXCEPT
fl::size getSlabCount() const FL_NO_EXCEPT
BaseAllocator mBaseAllocator
InlinedStorage mInlinedStorage
fl::size mActiveAllocations
static auto has_cleanup_impl(int) FL_NO_EXCEPT -> decltype(fl::declval< U >().cleanup(), fl::true_type{})
static fl::false_type has_cleanup_impl(...) FL_NO_EXCEPT
bool operator!=(const allocator_inlined &other) const FL_NO_EXCEPT
T * allocate(fl::size n) FL_NO_EXCEPT
allocator_inlined & operator=(const allocator_inlined &other) FL_NO_EXCEPT
void cleanup_base_allocator_impl(fl::true_type) FL_NO_EXCEPT
bool operator==(const allocator_inlined &other) const FL_NO_EXCEPT
void clear() FL_NO_EXCEPT
decltype(has_cleanup_impl< BaseAllocator >(0)) has_cleanup
const T & const_reference
const T * get_inlined_ptr() const FL_NO_EXCEPT
allocator_inlined() FL_NO_EXCEPT=default
allocator_inlined(const allocator_inlined< U, N, typename BaseAllocator::template rebind< U >::other > &other) FL_NO_EXCEPT
void cleanup_base_allocator() FL_NO_EXCEPT
T * get_inlined_ptr() FL_NO_EXCEPT
~allocator_inlined() FL_NO_EXCEPT
void destroy(U *p) FL_NO_EXCEPT
void construct(U *p, Args &&... args) FL_NO_EXCEPT
fl::ptrdiff_t difference_type
bool is_using_inlined() const FL_NO_EXCEPT
fl::size inlined_capacity() const FL_NO_EXCEPT
void cleanup_base_allocator_impl(fl::false_type) FL_NO_EXCEPT
fl::size total_size() const FL_NO_EXCEPT
void deallocate(T *p, fl::size n) FL_NO_EXCEPT
fl::bitset_fixed< N > mFreeBits
allocator_inlined< U, N, typename BaseAllocator::template rebind< U >::other > other
void construct(U *p, Args &&... args) FL_NO_EXCEPT
void deallocate(T *p, fl::size n) FL_NO_EXCEPT
allocation_result< pointer, size_type > allocate_at_least(fl::size n) FL_NO_EXCEPT
allocator_psram(const allocator_psram< U > &) FL_NO_EXCEPT
const T & const_reference
T * allocate(fl::size n) FL_NO_EXCEPT
pointer reallocate(pointer ptr, fl::size old_count, fl::size new_count) FL_NO_EXCEPT
~allocator_psram() FL_NO_EXCEPT
allocator_psram() FL_NO_EXCEPT
void destroy(U *p) FL_NO_EXCEPT
fl::ptrdiff_t difference_type
allocator_psram< U > other
~allocator_realloc() FL_NO_EXCEPT
const T & const_reference
allocation_result< pointer, size_type > allocate_at_least(fl::size n) FL_NO_EXCEPT
pointer reallocate(pointer ptr, fl::size old_count, fl::size new_count) FL_NO_EXCEPT
allocator_realloc(const allocator_realloc< U > &) FL_NO_EXCEPT
T * allocate(fl::size n) FL_NO_EXCEPT
allocator_realloc() FL_NO_EXCEPT
void destroy(U *p) FL_NO_EXCEPT
FL_STATIC_ASSERT(fl::is_trivially_copyable< T >::value, "allocator_realloc<T> requires T to be trivially copyable. " "NOTE: This allocator is now redundant - fl::allocator<T> automatically " "optimizes trivially copyable types. Just use fl::vector<T> instead.")
void deallocate(T *p, fl::size n) FL_NO_EXCEPT
void construct(U *p, Args &&... args) FL_NO_EXCEPT
fl::ptrdiff_t difference_type
allocator_realloc< U > other
allocator_slab() FL_NO_EXCEPT
static SlabAllocator< T, SLAB_SIZE > & get_allocator() FL_NO_EXCEPT
bool operator==(const allocator_slab &other) const FL_NO_EXCEPT
void deallocate(T *p, fl::size n) FL_NO_EXCEPT
fl::ptrdiff_t difference_type
void destroy(U *p) FL_NO_EXCEPT
~allocator_slab() FL_NO_EXCEPT
allocator_slab(const allocator_slab &other) FL_NO_EXCEPT
allocator_slab(const allocator_slab< U, SLAB_SIZE > &other) FL_NO_EXCEPT
const T & const_reference
bool operator!=(const allocator_slab &other) const FL_NO_EXCEPT
void cleanup() FL_NO_EXCEPT
allocator_slab & operator=(const allocator_slab &other) FL_NO_EXCEPT
void construct(U *p, Args &&... args) FL_NO_EXCEPT
T * allocate(fl::size n) FL_NO_EXCEPT
typename fl::conditional< fl::is_same< U, void >::value, allocator_slab< char, SLAB_SIZE >, allocator_slab< U, SLAB_SIZE > >::type other
void destroy(U *p) FL_NO_EXCEPT
pointer reallocate_impl(pointer ptr, fl::size old_count, fl::size new_count, fl::true_type) FL_NO_EXCEPT
fl::ptrdiff_t difference_type
~allocator() FL_NO_EXCEPT
void deallocate(T *p, fl::size n) FL_NO_EXCEPT
T * allocate(fl::size n) FL_NO_EXCEPT
void construct(U *p, Args &&... args) FL_NO_EXCEPT
const T & const_reference
allocation_result< pointer, size_type > allocate_at_least(fl::size n) FL_NO_EXCEPT
pointer reallocate(pointer ptr, fl::size old_count, fl::size new_count) FL_NO_EXCEPT
allocator(const allocator< U > &) FL_NO_EXCEPT
pointer reallocate_impl(pointer ptr, fl::size old_count, fl::size new_count, fl::false_type) FL_NO_EXCEPT
RAII guard for slab_mutex.
Single-threaded MCUs: no-op.
#define FASTLED_UNUSED(x)
void * slab_allocator_registry_get(fl::size block_size, fl::size slab_size)
void slab_allocator_registry_set(fl::size block_size, fl::size slab_size, void *allocator)
add_rvalue_reference< T >::type declval() FL_NO_EXCEPT
integral_constant< bool, false > false_type
void SetPSRamAllocator(void *(*alloc)(fl::size), void(*free)(void *))
expected< T, E > result
Alias for expected (Rust-style naming)
void PSRamDeallocate(void *ptr)
void * memset(void *s, int c, size_t n) FL_NO_EXCEPT
constexpr T && forward(typename remove_reference< T >::type &t) FL_NO_EXCEPT
void * Malloc(fl::size size)
InputGamut g FL_NO_EXCEPT
void * realloc(void *ptr, size_t new_size)
allocator_inlined< T, N, fl::allocator_slab< T > > allocator_inlined_slab
void * PSRamAllocate(fl::size size, bool zero)
To * bit_cast_ptr(void *storage) FL_NO_EXCEPT
integral_constant< bool, true > true_type
allocator_inlined< T, N, fl::allocator_slab< T, SLAB_SIZE > > allocator_inlined_slab_psram
allocator_inlined< T, N, fl::allocator_psram< T > > allocator_inlined_psram
Base definition for an LED controller.
Minimal mutex for the allocator layer (FastLED#3588).
Portable compile-time assertion wrapper.
PSRamDeleter() FL_NO_EXCEPT=default
fl::bitset_fixed< BLOCKS_PER_SLAB > allocated_blocks
InlinedStorage() FL_NO_EXCEPT
FL_ALIGN_AS(T) u8 data[N *sizeof(T)]
typename Allocator::pointer pointer
static constexpr bool has_allocate_at_least_v
typename Allocator::value_type value_type
static constexpr bool has_reallocate_v
typename Allocator::size_type size_type