Generated Documentation (C API)#
-
enum FP_MagicNumbers#
Magic numbers used to identify fat pointer types.
These magic numbers are stored in the header of each fat pointer to identify its allocation type and validate that a pointer is indeed a fat pointer.
Note
These were chosen explicitly to be invalid unicode code points.
Values:
-
enumerator FP_MAGIC_NUMBER#
Base magic number (high byte mask)
-
enumerator FP_HEAP_MAGIC_NUMBER#
Heap-allocated fat pointer.
-
enumerator FP_STACK_MAGIC_NUMBER#
Stack-allocated fat pointer.
-
enumerator FP_DYNARRAY_MAGIC_NUMBER#
Dynamic array fat pointer.
-
enumerator FP_MAGIC_NUMBER#
-
static thread_local struct __FatPointerHeader *__fp_global_header#
Thread local header utilized as an intermediate by fp_alloca and fp_alloca_void.
-
static inline void *__fp_alloc_default_impl(void *p, size_t size) noexcept#
Default memory allocation function used by the fat pointer library.
This function handles allocation, reallocation, and deallocation:
If p is NULL and size > 0: allocates new memory
If p is not NULL and size > 0: reallocates and copies data
If size is 0: frees memory and returns NULL
If size equals current allocation size: may return p unchanged
You can override this by defining FP_ALLOCATION_FUNCTION before including this header.
// Custom allocator example void* my_allocator(void* p, size_t size) { // Your custom allocation logic return custom_realloc(p, size); } #define FP_ALLOCATION_FUNCTION my_allocator
- Parameters:
p – Pointer to reallocate (NULL for new allocation)
size – Size in bytes to allocate (0 to free)
- Returns:
Pointer to allocated memory or NULL if freed
-
static inline constexpr bool is_fp(const void *p) noexcept#
Check if a pointer is a valid fat pointer.
int* arr = fp_malloc(int, 10); int* regular = malloc(sizeof(int) * 10); assert(is_fp(arr) == true); assert(is_fp(regular) == false); assert(is_fp(NULL) == false); fp_free_and_null(arr); free(regular);
- Parameters:
p – Pointer to check
- Returns:
true if p is a valid fat pointer, false otherwise
-
static inline constexpr size_t fp_magic_number(const void *p) noexcept#
Get the magic number of a fat pointer.
See also
- Parameters:
p – Fat pointer
- Returns:
Magic number identifying the allocation type
-
static inline constexpr bool fp_is_stack_allocated(const void *p) noexcept#
Check if a fat pointer is stack-allocated.
int* heap = fp_malloc(int, 10); int* stack = fp_alloca(int, 10); assert(!fp_is_stack_allocated(heap)); assert(fp_is_stack_allocated(stack));
- Parameters:
p – Fat pointer
- Returns:
true if stack-allocated, false otherwise
-
static inline constexpr bool fp_is_heap_allocated(const void *p) noexcept#
Check if a fat pointer is heap-allocated.
int* heap = fp_malloc(int, 10); int* stack = fp_alloca(int, 10); assert(fp_is_heap_allocated(heap)); assert(!fp_is_heap_allocated(stack));
- Parameters:
p – Fat pointer
- Returns:
true if heap-allocated, false otherwise
-
static inline void fp_free(void *p) noexcept#
Free a heap-allocated fat pointer.
int* data = fp_malloc(int, 100); // ... use data ... fp_free(data);
Warning
Only use with heap-allocated fat pointers (from fp_malloc/fp_realloc). Stack-allocated pointers are freed automatically.
- Parameters:
p – Fat pointer to free
-
static inline constexpr size_t fp_length(const void *p) noexcept#
Get the number of elements in a fat pointer.
double* arr = fp_malloc(double, 75); printf("Array has %zu elements\n", fp_length(arr)); // Prints: 75
- Parameters:
p – Fat pointer
- Returns:
Number of elements (not bytes) in the allocation
-
static inline constexpr bool fp_empty(const void *p) noexcept#
Check if a fat pointer is empty (zero length)
int* empty = fp_malloc(int, 0); int* full = fp_malloc(int, 10); assert(fp_empty(empty)); assert(!fp_empty(full));
- Parameters:
p – Fat pointer
- Returns:
true if empty, false otherwise
-
void *memswap(void *a, void *b, size_t n) noexcept#
Swap memory contents of two regions.
int x = 10, y = 20; memswap(&x, &y, sizeof(int)); // Now x == 20, y == 10
- Parameters:
a – First memory region
b – Second memory region
n – Number of bytes to swap
- Returns:
Pointer to first region (second before the swap), or NULL if regions are identical
-
static inline bool fp_swap(void *a, void *b) noexcept#
Swap contents of two fat pointers.
Both pointers must have the same size for the swap to succeed.
int* arr1 = fp_malloc(int, 5); int* arr2 = fp_malloc(int, 5); fp_iterate(arr1) { *i = 1; } fp_iterate(arr2) { *i = 2; } fp_swap(arr1, arr2); // Now arr1 contains all 2s, arr2 contains all 1s
- Parameters:
a – First fat pointer
b – Second fat pointer
- Returns:
true if swap succeeded, false if sizes don’t match
-
static inline constexpr int fp_view_compare(const fp_void_view a, const fp_void_view b) noexcept#
Compare two void views for equality.
- Parameters:
a – First view
b – Second view
- Returns:
0 if equal, non-zero otherwise
-
static inline constexpr bool fp_view_equal(const fp_void_view a, const fp_void_view b) noexcept#
Check if two void views are equal.
- Parameters:
a – First view
b – Second view
- Returns:
true if views have same size and content, false otherwise
-
static inline bool fp_view_swap(fp_void_view a, fp_void_view b) noexcept#
Swap contents of two void views.
- Parameters:
a – First view
b – Second view
- Returns:
true if swap succeeded, false if sizes don’t match
-
do_and_assert(action, assertion)#
Executes an action and asserts a condition based on the result in debug mode.
The action is always executed, but the assertion only fires in debug builds. This ensures side effects occur in both debug and release builds.
do_and_assert(fopen("file.txt", "r"), res != NULL);
- Parameters:
action – Expression to execute (result stored in ‘res’)
assertion – Condition to assert (can reference ‘res’)
-
assert_with_side_effects(assertion)#
Assert macro where the condition itself has side effects that must always execute.
assert_with_side_effects(write(fd, buffer, size) == size);
- Parameters:
assertion – Expression to evaluate (always executed, assertion checked in debug)
-
FP_NOEXCEPT#
noexceptin C++, empty in C
-
FP_CONSTEXPR#
constexprin C++, empty in C
-
FP_ALLOCATION_FUNCTION#
-
FP_MAX(a, b)#
Maximum of two values.
- Parameters:
a – First value
b – Second value
- Returns:
Maximum of a and b
-
FP_MIN(a, b)#
Minimum of two values.
- Parameters:
a – First value
b – Second value
- Returns:
Minimum of a and b
-
fp_alloca_void(_typesize, _size)#
Allocate a fat pointer on the stack (generic version)
Stack-allocated fat pointers are automatically freed when the scope exits. Use fp_alloca() macro for type-safe version.
void process() { void* buffer = fp_alloca_void(1, 1024); // 1024 bytes // Use buffer... // Automatically freed on return }
Warning
Stack allocations have limited size. Use fp_malloc() for large allocations.
- Parameters:
_typesize – Size of each element in bytes
_size – Number of elements to allocate
- Returns:
Void pointer to allocated stack memory with fat pointer header
-
fp_alloca(type, _size)
Allocate a typed fat pointer on the stack.
Best practices:
Use fp_alloca() for temporary buffers < 10KB
Use fp_malloc() for anything larger or with dynamic lifetime
Never return stack-allocated pointers
Be careful with recursion and stack allocations
void compute() { int* numbers = fp_alloca(int, 50); for(int i = 0; i < 50; i++) { numbers[i] = i * i; } printf("Length: %zu\n", fp_length(numbers)); // Automatically freed }
See also
fp_alloca() for type-safe version
See also
fp_malloc() for heap allocation
See also
fp_is_stack_allocated() to check allocation type
Warning
Stack allocations have limited size. Use fp_malloc() for large allocations.
Warning
Stack memory is only valid within the current scope. Do not return stack-allocated pointers from functions.
- Parameters:
type – Element type
_size – Number of elements to allocate
- Returns:
Typed pointer to allocated stack memory
-
fp_malloc(type, _size)#
Allocate a typed fat pointer on the heap.
int* data = fp_malloc(int, 100); for(size_t i = 0; i < fp_length(data); i++) { data[i] = rand(); } fp_free_and_null(data);
- Parameters:
type – Element type
_size – Number of elements to allocate
- Returns:
Typed pointer to allocated heap memory
-
fp_realloc(type, p, _size)#
Reallocate a fat pointer with a new size.
Existing data is preserved up to the minimum of old and new sizes.
float* values = fp_malloc(float, 50); // ... use values ... values = fp_realloc(float, values, 100); // Expand to 100 elements
- Parameters:
type – Element type
p – Existing fat pointer
_size – New number of elements
- Returns:
Reallocated typed pointer (may be different address)
-
fp_free_and_null(p)#
Free a fat pointer and set it to NULL.
In general this macro is safer than using fp_free directly
int* data = fp_malloc(int, 50); fp_free_and_null(data); assert(data == NULL);
- Parameters:
p – Fat pointer to free
-
fp_size#
Alias for fp_length()
-
fp_front(a)#
Get pointer to the first element.
- Parameters:
a – Fat pointer
- Returns:
Pointer to first element
-
fp_begin(a)#
Alias for fp_front.
-
fp_back(a)#
Get pointer to the last element.
int* arr = fp_malloc(int, 10); *fp_front(arr) = 1; // First element *fp_back(arr) = 100; // Last element
- Parameters:
a – Fat pointer
- Returns:
Typed pointer to last element
-
fp_end(a)#
Get pointer to one past the last element (end iterator)
int* arr = fp_malloc(int, 5); for(int* p = fp_begin(arr); p != fp_end(arr); ++p) { *p = 0; }
- Parameters:
a – Fat pointer
- Returns:
Pointer to one past the end
-
fp_iterate_named(a, iter)#
Iterate over fat pointer with named iterator.
int* arr = fp_malloc(int, 10); fp_iterate_named(arr, ptr) { *ptr = ptr - arr; // Set to index }
- Parameters:
a – Fat pointer
iter – Iterator variable name
-
fp_iterate(a)#
Iterate over fat pointer (iterator named ‘i’)
float* values = fp_malloc(float, 20); fp_iterate(values) { *i = 3.14f; }
- Parameters:
a – Fat pointer
-
fp_iterate_calculate_index(a, i)#
Calculate index from iterator and base pointer.
int* arr = fp_malloc(int, 100); fp_iterate_named(arr, ptr) { size_t idx = fp_iterate_calculate_index(arr, ptr); printf("Index: %zu, Value: %d\n", idx, *ptr); }
- Parameters:
a – Base fat pointer
i – Iterator pointer
- Returns:
Index as size_t
-
fp_iterate_reverse_named(a, iter)#
Iterate over fat pointer in reverse with named iterator.
int* arr = fp_malloc(int, 5); int val = 0; fp_iterate(arr) { *i = val++; } fp_iterate_reverse(arr, item) { printf("%d ", *item); // Prints: 4 3 2 1 0 }
- Parameters:
a – Fat pointer
iter – Iterator variable name
-
fp_iterate_reverse(a)#
Iterate over fat pointer in reverse (iterator named ‘i’)
int* arr = fp_malloc(int, 5); int val = 0; fp_iterate(arr) { *i = val++; } fp_iterate_reverse(arr) { printf("%d ", *i); // Prints: 4 3 2 1 0 }
- Parameters:
a – Fat pointer
-
fp_clone(a)#
Create a shallow copy of a fat pointer.
Creates an independent copy of the data. The new pointer must be freed separately.
int* original = fp_malloc(int, 10); fp_iterate(original) { *i = 42; } int* copy = fp_clone(original); copy[0] = 99; // Doesn't affect original fp_free_and_null(original); fp_free_and_null(copy);
- Parameters:
a – Fat pointer to clone
- Returns:
New heap-allocated fat pointer with copied data
-
fp_contains(a, needle)#
Check if a fat pointer contains a specific value.
Uses memcmp for comparison, so works with any type.
int* numbers = fp_malloc(int, 100); numbers[50] = 42; assert(fp_contains(numbers, 42)); assert(!fp_contains(numbers, 999));
- Parameters:
a – Fat pointer to search
needle – Value to find
- Returns:
true if value found, false otherwise
-
fp_not_found#
Sentinel value indicating element not found in search operations.
This value is returned by fp_find and fp_rfind when the searched element is not present in the fat pointer. It is set to SIZE_MAX, the maximum value of size_t, which cannot be a valid index.
int* arr = fp_malloc(int, 10); size_t idx = fp_find(arr, 42); if(idx == fp_not_found) { printf("Value not found\n"); }
-
fp_find(a, needle)#
Find the index of a specific value in a fat pointer.
Uses memcmp for comparison, so works with any type. Returns fp_not_found (SIZE_MAX) if the element is not present.
int* numbers = fp_malloc(int, 100); for(size_t i = 0; i < fp_length(numbers); i++) { numbers[i] = i * 2; } numbers[50] = 999; size_t idx = fp_find(numbers, 999); if(idx != fp_not_found) { printf("Found at index: %zu\n", idx); // Prints: 50 } else { printf("Not found\n"); } // Not found case assert(fp_find(numbers, 777) == fp_not_found);
- Parameters:
a – Fat pointer to search
needle – Value to find
- Returns:
Index of first occurrence (size_t), or fp_not_found if not found
-
fp_rfind(a, needle)#
Find the index of a specific value searching from the end (reverse find)
Searches backwards through the fat pointer, returning the index of the last occurrence of the value. Uses memcmp for comparison, so works with any type. Returns fp_not_found (SIZE_MAX) if the element is not present.
int* numbers = fp_malloc(int, 100); for(size_t i = 0; i < fp_length(numbers); i++) { numbers[i] = i % 10; // 0,1,2,...,9,0,1,2,... } // Find last occurrence of 5 size_t first = fp_find(numbers, 5); // Returns 5 size_t last = fp_rfind(numbers, 5); // Returns 95 printf("First occurrence: %zu\n", first); printf("Last occurrence: %zu\n", last); // Not found case assert(fp_rfind(numbers, 999) == fp_not_found);
- Parameters:
a – Fat pointer to search
needle – Value to find
- Returns:
Index of last occurrence (size_t), or fp_not_found if not found
-
fp_view(type)#
Define a view type for a specific element type (C version)
fp_view(int) my_view; fp_view(char) str_view;
- Parameters:
type – Element type
-
fp_view_literal(type, data, size)#
Create a view literal (C version)
int buffer[10]; fp_view(int) v = fp_view_literal(int, buffer, 10);
- Parameters:
type – Element type
data – Pointer to data
size – Number of elements
- Returns:
View structure
-
fp_void_view_literal(data, size)#
Create a void view literal.
- Parameters:
data – Pointer to data
size – Number of elements
- Returns:
Untyped view
-
fp_view_from_variable(type, var)#
Create a view from a single variable.
int x = 42; fp_view(int) v = fp_view_from_variable(int, x); assert(fp_view_size(v) == 1); assert(*fp_view_data(int, v) == 42);
- Parameters:
type – Element type
var – Variable to create view of
- Returns:
View with size 1 pointing to the variable
-
fp_variable_to_void_view(type, data)#
Convert a variable to a void view.
double value = 3.14; fp_void_view v = fp_variable_to_void_view(double, value); assert(fp_view_size(v) == sizeof(double));
- Parameters:
type – Type of variable
data – Variable
- Returns:
Void view of the variable’s memory
-
fp_view_make(type, p, start, length)#
Create a view from a range within a fat pointer.
int* arr = fp_malloc(int, 100); // Create view of elements 10-29 (20 elements) fp_view(int) middle = fp_view_make(int, arr, 10, 20); fp_view_iterate(int, middle) { *i = 999; }
- Parameters:
type – Element type
p – Fat pointer
start – Starting index (inclusive)
length – Number of elements
- Returns:
Typed view of the specified range
-
fp_view_make_full(type, p)#
Create a view of an entire fat pointer.
float* data = fp_malloc(float, 50); fp_view(float) full = fp_view_make_full(float, data); assert(fp_view_size(full) == 50);
- Parameters:
type – Element type
p – Fat pointer
- Returns:
View covering all elements
-
fp_view_make_start_end(type, p, start, end)#
Create a view using start and end indices.
int* arr = fp_malloc(int, 100); // View elements 20-30 (inclusive) fp_view(int) slice = fp_view_make_start_end(int, arr, 20, 30); assert(fp_view_size(slice) == 11);
- Parameters:
type – Element type
p – Fat pointer
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View of the range [start, end]
-
fp_view_length(view)#
Get the number of elements in a view.
- Parameters:
view – View structure
- Returns:
Number of elements
-
fp_view_size(view)#
Alias for fp_view_length.
-
fp_view_data_void(view)#
Get untyped data pointer from view.
- Parameters:
view – View structure
- Returns:
Void pointer to data
-
fp_view_data(type, view)#
Get typed data pointer from view.
fp_view(double) v = ...; double* ptr = fp_view_data(double, v);
- Parameters:
type – Element type
view – View structure
- Returns:
Typed pointer to data
-
fp_view_access(type, view, index)#
Access element in view by index.
Asserts that index is within bounds.
fp_view(int) v = ...; int* elem = fp_view_access(int, v, 5); *elem = 42;
- Parameters:
type – Element type
view – View structure
index – Index to access
- Returns:
Pointer to element at index
-
fp_view_subscript(type, view, index)#
Alias for fp_view_access.
-
fp_view_to_byte_view(type, view)#
Convert a typed view to a byte view.
fp_view(int) int_view = ...; fp_view(uint8_t) bytes = fp_view_to_byte_view(int, int_view); // bytes.size == int_view.size * sizeof(int)
- Parameters:
type – Original element type
view – View to convert
- Returns:
View of bytes (fp_view(uint8_t))
-
fp_view_front(type, view)#
Get pointer to first element in view.
- Parameters:
type – Element type
view – View structure
- Returns:
Pointer to first element
-
fp_view_begin(type, view)#
Alias for fp_view_front.
-
fp_view_back(type, view)#
Get pointer to last element in view.
fp_view(int) v = ...; *fp_view_front(int, v) = 1; *fp_view_back(int, v) = 100;
- Parameters:
type – Element type
view – View structure
- Returns:
Pointer to last element
-
fp_view_end(type, view)#
Get pointer to one past the last element (end iterator)
- Parameters:
type – Element type
view – View structure
- Returns:
Pointer to one past the end
-
fp_view_subview(type, view, start, length)#
Create a subview from an existing view.
fp_view(int) full = fp_view_make_full(int, arr); fp_view(int) first_half = fp_view_subview(int, full, 0, fp_view_size(full) / 2);
- Parameters:
type – Element type
view – Parent view
start – Starting index
length – Number of elements
- Returns:
Subview of the specified range
-
fp_view_subview_start_end(type, view, start, end)#
Create a subview using start and end indices.
- Parameters:
type – Element type
view – Parent view
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Subview of the range [start, end]
-
fp_view_iterate_named(type, view, iter)#
Iterate over view with named iterator.
fp_view(float) v = ...; fp_view_iterate_named(float, v, ptr) { *ptr *= 2.0f; }
- Parameters:
type – Element type
view – View structure
iter – Iterator variable name
-
fp_view_iterate(type, view)#
Iterate over view (iterator named ‘i’)
fp_view(int) v = ...; fp_view_iterate(int, v) { printf("%d ", *i); }
- Parameters:
type – Element type
view – View structure
-
fp_view_iterate_calculate_index(type, view, i)#
Calculate index from iterator and view.
fp_view(int) v = ...; fp_view_iterate_named(int, v, ptr) { size_t idx = fp_view_iterate_calculate_index(int, v, ptr); printf("Index %zu: %d\n", idx, *ptr); }
- Parameters:
type – Element type
view – View structure
i – Iterator pointer
- Returns:
Index as size_t
-
fp_view_make_dynamic(type, view)#
Create a heap-allocated fat pointer from a view.
This creates an owning copy of the view’s data.
int buffer[100]; fp_view(int) v = fp_view_literal(int, buffer, 100); // Create owning copy int* owned = fp_view_make_dynamic(int, v); // Can modify independently owned[0] = 999; fp_free_and_null(owned);
- Parameters:
type – Element type
view – View to copy
- Returns:
New heap-allocated fat pointer (must be freed with e.g. fp_free)
-
struct __fp_view#
- #include <pointer.h>
View structure for non-owning references to memory regions (C version)
In C, all views are untyped. Use casting to access typed data.
Dynamic Arrays (C API)#
-
static inline constexpr uint64_t fp_upper_power_of_two(uint64_t v) noexcept#
Calculate next power of two greater than or equal to v.
Used internally for capacity growth. Ensures efficient memory usage with power-of-two allocations.
assert(fp_upper_power_of_two(5) == 8); assert(fp_upper_power_of_two(16) == 16); assert(fp_upper_power_of_two(100) == 128);
- Parameters:
v – Input value
- Returns:
Next power of two >= v
-
struct __FatDynamicArrayHeader *__fpda_header_null_ref() noexcept#
Get reference to null dynamic array header.
- Returns:
Pointer to static null header
-
static inline struct __FatDynamicArrayHeader *__fpda_header(const void *da) noexcept#
Get dynamic array header from data pointer.
- Parameters:
da – Dynamic array pointer
- Returns:
Pointer to header (or null ref if da is NULL)
-
void *__fpda_malloc(size_t _size) noexcept#
Internal allocation function for dynamic arrays.
- Parameters:
_size – Size in bytes to allocate
- Returns:
Pointer to allocated data
-
static inline bool is_fpda(const void *da) noexcept#
Check if pointer is a dynamic array.
fp_dynarray(int) arr = NULL; assert(!is_fpda(arr)); // NULL is not a dynamic array fpda_push_back(arr, 42); assert(is_fpda(arr)); // Now it is fpda_free_and_null(arr);
- Parameters:
da – Pointer to check
- Returns:
true if da is a valid dynamic array
-
void fpda_free(void *da) noexcept#
Free a dynamic array.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 10); fpda_free(arr); // arr is now invalid - do not use
- Parameters:
da – Dynamic array to free
-
static inline size_t fpda_capacity(const void *da) noexcept#
Get allocated capacity of dynamic array.
fp_dynarray(int) arr = NULL; fpda_reserve(arr, 50); assert(fpda_capacity(arr) == 50); assert(fpda_size(arr) == 0); // Add 30 elements - no reallocation for(int i = 0; i < 30; i++) fpda_push_back(arr, i); assert(fpda_capacity(arr) == 50); // Still has room fpda_free_and_null(arr);
- Parameters:
da – Dynamic array
- Returns:
Number of elements that can be stored without reallocation
-
static inline void *__fpda_maybe_grow(void **da, size_t type_size, size_t new_size, bool update_utilized, bool exact_sizing) noexcept#
Internal function to grow dynamic array if needed.
-
static inline void *__fpda_maybe_grow_insert(void **da, size_t type_size, size_t new_index, size_t new_size, bool exact_sizing) noexcept#
Internal function for insert with growth.
-
static inline void *__fpda_delete(void **da, size_t type_size, size_t start, size_t count, bool make_size_match_capacity) noexcept#
Internal function for deletion.
-
static inline void __fpda_swap_range(void *da, size_t type_size, size_t range1_start, size_t range2_start, size_t count, bool bidirectional) noexcept#
Internal function for swapping ranges.
-
static inline void *__fpda_pop_front(void *_da, size_t type_size) noexcept#
Internal function for deleting the first element.
-
static inline void __fpda_clone_to(void **dest, const void *src, size_t type_size, bool shrink_to_fit) noexcept#
Internal function for cloning to destination.
-
static inline void *__fpda_clone(const void *src, size_t type_size) noexcept#
Internal function for cloning.
-
static inline void *__fpda_concatenate_view_in_place(void **dest, const fp_void_view src, size_t type_size) noexcept#
Internal function for concatenating view in place.
-
fp_dynarray(type)#
Define a dynamic array type.
Creates a typed dynamic array pointer. The array starts as NULL and grows automatically as elements are added.
fp_dynarray(int) integers = NULL; fp_dynarray(float) floats = NULL; fp_dynarray(MyStruct) structs = NULL;
- Parameters:
type – Element type
-
FPDA_DEFAULT_SIZE_BYTES#
Default initial allocation size in bytes (defaults to 16)
When a dynamic array is first used, it allocates at least this many bytes. Can be overridden by defining before including this header.
#define FPDA_DEFAULT_SIZE_BYTES 64 #include "dynarray.h"
-
FPDA_HEADER_SIZE#
Size of dynamic array header in bytes.
-
fpda_malloc(type, _size)#
Allocate a dynamic array with initial capacity.
// Allocate with capacity for 100 integers fp_dynarray(int) arr = fpda_malloc(int, 100); assert(fpda_capacity(arr) == 100); assert(fpda_size(arr) == 0); // Size is 0 until elements added fpda_free_and_null(arr);
- Parameters:
type – Element type
_size – Initial capacity in elements
- Returns:
Dynamic array with specified capacity and size
-
fpda_free_and_null(da)#
Free a dynamic array and set pointer to NULL.
Safer than fpda_free() as it prevents use-after-free.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 42); fpda_free_and_null(arr); assert(arr == NULL);
- Parameters:
da – Dynamic array to free
-
fpda_length#
Get number of elements in dynamic array.
Alias for fp_length. Returns the count of elements currently in use, not the capacity.
fp_dynarray(int) arr = NULL; fpda_reserve(arr, 100); fpda_push_back(arr, 1); fpda_push_back(arr, 2); assert(fpda_length(arr) == 2); // Elements in use assert(fpda_capacity(arr) == 100); // Allocated capacity
-
fpda_size#
Alias for fpda_length.
-
fpda_empty#
Check if dynamic array is empty.
fp_dynarray(int) arr = NULL; assert(fpda_empty(arr)); fpda_push_back(arr, 42); assert(!fpda_empty(arr)); fpda_free_and_null(arr);
-
fpda_front(a)#
Get pointer to first element.
-
fpda_begin(a)#
Get iterator to beginning (alias for fpda_front)
-
fpda_back(a)#
Get pointer to last element.
-
fpda_end(a)#
Get iterator to one past end.
-
fpda_iterate_named#
Iterate over dynamic array with named iterator.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 10; i++) fpda_push_back(arr, i); fpda_iterate_named(arr, ptr) *ptr *= 2; fpda_free_and_null(arr);
-
fpda_iterate#
Iterate over dynamic array (iterator named ‘i’)
-
fpda_iterate_calculate_index#
Calculate index from iterator.
-
fpda_reserve(a, _size)#
Reserve capacity for at least _size elements.
Ensures the array can hold at least _size elements without reallocation. Does not change the size, only the capacity.
fp_dynarray(int) arr = NULL; // Reserve space for 1000 elements fpda_reserve(arr, 1000); // Add elements without reallocation for(int i = 0; i < 1000; i++) fpda_push_back(arr, i); // No reallocations fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_size – Minimum capacity to reserve
-
fpda_reserve_void_pointer(a, type_size, _size)#
Reserve capacity (void pointer version)
- Parameters:
a – Dynamic array (void*)
type_size – Size of each element
_size – Minimum capacity to reserve
-
fpda_grow_to_size(a, _size)#
Grow array to exact size.
fp_dynarray(int) arr = NULL; fpda_grow_to_size(arr, 50); assert(fpda_size(arr) == 50); assert(fpda_capacity(arr) >= 50); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_size – New size (updates both size and ensures capacity)
-
fpda_grow(a, _to_add)#
Grow array by adding elements.
Increases size by _to_add. New elements are uninitialized.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 1); fpda_push_back(arr, 2); fpda_grow(arr, 3); // Add 3 more elements assert(fpda_size(arr) == 5); // Initialize new elements arr[2] = 3; arr[3] = 4; arr[4] = 5; fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_to_add – Number of elements to add
-
fpda_push_back(a, _value)#
Add element to end of array.
Automatically grows array if needed. Amortized O(1) operation.
fp_dynarray(int) numbers = NULL; for(int i = 0; i < 100; i++) fpda_push_back(numbers, i * i); assert(fpda_size(numbers) == 100); assert(numbers[50] == 2500); fpda_free(numbers);
- Parameters:
a – Dynamic array
_value – Value to add
-
fpda_grow_and_initialize(a, _to_add, _value)#
Grow array and initialize new elements.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 1); fpda_push_back(arr, 2); // Add 5 more elements, all initialized to 99 fpda_grow_and_initialize(arr, 5, 99); assert(fpda_size(arr) == 7); assert(arr[2] == 99); assert(arr[6] == 99); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_to_add – Number of elements to add
_value – Value to initialize new elements with
-
fpda_grow_to_size_and_initialize(a, _size, _value)#
Grow to size and initialize new elements.
fp_dynarray(float) data = NULL; fpda_grow_to_size_and_initialize(data, 100, 3.14f); assert(fpda_size(data) == 100); for(size_t i = 0; i < fpda_size(data); i++) assert(data[i] == 3.14f); fpda_free_and_null(data);
- Parameters:
a – Dynamic array
_size – Target size
_value – Value to initialize new elements with
-
fpda_pop_back_n(a, _count)#
Remove last n elements.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 10; i++) fpda_push_back(arr, i); fpda_pop_back_n(arr, 3); // Remove last 3 elements assert(fpda_size(arr) == 7); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_count – Number of elements to remove
- Returns:
Pointer to first removed element (the element after the new last element/now invalid)
-
fpda_pop_back(a)#
Remove last element.
fp_dynarray(int) stack = NULL; fpda_push_back(stack, 10); fpda_push_back(stack, 20); fpda_push_back(stack, 30); fpda_pop_back(stack); assert(fpda_size(stack) == 2); assert(stack[fpda_size(stack) - 1] == 20); fpda_free_and_null(stack);
- Parameters:
a – Dynamic array
- Returns:
Pointer to removed element (now invalid)
-
fpda_pop_back_to_size(a, size)#
Pop elements until size reaches target.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 100; i++) fpda_push_back(arr, i); fpda_pop_back_to_size(arr, 50); assert(fpda_size(arr) == 50); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
size – Target size
- Returns:
Pointer to first removed element (the element after the new last element/now invalid)
-
fpda_insert(a, _pos, _val)#
Insert element at position.
Elements after _pos are shifted right. O(n) operation.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 1); fpda_push_back(arr, 2); fpda_push_back(arr, 4); fpda_push_back(arr, 5); // Insert 3 at index 2 fpda_insert(arr, 2, 3); // arr is now: [1, 2, 3, 4, 5] assert(fpda_size(arr) == 5); assert(arr[2] == 3); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos – Position to insert at
_val – Value to insert
-
fpda_push_front(a, _val)#
Insert element at front.
fp_dynarray(int) deque = NULL; fpda_push_front(deque, 3); fpda_push_front(deque, 2); fpda_push_front(deque, 1); // deque is now: [1, 2, 3] assert(deque[0] == 1); fpda_free_and_null(deque);
- Parameters:
a – Dynamic array
_val – Value to insert
-
fpda_insert_uninitialized(a, _pos, _count)#
Insert uninitialized elements.
Useful for bulk insertion where you’ll initialize elements manually.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 1); fpda_push_back(arr, 5); // Insert 3 uninitialized elements at position 1 int* new_elems = fpda_insert_uninitialized(arr, 1, 3); // TODO: Would this be 1, 3 or 0, 3? new_elems[0] = 2; new_elems[1] = 3; new_elems[2] = 4; // arr is now: [1, 2, 3, 4, 5] fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos – Position to insert at
_count – Number of elements to insert
- Returns:
Pointer to first new uninitialized element
-
fpda_delete_range(a, _pos, _count)#
Delete range of elements.
Removes elements and shifts remaining elements left. Does not reduce capacity. O(n) operation.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 10; i++) fpda_push_back(arr, i); // arr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] fpda_delete_range(arr, 3, 4); // arr: [0, 1, 2, 7, 8, 9] assert(fpda_size(arr) == 6); assert(arr[3] == 7); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos – Starting position
_count – Number of elements to delete
- Returns:
Modified a.
-
fpda_delete(a, _pos)#
Delete single element.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 5; i++) fpda_push_back(arr, i * 10); // arr: [0, 10, 20, 30, 40] fpda_delete(arr, 2); // arr: [0, 10, 30, 40] assert(fpda_size(arr) == 4); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos – Position of element to delete
- Returns:
Modified a.
-
fpda_delete_start_end(a, _start, _end)#
Delete range using start and end indices.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 10; i++) fpda_push_back(arr, i); // Delete elements 3 through 7 (inclusive) fpda_delete_start_end(arr, 3, 7); // arr: [0, 1, 2, 8, 9] assert(fpda_size(arr) == 5); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_start – Starting index (inclusive)
_end – Ending index (inclusive)
- Returns:
Modified a.
-
fpda_shrink_delete_range(a, _pos, _count)#
Delete range and shrink capacity to match size.
Like fpda_delete_range but also reallocates to free unused capacity.
fp_dynarray(int) arr = NULL; fpda_reserve(arr, 100); for(int i = 0; i < 50; i++) fpda_push_back(arr, i); assert(fpda_capacity(arr) == 100); fpda_shrink_delete_range(arr, 0, 40); // Only 10 elements remain assert(fpda_size(arr) == 10); assert(fpda_capacity(arr) == 10); // Capacity shrunk fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos – Starting position
_count – Number of elements to delete
- Returns:
Modified a.
-
fpda_shrink_delete(a, _pos)#
Delete single element and shrink capacity.
- Parameters:
a – Dynamic array
_pos – Position to delete
- Returns:
Modified a.
-
fpda_shrink_delete_start_end(a, _start, _end)#
Delete range and shrink using start/end indices.
- Parameters:
a – Dynamic array
_start – Starting index (inclusive)
_end – Ending index (inclusive)
- Returns:
Modified a.
-
fpda_resize(a, _size)#
Resize array to new size.
If new size is larger, capacity grows and new elements are uninitialized. If new size is smaller, elements are deleted and capacity shrinks.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 10; i++) fpda_push_back(arr, i); // Grow fpda_resize(arr, 20); assert(fpda_size(arr) == 20); // Shrink fpda_resize(arr, 5); assert(fpda_size(arr) == 5); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_size – New size
-
fpda_shrink_to_fit(a)#
Shrink capacity to match current size.
Frees unused capacity. Useful after removing many elements.
fp_dynarray(int) arr = NULL; fpda_reserve(arr, 1000); for(int i = 0; i < 100; i++) fpda_push_back(arr, i); assert(fpda_capacity(arr) == 1000); assert(fpda_size(arr) == 100); fpda_shrink_to_fit(arr); assert(fpda_capacity(arr) == 100); // Freed 900 elements worth of memory fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
-
fpda_swap_range(a, _start1, _start2, _count)#
Swap two ranges of elements.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 10; i++) fpda_push_back(arr, i); // arr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // Swap [0,1,2] with [7,8,9] fpda_swap_range(arr, 0, 7, 3); // arr: [7, 8, 9, 3, 4, 5, 6, 0, 1, 2] fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_start1 – Start of first range
_start2 – Start of second range
_count – Number of elements to swap
-
fpda_swap(a, _pos1, _pos2)#
Swap two elements.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 10); fpda_push_back(arr, 20); fpda_push_back(arr, 30); fpda_swap(arr, 0, 2); // arr: [30, 20, 10] assert(arr[0] == 30); assert(arr[2] == 10); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos1 – First position
_pos2 – Second position
-
fpda_swap_delete_range(a, _pos, _count)#
Swap range to end and delete.
Efficiently deletes by swapping with end elements instead of shifting. O(1) operation but doesn’t preserve order.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 10; i++) fpda_push_back(arr, i); // arr: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] // Delete elements at positions 2-3 by swapping with end fpda_swap_delete_range(arr, 2, 2); // arr: [0, 1, 8, 9, 4, 5, 6, 7] assert(fpda_size(arr) == 8); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos – Starting position
_count – Number of elements
-
fpda_swap_delete(a, _pos)#
Swap element to end and delete.
Fast O(1) deletion that doesn’t preserve order.
fp_dynarray(int) arr = NULL; for(int i = 0; i < 5; i++) fpda_push_back(arr, i * 10); // arr: [0, 10, 20, 30, 40] fpda_swap_delete(arr, 1); // arr: [0, 40, 20, 30] (40 moved to position 1) assert(fpda_size(arr) == 4); assert(arr[1] == 40); fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
_pos – Position to delete
-
fpda_swap_delete_start_end(a, _start, _end)#
Swap range to end and delete using start/end indices.
- Parameters:
a – Dynamic array
_start – Starting index (inclusive)
_end – Ending index (inclusive)
-
fpda_pop_front(a)#
Remove and return first element.
Shifts all elements left. O(n) operation.
fp_dynarray(int) queue = NULL; fpda_push_back(queue, 1); fpda_push_back(queue, 2); fpda_push_back(queue, 3); fpda_pop_front(queue); // queue: [2, 3] assert(fpda_size(queue) == 2); assert(queue[0] == 2); fpda_free_and_null(queue);
Note
The final element is just shifted to the end, so the pointer to it is valid as long as the array is.
- Parameters:
a – Dynamic array
- Returns:
Pointer to removed element (now at end of array)
-
fpda_clone_to(dest, src)#
Clone array to destination.
Copies all elements and capacity from src to dest.
fp_dynarray(int) original = NULL; for(int i = 0; i < 10; i++) fpda_push_back(original, i); fp_dynarray(int) copy = NULL; fpda_clone_to(copy, original); assert(fpda_size(copy) == 10); assert(copy[5] == 5); fpda_free_and_null(original); fpda_free_and_null(copy);
- Parameters:
dest – Destination array
src – Source array
-
fpda_assign(dest, src)#
Alias for fpda_clone_to.
-
fpda_clone_to_shrink(dest, src)#
Clone array to destination with minimal capacity.
Like fpda_clone_to but capacity matches size exactly.
- Parameters:
dest – Destination array
src – Source array
-
fpda_clone(src)#
Create a clone of dynamic array.
fp_dynarray(int) original = NULL; for(int i = 0; i < 5; i++) fpda_push_back(original, i * i); fp_dynarray(int) clone = fpda_clone(original); clone[0] = 999; // Doesn't affect original assert(original[0] == 0); assert(clone[0] == 999); fpda_free_and_null(original); fpda_free_and_null(clone);
- Parameters:
src – Source array
- Returns:
New array with copied data
-
fpda_copy(src)#
Alias for fpda_clone.
-
fpda_clear(a)#
Clear all elements (keeps capacity)
Sets size to 0 but doesn’t free memory.
fp_dynarray(int) arr = NULL; fpda_reserve(arr, 100); for(int i = 0; i < 50; i++) fpda_push_back(arr, i); assert(fpda_size(arr) == 50); assert(fpda_capacity(arr) == 100); fpda_clear(arr); assert(fpda_size(arr) == 0); assert(fpda_capacity(arr) == 100); // Capacity unchanged fpda_free_and_null(arr);
- Parameters:
a – Dynamic array
-
fpda_concatenate_view_in_place(dest, src)#
Concatenate view to array in place.
fp_dynarray(int) arr = NULL; fpda_push_back(arr, 1); fpda_push_back(arr, 2); int more[] = {3, 4, 5}; fp_view(int) v = fp_view_literal(int, more, 3); fpda_concatenate_view_in_place(arr, v); // arr: [1, 2, 3, 4, 5] assert(fpda_size(arr) == 5); fpda_free_and_null(arr);
- Parameters:
dest – Destination array (modified)
src – Source view
-
fpda_concatenate_view(dest, src)#
Concatenate view to array (returns new array)
fp_dynarray(int) arr1 = NULL; fpda_push_back(arr1, 1); fpda_push_back(arr1, 2); int extra[] = {3, 4}; fp_view(int) v = fp_view_literal(int, extra, 2); fp_dynarray(int) result = fpda_concatenate_view(arr1, v); // result: [1, 2, 3, 4] // arr1: [1, 2] (unchanged) fpda_free_and_null(arr1); fpda_free_and_null(result);
- Parameters:
dest – Source array (not modified)
src – View to append
- Returns:
New array with concatenated data
-
fpda_concatenate_in_place(dest, src)#
Concatenate two arrays in place.
fp_dynarray(int) arr1 = NULL; fp_dynarray(int) arr2 = NULL; fpda_push_back(arr1, 1); fpda_push_back(arr1, 2); fpda_push_back(arr2, 3); fpda_push_back(arr2, 4); fpda_concatenate_in_place(arr1, arr2); // arr1: [1, 2, 3, 4] // arr2: [3, 4] (unchanged) fpda_free_and_null(arr1); fpda_free_and_null(arr2);
- Parameters:
dest – Destination array (modified)
src – Source array
-
fpda_concatenate(dest, src)#
Concatenate two arrays (returns new array)
fp_dynarray(int) arr1 = NULL; fp_dynarray(int) arr2 = NULL; fpda_push_back(arr1, 1); fpda_push_back(arr1, 2); fpda_push_back(arr2, 3); fpda_push_back(arr2, 4); fp_dynarray(int) combined = fpda_concatenate(arr1, arr2); // combined: [1, 2, 3, 4] // arr1 and arr2 unchanged assert(fpda_size(combined) == 4); fpda_free_and_null(arr1); fpda_free_and_null(arr2); fpda_free_and_null(combined);
- Parameters:
dest – First array (not modified)
src – Second array (not modified)
- Returns:
New array with concatenated data
-
struct __FatDynamicArrayHeader#
- #include <dynarray.h>
Header structure for dynamic arrays.
Extends the fat pointer header with capacity information. Layout: [__FatDynamicArrayHeader][__FatPointerHeader][user data…][null terminator] ^ returned pointer
Generated Documentation (C++ API)#
-
constexpr size_t fp::not_found = SIZE_MAX#
Sentinel value indicating element not found in search operations.
This value is returned by fp_find and fp_rfind when the searched element is not present in the fat pointer. It is set to SIZE_MAX, the maximum value of size_t, which cannot be a valid index.
fp::auto_free arr = fp::malloc(int, 10); size_t idx = arr.find(42); if(idx == fp::not_found) printf("Value not found\n");
-
template<typename T>
inline void fp::__destroy(view<T> view)# Internal function used to free all elements in a view.
-
template<typename T>
inline pointer<T> fp::malloc(size_t count = 1) Allocate a fat pointer on the heap.
// Allocate single element fp::pointer<int> single = fp::malloc<int>(); *single = 42; // Allocate array fp::pointer<float> arr = fp::malloc<float>(100); for(size_t i = 0; i < arr.size(); i++) arr[i] = i * 1.5f; // Allocate for complex types struct Point { int x, y; }; fp::pointer<Point> points = fp::malloc<Point>(50); points[0] = {10, 20}; single.free(); arr.free(); points.free();
See also
fp_alloc() for a version that dynamically stack allocates.
RAII Allocation#
// Use with RAII for automatic cleanup fp::raii::pointer<int> auto_arr = fp::malloc<int>(100); fp::auto_free same_as_above = fp::malloc<int>(100); // No need to call free() - automatic cleanup
- Template Parameters:
T – Element type
- Parameters:
count – Number of elements to allocate (default: 1)
- Returns:
New fat pointer with allocated memory
-
template<typename T>
inline pointer<T> fp::realloc(pointer<T> ptr, size_t new_count)# Reallocate a fat pointer with a new size.
This is equivalent to calling ptr.realloc(new_count).
fp::pointer<int> arr = fp::malloc<int>(10); arr = fp::realloc(arr, 20); assert(arr.size() == 20); arr.free();
- Template Parameters:
T – Element type
- Parameters:
ptr – Pointer to reallocate
new_count – New number of elements
- Returns:
Reallocated pointer (may have different address)
-
template<typename T>
inline void fp::free(pointer<T> &ptr, bool nullify = true)# Free a fat pointer (functional style)
This is a functional-style interface to free memory, equivalent to calling ptr.free(). The pointer is passed by reference and will be nullified by default, preventing use-after-free bugs.
This function provides a familiar interface for developers used to C-style free(), while maintaining the safety guarantees of the C++ wrapper.
// Functional style (like C's free) fp::pointer<int> arr = fp::malloc<int>(50); fp::free(arr); // Equivalent to arr.free() assert(!arr); // Pointer is null // Member function style fp::pointer<int> arr2 = fp::malloc<int>(50); arr2.free(); // Same effect
See also
fp::pointer::free() for member function version
See also
fp::raii::pointer for automatic memory management
- Template Parameters:
T – Element type
- Parameters:
ptr – Pointer to free (passed by reference)
nullify – If true, sets the pointer to nullptr after freeing (default: true)
-
template<typename T>
inline void fp::free_and_null(pointer<T> &ptr)# Free a fat pointer and explicitly set it to null.
- Deprecated:
This function is redundant since fp::free() nullifies by default. Use fp::free(ptr) instead, which has the same behavior.
This function frees the allocated memory and sets the pointer to nullptr. It exists for clarity and backwards compatibility, but is functionally identical to calling fp::free(ptr) with default parameters.
The explicit name makes the nullification behavior clear in code, which can improve readability in some contexts.
fp::pointer<int> arr = fp::malloc<int>(50); arr.fill(42); // These are exactly equivalent: fp::free_and_null(arr); // Explicit name fp::free(arr); // Default behavior (preferred) // Both result in: assert(arr.data() == nullptr); assert(!arr);
See also
fp::free() for the preferred interface
See also
fp::pointer::free() for member function version
See also
fp::raii::pointer for automatic memory management
- Template Parameters:
T – Element type
- Parameters:
ptr – Pointer to free (passed by reference, will be nullified)
-
template<typename T>
inline void fp::free(const pointer<T> &ptr)# Free a fat pointer (const version)
This is a functional-style interface for freeing through const references. This overload does not nullify the pointer since the reference is const.
This overload exists primarily for compatibility with const contexts and generic code that may receive const references. However, its use is discouraged as it leaves the pointer in a dangerous dangling state.
// Dangerous usage (avoid if possible) void unsafe_cleanup(const fp::pointer<int>& arr) { // Process data for(size_t i = 0; i < arr.size(); i++) { process(arr[i]); } fp::free(arr); // Calls const version - doesn't nullify // arr is now dangling but we can't nullify it } fp::pointer<int> data = fp::malloc<int>(10); unsafe_cleanup(data); // data still appears non-null but is invalid - DANGEROUS!Why to Avoid#
void demonstrate_danger() { fp::pointer<int> arr = fp::malloc<int>(5); arr.fill(42); const fp::pointer<int>& const_ref = arr; fp::free(const_ref); // Const version called // arr is now invalid but still appears non-null if(arr) { // Returns true - MISLEADING! // arr[0] = 99; // UNDEFINED BEHAVIOR - use after free! } }See also
free(pointer<T>&, bool) for the safer, non-const version
See also
fp::pointer::free() for member function version
See also
fp::raii::pointer for automatic, safe memory management
Warning
This version does not nullify the pointer, making it dangerous. The pointer becomes invalid but cannot be modified through the const reference.
Warning
Strongly prefer the non-const version or RAII pointers.
- Template Parameters:
T – Element type
- Parameters:
ptr – Const pointer to free
-
static inline size_t fp::encode_utf8(uint32_t codepoint, char out[4])#
-
template<typename T, size_t N>
struct array : public fp::pointer_crtp<T, array<T, N>># - #include <pointer.hpp>
Fixed-size array (fp::array) with fat pointer interface.
This class provides a stack-allocated array with the same interface as fat pointers. It’s useful when you know the size at compile time and want to avoid heap allocation. The array is automatically destroyed when it goes out of scope.
// Create fixed-size array fp::array<int, 10> arr; // Initialize with initializer list fp::array<float, 5> values = {1.0f, 2.0f, 3.0f, 4.0f, 5.0f}; // Access elements arr[0] = 42; arr.fill(99); // Use like any other fat pointer for(int& val : arr) val *= 2; // Create views auto v = arr.view(2, 5); // Check properties assert(arr.size() == 10); assert(arr.stack_allocated()); assert(!arr.heap_allocated()); // No need to free - automatically destroyed
Compile-Time Usage#
constexpr fp::array<int, 5> get_primes() { fp::array<int, 5> primes; primes[0] = 2; primes[1] = 3; primes[2] = 5; primes[3] = 7; primes[4] = 11; return primes; } constexpr auto primes = get_primes(); static_assert(primes[2] == 5);
Using as Function Parameters#
template<size_t N> void process(fp::array<int, N>& arr) { for(size_t i = 0; i < arr.size(); i++) arr[i] *= 2; } fp::array<int, 10> data; data.fill(5); process(data); assert(data[0] == 10);
STL Compatibility#
fp::array<int, 20> numbers; // Use with STL algorithms std::iota(numbers.begin(), numbers.end(), 1); std::reverse(numbers.begin(), numbers.end()); // Convert to span std::span<int> s = numbers.span();
Aggregate Operations#
fp::array<double, 100> data; data.fill(1.0); // Use front() and back() data.front() = 0.0; data.back() = 100.0; // Create subviews auto first_quarter = data.view(0, 25); auto last_quarter = data.view(75, 25); first_quarter.fill(2.0); last_quarter.fill(3.0);
- Template Parameters:
T – Element type
N – Number of elements (compile-time constant)
Unnamed Group
Unnamed Group
Unnamed Group
-
inline size_t length() const#
Get the number of elements.
fp::auto_free arr = fp::malloc<int>(50); std::cout << "Array has " << arr.length() << " elements\n"; // Use in loops for(size_t i = 0; i < arr.length(); i++) arr[i] = i;
Unnamed Group
-
inline T *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(50); // Manual iteration for(int* it = arr.begin(); it != arr.end(); ++it) *it = 42; // Use with STL algorithms std::iota(arr.begin(), arr.end(), 0); std::sort(arr.begin(), arr.end()); std::reverse(arr.begin(), arr.end()); // Distance size_t count = std::distance(arr.begin(), arr.end()); assert(count == arr.size());
Unnamed Group
-
inline T *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); arr.fill(1); // Range-based for loop for(int& val : arr) val *= 2; // Find operations auto it = std::find(arr.begin(), arr.end(), 42); if(it != arr.end()) std::cout << "Found at index: " << (it - arr.begin()) << "\n"; // Accumulate int sum = std::accumulate(arr.begin(), arr.end(), 0);
Unnamed Group
Unnamed Group
Unnamed Group
Public Functions
-
constexpr array() = default#
Default constructor - elements are default-initialized.
-
inline constexpr array(std::initializer_list<T> init)#
Construct from initializer list.
fp::array<int, 5> arr = {1, 2, 3, 4, 5}; fp::array<std::string, 3> names = {"Alice", "Bob", "Charlie"}; // This would fail assertion: // fp::array<int, 5> bad = {1, 2, 3}; // Only 3 elements!
- Parameters:
init – Initializer list of values (must have exactly N elements)
-
inline operator array<std::add_const_t<T>, N>() const#
Implicit conversion to const array.
Allows passing non-const arrays to functions expecting const arrays.
void print_array(const fp::array<const int, 5>& arr) { for(const auto& val : arr) { std::cout << val << " "; } } fp::array<int, 5> data = {1, 2, 3, 4, 5}; print_array(data); // Implicit conversion
-
inline T *release()#
Release ownership of the pointer.
After calling release(), the pointer object no longer owns the memory. The caller becomes responsible for freeing it.
fp::auto_free arr = fp::malloc<int>(10).fill(42); // Transfer ownership int* raw = arr.release(); assert(arr.data() == nullptr); // Now we must manually free fp_free(raw);
- Returns:
The raw pointer (ownership transferred to caller)
-
inline bool is_fp() const#
Check if this is a valid fat pointer.
int regular[10]; fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; assert(arr.is_fp()); assert(!null_ptr.is_fp());
-
inline bool stack_allocated() const#
Check if this is stack-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(stack_arr.stack_allocated()); assert(!heap_arr.stack_allocated());
-
inline bool heap_allocated() const#
Check if this is heap-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(!stack_arr.heap_allocated()); assert(heap_arr.heap_allocated());
-
inline operator bool() const#
Check if pointer is non-null.
fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; if(arr) std::cout << "Array is valid\n"; if(!null_ptr) std::cout << "Null pointer\n"; // Safe access pattern if(arr && arr.size() > 0) arr[0] = 42;
-
inline bool empty() const#
Check if the pointer is empty.
fp::auto_free arr1 = fp::malloc<int>(10); fp::auto_free arr2 = fp::malloc<int>(0); assert(!arr1.empty()); assert(arr2.empty()); // Safe access pattern if(!arr1.empty()) arr1[0] = 42;
-
inline view_t view(size_t start, size_t length)#
Create a view of a portion of this pointer.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20-39 auto v = arr.view(20, 20); v.fill(999); assert(arr[20] == 999); assert(arr[39] == 999); assert(arr[19] != 999); // Outside view // Process data in chunks for(size_t i = 0; i < arr.size(); i += 10) { auto chunk = arr.view(i, 10); process_chunk(chunk); }
- Parameters:
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
inline view_t view_full()#
Create a view of the entire pointer.
fp::auto_free arr = fp::malloc<int>(50); // Create full view auto v = arr.view_full(); assert(v.size() == arr.size()); // Useful for passing to functions expecting views void process_view(fp::view<int> data) { for(auto& val : data) val *= 2; } process_view(arr.view_full());
- Returns:
View over all elements
-
inline view_t full_view()#
Alias for view_full.
fp::auto_free arr = fp::malloc<int>(50); // Both are equivalent auto v1 = arr.view_full(); auto v2 = arr.full_view(); assert(v1.size() == v2.size());
-
inline view_t view_start_end(size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10 through 20 (inclusive) - 11 elements auto v = arr.view_start_end(10, 20); assert(v.size() == 11); // Process quarters size_t quarter = arr.size() / 4; auto q1 = arr.view_start_end(0, quarter - 1); auto q2 = arr.view_start_end(quarter, 2 * quarter - 1); auto q3 = arr.view_start_end(2 * quarter, 3 * quarter - 1); auto q4 = arr.view_start_end(3 * quarter, arr.size() - 1);
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
inline const view_t view_start_end(size_t start, size_t end) const#
Create a view with start/end indices (const version)
-
inline T &front()#
Get reference to first element.
fp::auto_free arr = fp::malloc<int>(10).fill(5); arr.front() = 100; assert(arr[0] == 100); // Useful for algorithms int first = arr.front(); int last = arr.back();
-
inline T &back()#
Get reference to last element.
fp::auto_free arr = fp::malloc<int>(10); arr.fill(5); arr.back() = 999; assert(arr[arr.size() - 1] == 999); // Access both ends if(!arr.empty()) { arr.front() = 1; arr.back() = 100; }
-
inline array<T, N> &fill(const T &value = {})#
Fill all elements with a value.
fp::auto_free arr = fp::malloc<int>(100); // Fill with specific value arr.fill(42); assert(arr[0] == 42); assert(arr[99] == 42); // Fill with default value (0 for int) arr.fill(); assert(arr[0] == 0); // Method chaining fp::auto_free data = fp::malloc<float>(50).fill(3.14f); // Fill with custom types struct Point { int x = 0, y = 0; }; fp::auto_free points = fp::malloc<Point>(10); points.fill(Point{5, 10});
- Parameters:
value – Value to fill with (default-constructed if not provided)
- Returns:
Reference to derived class for chaining
Public Members
-
__FatPointerHeaderTruncated __header = __default_header#
Fat pointer header with metadata.
Public Static Attributes
- static constexpr __FatPointerHeaderTruncated __default_header = {.magic =FP_STACK_MAGIC_NUMBER,.size =N,}
Default header for stack-allocated arrays.
-
template<typename T>
struct auto_free : public T# - #include <pointer.hpp>
RAII wrapper that automatically frees the wrapped pointer on destruction.
This class wraps any type with a .free method a bool convertible raw field and construction from a (possibly null) pointer and ensures automatic cleanup when the object goes out of scope. It implements proper move semantics and copy on assignment.
void process() { auto_free<fp::pointer<int>> data(fp::malloc<int>(100)); data[0] = 42; // Automatically freed when data goes out of scope } // Move semantics work correctly auto_free<fp::pointer<int>> create() { auto_free<fp::pointer<int>> temp(fp::malloc<int>(10)); return temp; // Moved, not freed }
- Template Parameters:
T – Wrapped pointer type (e.g., fp::pointer<int>)
Public Functions
-
inline constexpr auto_free()#
Default constructor - initializes to nullptr.
-
inline constexpr auto_free(std::nullptr_t)#
Construct from nullptr.
-
inline constexpr auto_free(const auto_free &o)#
Copy constructor from another auto_free - clones the data.
-
inline constexpr auto_free(auto_free &&o)#
Move constructor from another auto_free - transfers ownership.
-
inline constexpr auto_free &operator=(const T &o)#
Copy assignment - clones the data, frees old data.
-
inline constexpr auto_free &operator=(T &&o)#
Move assignment from T - transfers ownership, frees old data.
-
inline constexpr auto_free &operator=(const auto_free &o)#
Copy assignment from auto_free - clones the data, frees old data.
-
inline constexpr auto_free &operator=(auto_free &&o)#
Move assignment from auto_free - transfers ownership, frees old data.
-
inline ~auto_free()#
Destructor - automatically frees the pointer if non-null.
-
template<>
struct auto_free<string> : public fp::string# Unnamed Group
-
inline T *data()#
Get raw pointer to data.
fp::auto_free arr = fp::malloc<int>(10); int* raw = arr.data(); // Use with C functions memset(raw, 0, arr.size() * sizeof(int)); // Pass to C APIs qsort(arr.data(), arr.size(), sizeof(int), compare_func);
Unnamed Group
-
inline T &operator*()#
Dereference operator.
- Returns:
Reference to the pointed-to value
Unnamed Group
-
inline T &operator*()
Dereference operator - access first element.
- Returns:
Reference to first element
Unnamed Group
-
inline T *operator->()#
Arrow operator for member access.
- Returns:
Raw pointer
Unnamed Group
-
inline T *operator->()
Arrow operator - access first element’s members.
- Returns:
Pointer to first element
Unnamed Group
-
inline explicit operator T*()#
Explicit conversion to raw pointer.
Requires explicit cast to prevent accidental implicit conversions.
fp::auto_free arr = fp::malloc<int>(10); // Explicit cast required int* ptr = (int*)arr; // Won't compile (good!): // int* ptr2 = arr;
Unnamed Group
-
inline size_t length() const#
Get the number of elements.
fp::auto_free arr = fp::malloc<int>(50); std::cout << "Array has " << arr.length() << " elements\n"; // Use in loops for(size_t i = 0; i < arr.length(); i++) arr[i] = i;
Unnamed Group
-
inline T *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(50); // Manual iteration for(int* it = arr.begin(); it != arr.end(); ++it) *it = 42; // Use with STL algorithms std::iota(arr.begin(), arr.end(), 0); std::sort(arr.begin(), arr.end()); std::reverse(arr.begin(), arr.end()); // Distance size_t count = std::distance(arr.begin(), arr.end()); assert(count == arr.size());
Unnamed Group
-
inline T *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); arr.fill(1); // Range-based for loop for(int& val : arr) val *= 2; // Find operations auto it = std::find(arr.begin(), arr.end(), 42); if(it != arr.end()) std::cout << "Found at index: " << (it - arr.begin()) << "\n"; // Accumulate int sum = std::accumulate(arr.begin(), arr.end(), 0);
Unnamed Group
-
inline T &operator[](size_t i)#
Subscript operator - access element by index.
Note
Bounds checked in debug!
- Parameters:
i – Index
- Returns:
Reference to element at index
Public Types
-
using view_t = fp::view<T>#
View type for this pointer.
Public Functions
-
inline operator dynarray<std::add_const_t<char>>() const#
Implicit conversion to const dynarray.
Allows passing non-const arrays to functions expecting const arrays.
void print_numbers(const fp::dynarray<const int>& arr) { for(auto& n : arr) std::cout << n << " "; } fp::dynarray<int> numbers = {1, 2, 3}; print_numbers(numbers); // Implicit conversion numbers.free();
-
inline operator pointer<std::add_const_t<T>>() const#
Implicit conversion to const pointer.
Allows passing non-const pointers to functions expecting const pointers.
void print_data(fp::pointer<const int> data) { for(size_t i = 0; i < data.size(); i++) { std::cout << data[i] << " "; } } fp::auto_release arr = fp::malloc<int>(5).fill(42); print_data(arr); // Implicit conversion
-
inline void free(bool nullify = true)#
Free the allocated memory.
Releases the memory allocated for this fat pointer. By default, the internal pointer is set to nullptr after freeing to prevent use-after-free bugs.
This is the preferred method for freeing memory as it provides safety by default. The pointer object remains valid but will be null after this call.
fp::pointer<int> arr = fp::malloc<int>(20); // Default: nullifies after free arr.free(); assert(arr.data() == nullptr); // Explicit: don't nullify (use with caution) fp::pointer<int> arr2 = fp::malloc<int>(20); arr2.free(false); // arr2.data() is now a dangling pointer - DANGEROUS! // Better: use default behavior fp::pointer<int> arr3 = fp::malloc<int>(20); arr3.free(true); // Explicit, but default
RAII Dynarray Usage#
// If you don't want to call free() manually, use RAII { fp::raii::pointer<int> auto_arr = fp::malloc<int>(100); // or fp::auto_free auto_arr = ... // Use auto_arr... // Automatically freed when scope exits }
See also
fp::raii::pointer for automatic memory management
Warning
After calling free(), any views or references to the data become invalid.
Warning
Only call free() on heap-allocated pointers, not stack-allocated ones.
- Parameters:
nullify – If true, sets the internal pointer to nullptr after freeing (default: true)
-
inline void free() const#
Free the allocated memory (const version)
This overload is provided for const pointers and does not nullify the internal pointer. Use with extreme caution as the pointer will be left in a dangling state.
This overload exists primarily for compatibility with const contexts, but its use is discouraged. Consider restructuring your code to avoid freeing through const references.
// Dangerous usage (avoid if possible) void unsafe_free(const fp::pointer<int>& arr) { arr.free(); // Calls const version // arr.data() is now dangling but we can't nullify it }
See also
free(bool) for the safer, non-const version
Warning
This version does not nullify the pointer, making it dangerous. Prefer the non-const version whenever possible.
Warning
The pointer becomes invalid but the const object cannot be modified.
-
inline void free(bool nullify = true)
Free the dynamic array.
Calls destructors for non-trivial types before freeing memory.
fp::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); strings.free(); // Destructors called, memory freed, ptr nulled assert(!strings);- Parameters:
nullify – If true, sets pointer to null (default: true)
-
inline void free() const
Free the dynamic array (const version)
Warning
Does not nullify pointer. Prefer non-const version.
-
inline pointer &realloc(size_t new_count)#
Reallocate with a new size.
Existing data is preserved up to the minimum of old and new sizes. The pointer address may change, but the reference is updated automatically.
fp::pointer<int> arr = fp::malloc<int>(10); for(size_t i = 0; i < arr.size(); i++) arr[i] = i; // Expand to 20 elements (first 10 preserved) arr.realloc(20); assert(arr.size() == 20); assert(arr[5] == 5); // Old data still there // Shrink to 5 elements arr.realloc(5); assert(arr.size() == 5); arr.free();
- Parameters:
new_count – New number of elements
- Returns:
Reference to this pointer (may have new address)
-
inline pointer clone() const#
Create a copy of this pointer.
Creates an independent copy of the data. Modifications to the clone do not affect the original.
fp::auto_free original = fp::malloc<int>(5).fill(42); fp::pointer<int> copy = original.clone(); copy[0] = 99; // Doesn't affect original assert(original[0] == 42); assert(copy[0] == 99); copy.free();
- Returns:
New pointer with copied data (must be freed separately)
-
inline Derived clone() const
Create a copy of this array.
fp::raii::dynarray<int> original; original.push_back(1); original.push_back(2); original.push_back(3); fp::raii::dynarray<int> copy = original.clone(); copy[0] = 999; // Doesn't affect original assert(original[0] == 1); assert(copy[0] == 999);
- Returns:
New array with copied data
-
inline T *data()
Get the raw pointer.
-
inline const T *data() const#
Get the raw pointer (const version)
-
inline T *release()#
Release ownership of the pointer.
After calling release(), the pointer object no longer owns the memory. The caller becomes responsible for freeing it.
fp::auto_free arr = fp::malloc<int>(10).fill(42); // Transfer ownership int* raw = arr.release(); assert(arr.data() == nullptr); // Now we must manually free fp_free(raw);
- Returns:
The raw pointer (ownership transferred to caller)
-
inline bool is_fp() const#
Check if this is a valid fat pointer.
int regular[10]; fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; assert(arr.is_fp()); assert(!null_ptr.is_fp());
-
inline bool stack_allocated() const#
Check if this is stack-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(stack_arr.stack_allocated()); assert(!heap_arr.stack_allocated());
-
inline bool heap_allocated() const#
Check if this is heap-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(!stack_arr.heap_allocated()); assert(heap_arr.heap_allocated());
-
inline operator bool() const#
Check if pointer is non-null.
fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; if(arr) std::cout << "Array is valid\n"; if(!null_ptr) std::cout << "Null pointer\n"; // Safe access pattern if(arr && arr.size() > 0) arr[0] = 42;
-
inline bool empty() const#
Check if the pointer is empty.
fp::auto_free arr1 = fp::malloc<int>(10); fp::auto_free arr2 = fp::malloc<int>(0); assert(!arr1.empty()); assert(arr2.empty()); // Safe access pattern if(!arr1.empty()) arr1[0] = 42;
-
inline view_t view(size_t start, size_t length)#
Create a view of a portion of this pointer.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20-39 auto v = arr.view(20, 20); v.fill(999); assert(arr[20] == 999); assert(arr[39] == 999); assert(arr[19] != 999); // Outside view // Process data in chunks for(size_t i = 0; i < arr.size(); i += 10) { auto chunk = arr.view(i, 10); process_chunk(chunk); }
- Parameters:
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
inline view_t view_full()#
Create a view of the entire pointer.
fp::auto_free arr = fp::malloc<int>(50); // Create full view auto v = arr.view_full(); assert(v.size() == arr.size()); // Useful for passing to functions expecting views void process_view(fp::view<int> data) { for(auto& val : data) val *= 2; } process_view(arr.view_full());
- Returns:
View over all elements
-
inline view_t full_view()#
Alias for view_full.
fp::auto_free arr = fp::malloc<int>(50); // Both are equivalent auto v1 = arr.view_full(); auto v2 = arr.full_view(); assert(v1.size() == v2.size());
-
inline view_t view_start_end(size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10 through 20 (inclusive) - 11 elements auto v = arr.view_start_end(10, 20); assert(v.size() == 11); // Process quarters size_t quarter = arr.size() / 4; auto q1 = arr.view_start_end(0, quarter - 1); auto q2 = arr.view_start_end(quarter, 2 * quarter - 1); auto q3 = arr.view_start_end(2 * quarter, 3 * quarter - 1); auto q4 = arr.view_start_end(3 * quarter, arr.size() - 1);
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
inline const view_t view_start_end(size_t start, size_t end) const#
Create a view with start/end indices (const version)
-
inline T &front()#
Get reference to first element.
fp::auto_free arr = fp::malloc<int>(10).fill(5); arr.front() = 100; assert(arr[0] == 100); // Useful for algorithms int first = arr.front(); int last = arr.back();
-
inline T &back()#
Get reference to last element.
fp::auto_free arr = fp::malloc<int>(10); arr.fill(5); arr.back() = 999; assert(arr[arr.size() - 1] == 999); // Access both ends if(!arr.empty()) { arr.front() = 1; arr.back() = 100; }
-
inline pointer<T> &fill(const T &value = {})#
Fill all elements with a value.
fp::auto_free arr = fp::malloc<int>(100); // Fill with specific value arr.fill(42); assert(arr[0] == 42); assert(arr[99] == 42); // Fill with default value (0 for int) arr.fill(); assert(arr[0] == 0); // Method chaining fp::auto_free data = fp::malloc<float>(50).fill(3.14f); // Fill with custom types struct Point { int x = 0, y = 0; }; fp::auto_free points = fp::malloc<Point>(10); points.fill(Point{5, 10});
- Parameters:
value – Value to fill with (default-constructed if not provided)
- Returns:
Reference to derived class for chaining
-
inline bool is_dynarray() const#
Check if this is a valid dynamic array.
fp::raii::dynarray<int> arr; assert(!arr.is_dynarray()); // Empty/null arr.push_back(42); assert(arr.is_dynarray()); // Now valid
- Returns:
true if this is a dynamic array
-
inline size_t capacity() const#
Get allocated capacity.
fp::raii::dynarray<int> arr; arr.reserve(50); assert(arr.capacity() == 50); assert(arr.size() == 0); arr.push_back(1); assert(arr.capacity() == 50); // No reallocation
- Returns:
Number of elements that can be stored without reallocation
-
inline Derived &reserve(size_t size)#
Reserve capacity for at least size elements.
fp::raii::dynarray<int> arr; // Reserve and chain operations arr.reserve(1000) .push_back(42); arr.push_back(99); // No reallocations for next 998 elements
- Parameters:
size – Minimum capacity to reserve
- Returns:
Reference to this array for chaining
-
inline Derived &grow(size_t to_add, const T &value = {})#
Grow array by adding initialized elements.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); // Add 5 elements, all initialized to 99 arr.grow(5, 99); assert(arr.size() == 7); assert(arr[2] == 99);
- Parameters:
to_add – Number of elements to add
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline Derived &grow_uninitialized(size_t to_add)#
Grow array with uninitialized elements.
New elements are uninitialized - you must initialize them before use. Useful for performance when you’ll immediately overwrite values.
fp::raii::dynarray<int> arr; arr.push_back(1); size_t old_size = arr.size(); arr.grow_uninitialized(10); // Initialize new elements for(size_t i = old_size; i < arr.size(); i++) arr[i] = i * 10;
- Parameters:
to_add – Number of elements to add
- Returns:
Reference to this array for chaining
-
inline Derived &grow_to_size(size_t size, const T &value = {})#
Grow to exact size with initialized elements.
fp::raii::dynarray<float> data; data.grow_to_size(100, 3.14f); assert(data.size() == 100); for(auto& val : data) assert(val == 3.14f);
Note
If size is smaller than the current size, this function does nothing!
- Parameters:
size – Target size
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline Derived &grow_to_size_uninitialized(size_t size)#
Grow to exact size with uninitialized elements.
- Parameters:
size – Target size
- Returns:
Reference to this array for chaining
-
inline T &push_back(const T &value)#
Add element to end of array.
fp::raii::dynarray<std::string> names; names.push_back("Alice"); names.push_back("Bob"); std::string& ref = names.push_back("Charlie"); ref += " Smith"; // Modify in place assert(names[2] == "Charlie Smith");
- Parameters:
value – Value to add
- Returns:
Reference to the newly added element
-
template<typename ...Targs>
inline T &emplace_back(Targs... args)# Construct element in-place at end of array.
Constructs the element directly in the array without copying/moving.
struct Point { int x, y; Point(int x_, int y_) : x(x_), y(y_) {} }; fp::raii::dynarray<Point> points; // Construct directly in array points.emplace_back(10, 20); points.emplace_back(30, 40); assert(points[0].x == 10);
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to the newly constructed element
-
inline T &pop_back_n(size_t count)#
Remove last n elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.pop_back_n(3); assert(arr.size() == 7);
- Parameters:
count – Number of elements to remove
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &pop_back()#
Remove last element.
fp::raii::dynarray<int> stack; stack.push_back(10); stack.push_back(20); stack.push_back(30); stack.pop_back(); assert(stack.size() == 2); assert(stack.back() == 20);
- Returns:
Reference to removed element (now invalid)
-
inline T &pop_back_to_size(size_t size)#
Pop elements until size reaches target.
fp::raii::dynarray<int> arr; for(int i = 0; i < 100; i++) arr.push_back(i); arr.pop_back_to_size(50); assert(arr.size() == 50);
- Parameters:
size – Target size
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &insert(size_t pos, const T &value = {})#
Insert element at position.
Elements after pos are shifted right. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); arr.push_back(4); arr.insert(2, 3); // arr: [1, 2, 3, 4] assert(arr[2] == 3);
- Parameters:
pos – Position to insert at
value – Value to insert (default-constructed if omitted)
- Returns:
Reference to inserted element
-
template<typename ...Targs>
inline T &emplace(size_t pos, Targs... args)# Construct element in-place at position.
Elements after pos are shifted right. O(n) operation.
struct Widget { int id; std::string name; Widget(int i, std::string n) : id(i), name(std::move(n)) {} }; fp::raii::dynarray<Widget> widgets; widgets.emplace_back(1, "First"); widgets.emplace_back(3, "Third"); widgets.emplace(1, 2, "Second"); // widgets: [(1,"First"), (2,"Second"), (3,"Third")]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
pos – Position to insert at
args – Constructor arguments
- Returns:
Reference to inserted element
-
inline T &push_front(const T &value = {})#
Insert element at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<int> deque; deque.push_front(3); deque.push_front(2); deque.push_front(1); // deque: [1, 2, 3] assert(deque[0] == 1);
- Parameters:
value – Value to insert
- Returns:
Reference to inserted element
-
template<typename ...Targs>
inline T &emplace_front(Targs... args)# Construct element in-place at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<std::string> list; list.emplace_front("World"); list.emplace_front("Hello"); // list: ["Hello", "World"]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to newly constructed element
-
inline view<T> insert_uninitialized(size_t pos, size_t count = 1)#
Insert uninitialized elements.
Elements after pos are shifted right. O(n) operation.
fp::dynarray<int> arr; arr.push_back(1); arr.push_back(5); auto view = arr.insert_uninitialized(1, 3); view[0] = 2; view[1] = 3; view[2] = 4; // arr: [1, 2, 3, 4, 5]
- Parameters:
pos – Position to insert at
count – Number of elements to insert (default: 1)
- Returns:
View over the inserted uninitialized elements
-
inline Derived &delete_range(size_t pos, size_t count)#
Delete range of elements.
Elements after pos + count are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.delete_range(3, 4) .push_back(99); assert(arr.size() == 7);
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline Derived &delete_(size_t pos)#
Delete single element.
Elements after pos are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1).push_back(2).push_back(3); arr.delete_(1); // arr: [1, 3]
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &remove(size_t pos)#
Alias for delete_.
-
inline Derived &delete_start_end(size_t start, size_t end)#
Delete range using start and end indices.
Elements after end are shifted left. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete_range(size_t pos, size_t count)#
Delete range and shrink capacity.
Like delete_range but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete(size_t pos)#
Delete element and shrink capacity.
Like delete_ but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete_start_end(size_t start, size_t end)#
Delete range and shrink using start/end indices.
Like delete_start_end but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline Derived &resize(size_t size)#
Resize array to new size.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.resize(20); // Grow assert(arr.size() == 20); arr.resize(5); // Shrink assert(arr.size() == 5);
- Parameters:
size – New size
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_to_fit()#
Shrink capacity to match size.
fp::raii::dynarray<int> arr; arr.reserve(1000); for(int i = 0; i < 100; i++) arr.push_back(i); assert(arr.capacity() == 1000); arr.shrink_to_fit(); assert(arr.capacity() == 100);
- Returns:
Reference to this array for chaining
-
inline Derived &swap_range(size_t start1, size_t start2, size_t count)#
Swap two ranges of elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_range(0, 7, 3); // Swapped [0,1,2] with [7,8,9]
- Parameters:
start1 – Start of first range
start2 – Start of second range
count – Number of elements to swap
- Returns:
Reference to this array for chaining
-
inline Derived &swap(size_t pos1, size_t pos2)#
Swap two elements.
fp::raii::dynarray<int> arr = {10, 20, 30}; arr.swap(0, 2); // arr: [30, 20, 10]
- Parameters:
pos1 – First position
pos2 – Second position
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete_range(size_t pos, size_t count)#
Swap range to end and delete.
O(1) deletion that doesn’t preserve order.
fp::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_delete_range(2, 2); // Deleted elements at 2-3 by swapping with end assert(arr.size() == 8);
- Parameters:
pos – Starting position
count – Number of elements
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete(size_t pos)#
Swap element to end and delete.
Fast O(1) unordered deletion.
fp::dynarray<int> arr = {0, 10, 20, 30, 40}; arr.swap_delete(1); // arr: [0, 40, 20, 30] (40 moved to position 1)
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete_start_end(size_t start, size_t end)#
Swap range to end and delete using start/end indices.
O(1) deletion that doesn’t preserve order.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline T &pop_front()#
Remove and return first element.
Shifts all elements left. O(n) operation.
fp::dynarray<int> queue; queue.push_back(1).push_back(2).push_back(3); queue.pop_front(); // queue: [2, 3]
- Returns:
Reference to removed element (now invalid)
-
inline Derived &clear()#
Clear all elements (keeps capacity)
Calls destructors for non-trivial types.
fp::raii::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); assert(strings.size() == 2); strings.clear(); assert(strings.size() == 0); assert(strings.capacity() > 0); // Capacity unchanged
- Returns:
Reference to this array for chaining
-
inline Derived &concatenate_view_in_place(const view<const T> view)#
Concatenate view to this array in place.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; arr.concatenate_view_in_place({more, 3}); // arr: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
Reference to this array for chaining
-
inline Derived concatenate_view(const view<const T> view) const#
Concatenate view (returns new array)
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; fp::raii::dynarray<int> combined = arr.concatenate_view({more, 3}); // combined: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
New array with concatenated data
-
inline Derived &concatenate_in_place(const Derived &other)#
Concatenate other array to this one in place.
fp::raii::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); arr1.concatenate_in_place(arr2); // arr1: [1, 2, 3, 4] // arr2: [3, 4] (unchanged)
- Parameters:
other – Array to append
- Returns:
Reference to this array for chaining
-
inline Derived concatenate(const Derived &other) const#
Concatenate two arrays (returns new array)
fp::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); fp::dynarray<int> combined = arr1.concatenate(arr2); // combined: [1, 2, 3, 4] // arr1 and arr2 unchanged
- Parameters:
other – Array to append
- Returns:
New array with concatenated data
Public Members
-
T *raw#
Raw pointer to data.
-
inline T *data()#
-
template<typename T>
struct dynarray : public fp::pointer<T>, public fp::dynarray_crtp<T, dynarray<T>># - #include <dynarray.hpp>
Dynamic array with manual memory management.
fp::dynarray is a std::vector-like container built on fat pointers. Provides automatic growth, efficient insertion/deletion, and full iterator support. Requires manual free() call or use fp::raii::dynarray for automatic cleanup.
Features:
Automatic capacity management with amortized O(1) push
Method chaining for fluent interface
Perfect forwarding with emplace operations
Automatic destructor calls for non-trivial types
STL-compatible interface
Basic Dynarray Usage#
fp::dynarray<int> numbers; // Add elements numbers.push_back(10); numbers.push_back(20); numbers.push_back(30); // Method chaining numbers.reserve(100) .grow(5, 42) .push_back(99); // Iteration for(auto& n : numbers) std::cout << n << " "; // Manual cleanup numbers.free();
Initializer List#
fp::dynarray<int> numbers = {1, 2, 3, 4, 5}; assert(numbers.size() == 5); assert(numbers[2] == 3); fp::dynarray<std::string> names = {"Alice", "Bob", "Charlie"}; assert(names.size() == 3); numbers.free(); names.free();
Complex Types in a Dynarray#
struct Person { std::string name; int age; Person(std::string n, int a) : name(std::move(n)), age(a) {} }; fp::dynarray<Person> people; // In-place construction (no copies) people.emplace_back("Alice", 30); people.emplace_back("Bob", 25); people.emplace(1, "Charlie", 35); // Insert at position 1 // people: [Alice(30), Charlie(35), Bob(25)] people.free(); // Destructors called automatically
Common Dynarray Operations#
fp::dynarray<int> data; for(int i = 0; i < 100; i++) data.push_back(i); // Delete range data.delete_range(10, 20); // Fast unordered delete (O(1)) data.swap_delete(5); // Insert multiple elements auto view = data.insert_uninitialized(0, 5); for(size_t i = 0; i < view.size(); i++) view[i] = -1; // Clone and concatenate fp::dynarray<int> copy = data.clone(); data.concatenate_in_place(copy); data.free(); copy.free();
STL Compatibility#
fp::dynarray<int> arr = {5, 2, 8, 1, 9}; // Use STL algorithms std::sort(arr.begin(), arr.end()); std::reverse(arr.begin(), arr.end()); // Find element auto it = std::find(arr.begin(), arr.end(), 5); if(it != arr.end()) std::cout << "Found at position: " << (it - arr.begin()) << "\n"; // Use with span (C++20) std::span<int> s = arr.span(); arr.free();
- Template Parameters:
T – Element type
Unnamed Group
Unnamed Group
Unnamed Group
-
inline T &operator*()
Dereference operator - access first element.
- Returns:
Reference to first element
Unnamed Group
-
inline T *operator->()
Arrow operator - access first element’s members.
- Returns:
Pointer to first element
Unnamed Group
Unnamed Group
-
inline size_t length() const#
Get the number of elements.
fp::auto_free arr = fp::malloc<int>(50); std::cout << "Array has " << arr.length() << " elements\n"; // Use in loops for(size_t i = 0; i < arr.length(); i++) arr[i] = i;
Unnamed Group
-
inline T *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(50); // Manual iteration for(int* it = arr.begin(); it != arr.end(); ++it) *it = 42; // Use with STL algorithms std::iota(arr.begin(), arr.end(), 0); std::sort(arr.begin(), arr.end()); std::reverse(arr.begin(), arr.end()); // Distance size_t count = std::distance(arr.begin(), arr.end()); assert(count == arr.size());
Unnamed Group
-
inline T *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); arr.fill(1); // Range-based for loop for(int& val : arr) val *= 2; // Find operations auto it = std::find(arr.begin(), arr.end(), 42); if(it != arr.end()) std::cout << "Found at index: " << (it - arr.begin()) << "\n"; // Accumulate int sum = std::accumulate(arr.begin(), arr.end(), 0);
Unnamed Group
Public Functions
-
inline dynarray(std::initializer_list<T> init)#
Construct from initializer list.
fp::dynarray<int> numbers = {1, 2, 3, 4, 5}; fp::dynarray<double> values = {3.14, 2.71, 1.41}; fp::dynarray<std::string> names = {"Alice", "Bob", "Charlie"}; assert(numbers.size() == 5); assert(values.size() == 3); assert(names[1] == "Bob"); numbers.free(); values.free(); names.free();
- Parameters:
init – Initializer list of values
-
inline operator dynarray<std::add_const_t<T>>() const#
Implicit conversion to const dynarray.
Allows passing non-const arrays to functions expecting const arrays.
void print_numbers(const fp::dynarray<const int>& arr) { for(auto& n : arr) std::cout << n << " "; } fp::dynarray<int> numbers = {1, 2, 3}; print_numbers(numbers); // Implicit conversion numbers.free();
-
inline operator pointer<std::add_const_t<T>>() const#
Implicit conversion to const pointer.
Allows passing non-const pointers to functions expecting const pointers.
void print_data(fp::pointer<const int> data) { for(size_t i = 0; i < data.size(); i++) { std::cout << data[i] << " "; } } fp::auto_release arr = fp::malloc<int>(5).fill(42); print_data(arr); // Implicit conversion
-
inline void free(bool nullify = true)#
Free the allocated memory.
Releases the memory allocated for this fat pointer. By default, the internal pointer is set to nullptr after freeing to prevent use-after-free bugs.
This is the preferred method for freeing memory as it provides safety by default. The pointer object remains valid but will be null after this call.
fp::pointer<int> arr = fp::malloc<int>(20); // Default: nullifies after free arr.free(); assert(arr.data() == nullptr); // Explicit: don't nullify (use with caution) fp::pointer<int> arr2 = fp::malloc<int>(20); arr2.free(false); // arr2.data() is now a dangling pointer - DANGEROUS! // Better: use default behavior fp::pointer<int> arr3 = fp::malloc<int>(20); arr3.free(true); // Explicit, but default
RAII Dynarray Usage#
// If you don't want to call free() manually, use RAII { fp::raii::pointer<int> auto_arr = fp::malloc<int>(100); // or fp::auto_free auto_arr = ... // Use auto_arr... // Automatically freed when scope exits }
See also
fp::raii::pointer for automatic memory management
Warning
After calling free(), any views or references to the data become invalid.
Warning
Only call free() on heap-allocated pointers, not stack-allocated ones.
- Parameters:
nullify – If true, sets the internal pointer to nullptr after freeing (default: true)
-
inline void free() const#
Free the allocated memory (const version)
This overload is provided for const pointers and does not nullify the internal pointer. Use with extreme caution as the pointer will be left in a dangling state.
This overload exists primarily for compatibility with const contexts, but its use is discouraged. Consider restructuring your code to avoid freeing through const references.
// Dangerous usage (avoid if possible) void unsafe_free(const fp::pointer<int>& arr) { arr.free(); // Calls const version // arr.data() is now dangling but we can't nullify it }
See also
free(bool) for the safer, non-const version
Warning
This version does not nullify the pointer, making it dangerous. Prefer the non-const version whenever possible.
Warning
The pointer becomes invalid but the const object cannot be modified.
-
inline pointer &realloc(size_t new_count)#
Reallocate with a new size.
Existing data is preserved up to the minimum of old and new sizes. The pointer address may change, but the reference is updated automatically.
fp::pointer<int> arr = fp::malloc<int>(10); for(size_t i = 0; i < arr.size(); i++) arr[i] = i; // Expand to 20 elements (first 10 preserved) arr.realloc(20); assert(arr.size() == 20); assert(arr[5] == 5); // Old data still there // Shrink to 5 elements arr.realloc(5); assert(arr.size() == 5); arr.free();
- Parameters:
new_count – New number of elements
- Returns:
Reference to this pointer (may have new address)
-
inline pointer clone() const#
Create a copy of this pointer.
Creates an independent copy of the data. Modifications to the clone do not affect the original.
fp::auto_free original = fp::malloc<int>(5).fill(42); fp::pointer<int> copy = original.clone(); copy[0] = 99; // Doesn't affect original assert(original[0] == 42); assert(copy[0] == 99); copy.free();
- Returns:
New pointer with copied data (must be freed separately)
-
inline T *data()
Get the raw pointer.
-
inline T *release()#
Release ownership of the pointer.
After calling release(), the pointer object no longer owns the memory. The caller becomes responsible for freeing it.
fp::auto_free arr = fp::malloc<int>(10).fill(42); // Transfer ownership int* raw = arr.release(); assert(arr.data() == nullptr); // Now we must manually free fp_free(raw);
- Returns:
The raw pointer (ownership transferred to caller)
-
inline bool is_fp() const#
Check if this is a valid fat pointer.
int regular[10]; fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; assert(arr.is_fp()); assert(!null_ptr.is_fp());
-
inline bool stack_allocated() const#
Check if this is stack-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(stack_arr.stack_allocated()); assert(!heap_arr.stack_allocated());
-
inline bool heap_allocated() const#
Check if this is heap-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(!stack_arr.heap_allocated()); assert(heap_arr.heap_allocated());
-
inline operator bool() const#
Check if pointer is non-null.
fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; if(arr) std::cout << "Array is valid\n"; if(!null_ptr) std::cout << "Null pointer\n"; // Safe access pattern if(arr && arr.size() > 0) arr[0] = 42;
-
inline bool empty() const#
Check if the pointer is empty.
fp::auto_free arr1 = fp::malloc<int>(10); fp::auto_free arr2 = fp::malloc<int>(0); assert(!arr1.empty()); assert(arr2.empty()); // Safe access pattern if(!arr1.empty()) arr1[0] = 42;
-
inline view_t view(size_t start, size_t length)#
Create a view of a portion of this pointer.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20-39 auto v = arr.view(20, 20); v.fill(999); assert(arr[20] == 999); assert(arr[39] == 999); assert(arr[19] != 999); // Outside view // Process data in chunks for(size_t i = 0; i < arr.size(); i += 10) { auto chunk = arr.view(i, 10); process_chunk(chunk); }
- Parameters:
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
inline view_t view_full()#
Create a view of the entire pointer.
fp::auto_free arr = fp::malloc<int>(50); // Create full view auto v = arr.view_full(); assert(v.size() == arr.size()); // Useful for passing to functions expecting views void process_view(fp::view<int> data) { for(auto& val : data) val *= 2; } process_view(arr.view_full());
- Returns:
View over all elements
-
inline view_t full_view()#
Alias for view_full.
fp::auto_free arr = fp::malloc<int>(50); // Both are equivalent auto v1 = arr.view_full(); auto v2 = arr.full_view(); assert(v1.size() == v2.size());
-
inline view_t view_start_end(size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10 through 20 (inclusive) - 11 elements auto v = arr.view_start_end(10, 20); assert(v.size() == 11); // Process quarters size_t quarter = arr.size() / 4; auto q1 = arr.view_start_end(0, quarter - 1); auto q2 = arr.view_start_end(quarter, 2 * quarter - 1); auto q3 = arr.view_start_end(2 * quarter, 3 * quarter - 1); auto q4 = arr.view_start_end(3 * quarter, arr.size() - 1);
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
inline const view_t view_start_end(size_t start, size_t end) const#
Create a view with start/end indices (const version)
-
inline T &front()#
Get reference to first element.
fp::auto_free arr = fp::malloc<int>(10).fill(5); arr.front() = 100; assert(arr[0] == 100); // Useful for algorithms int first = arr.front(); int last = arr.back();
-
inline T &back()#
Get reference to last element.
fp::auto_free arr = fp::malloc<int>(10); arr.fill(5); arr.back() = 999; assert(arr[arr.size() - 1] == 999); // Access both ends if(!arr.empty()) { arr.front() = 1; arr.back() = 100; }
-
inline pointer<T> &fill(const T &value = {})#
Fill all elements with a value.
fp::auto_free arr = fp::malloc<int>(100); // Fill with specific value arr.fill(42); assert(arr[0] == 42); assert(arr[99] == 42); // Fill with default value (0 for int) arr.fill(); assert(arr[0] == 0); // Method chaining fp::auto_free data = fp::malloc<float>(50).fill(3.14f); // Fill with custom types struct Point { int x = 0, y = 0; }; fp::auto_free points = fp::malloc<Point>(10); points.fill(Point{5, 10});
- Parameters:
value – Value to fill with (default-constructed if not provided)
- Returns:
Reference to derived class for chaining
-
inline bool is_dynarray() const#
Check if this is a valid dynamic array.
fp::raii::dynarray<int> arr; assert(!arr.is_dynarray()); // Empty/null arr.push_back(42); assert(arr.is_dynarray()); // Now valid
- Returns:
true if this is a dynamic array
-
inline size_t capacity() const#
Get allocated capacity.
fp::raii::dynarray<int> arr; arr.reserve(50); assert(arr.capacity() == 50); assert(arr.size() == 0); arr.push_back(1); assert(arr.capacity() == 50); // No reallocation
- Returns:
Number of elements that can be stored without reallocation
-
inline void free(bool nullify = true)
Free the dynamic array.
Calls destructors for non-trivial types before freeing memory.
fp::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); strings.free(); // Destructors called, memory freed, ptr nulled assert(!strings);- Parameters:
nullify – If true, sets pointer to null (default: true)
-
inline void free() const
Free the dynamic array (const version)
Warning
Does not nullify pointer. Prefer non-const version.
-
inline dynarray<T> &reserve(size_t size)#
Reserve capacity for at least size elements.
fp::raii::dynarray<int> arr; // Reserve and chain operations arr.reserve(1000) .push_back(42); arr.push_back(99); // No reallocations for next 998 elements
- Parameters:
size – Minimum capacity to reserve
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &grow(size_t to_add, const T &value = {})#
Grow array by adding initialized elements.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); // Add 5 elements, all initialized to 99 arr.grow(5, 99); assert(arr.size() == 7); assert(arr[2] == 99);
- Parameters:
to_add – Number of elements to add
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &grow_uninitialized(size_t to_add)#
Grow array with uninitialized elements.
New elements are uninitialized - you must initialize them before use. Useful for performance when you’ll immediately overwrite values.
fp::raii::dynarray<int> arr; arr.push_back(1); size_t old_size = arr.size(); arr.grow_uninitialized(10); // Initialize new elements for(size_t i = old_size; i < arr.size(); i++) arr[i] = i * 10;
- Parameters:
to_add – Number of elements to add
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &grow_to_size(size_t size, const T &value = {})#
Grow to exact size with initialized elements.
fp::raii::dynarray<float> data; data.grow_to_size(100, 3.14f); assert(data.size() == 100); for(auto& val : data) assert(val == 3.14f);
Note
If size is smaller than the current size, this function does nothing!
- Parameters:
size – Target size
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &grow_to_size_uninitialized(size_t size)#
Grow to exact size with uninitialized elements.
- Parameters:
size – Target size
- Returns:
Reference to this array for chaining
-
inline T &push_back(const T &value)#
Add element to end of array.
fp::raii::dynarray<std::string> names; names.push_back("Alice"); names.push_back("Bob"); std::string& ref = names.push_back("Charlie"); ref += " Smith"; // Modify in place assert(names[2] == "Charlie Smith");
- Parameters:
value – Value to add
- Returns:
Reference to the newly added element
-
inline T &emplace_back(Targs... args)#
Construct element in-place at end of array.
Constructs the element directly in the array without copying/moving.
struct Point { int x, y; Point(int x_, int y_) : x(x_), y(y_) {} }; fp::raii::dynarray<Point> points; // Construct directly in array points.emplace_back(10, 20); points.emplace_back(30, 40); assert(points[0].x == 10);
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to the newly constructed element
-
inline T &pop_back_n(size_t count)#
Remove last n elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.pop_back_n(3); assert(arr.size() == 7);
- Parameters:
count – Number of elements to remove
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &pop_back()#
Remove last element.
fp::raii::dynarray<int> stack; stack.push_back(10); stack.push_back(20); stack.push_back(30); stack.pop_back(); assert(stack.size() == 2); assert(stack.back() == 20);
- Returns:
Reference to removed element (now invalid)
-
inline T &pop_back_to_size(size_t size)#
Pop elements until size reaches target.
fp::raii::dynarray<int> arr; for(int i = 0; i < 100; i++) arr.push_back(i); arr.pop_back_to_size(50); assert(arr.size() == 50);
- Parameters:
size – Target size
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &insert(size_t pos, const T &value = {})#
Insert element at position.
Elements after pos are shifted right. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); arr.push_back(4); arr.insert(2, 3); // arr: [1, 2, 3, 4] assert(arr[2] == 3);
- Parameters:
pos – Position to insert at
value – Value to insert (default-constructed if omitted)
- Returns:
Reference to inserted element
-
inline T &emplace(size_t pos, Targs... args)#
Construct element in-place at position.
Elements after pos are shifted right. O(n) operation.
struct Widget { int id; std::string name; Widget(int i, std::string n) : id(i), name(std::move(n)) {} }; fp::raii::dynarray<Widget> widgets; widgets.emplace_back(1, "First"); widgets.emplace_back(3, "Third"); widgets.emplace(1, 2, "Second"); // widgets: [(1,"First"), (2,"Second"), (3,"Third")]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
pos – Position to insert at
args – Constructor arguments
- Returns:
Reference to inserted element
-
inline T &push_front(const T &value = {})#
Insert element at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<int> deque; deque.push_front(3); deque.push_front(2); deque.push_front(1); // deque: [1, 2, 3] assert(deque[0] == 1);
- Parameters:
value – Value to insert
- Returns:
Reference to inserted element
-
inline T &emplace_front(Targs... args)#
Construct element in-place at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<std::string> list; list.emplace_front("World"); list.emplace_front("Hello"); // list: ["Hello", "World"]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to newly constructed element
-
inline view<T> insert_uninitialized(size_t pos, size_t count = 1)#
Insert uninitialized elements.
Elements after pos are shifted right. O(n) operation.
fp::dynarray<int> arr; arr.push_back(1); arr.push_back(5); auto view = arr.insert_uninitialized(1, 3); view[0] = 2; view[1] = 3; view[2] = 4; // arr: [1, 2, 3, 4, 5]
- Parameters:
pos – Position to insert at
count – Number of elements to insert (default: 1)
- Returns:
View over the inserted uninitialized elements
-
inline dynarray<T> &delete_range(size_t pos, size_t count)#
Delete range of elements.
Elements after pos + count are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.delete_range(3, 4) .push_back(99); assert(arr.size() == 7);
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &delete_(size_t pos)#
Delete single element.
Elements after pos are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1).push_back(2).push_back(3); arr.delete_(1); // arr: [1, 3]
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &delete_start_end(size_t start, size_t end)#
Delete range using start and end indices.
Elements after end are shifted left. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &shrink_delete_range(size_t pos, size_t count)#
Delete range and shrink capacity.
Like delete_range but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &shrink_delete(size_t pos)#
Delete element and shrink capacity.
Like delete_ but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &shrink_delete_start_end(size_t start, size_t end)#
Delete range and shrink using start/end indices.
Like delete_start_end but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &resize(size_t size)#
Resize array to new size.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.resize(20); // Grow assert(arr.size() == 20); arr.resize(5); // Shrink assert(arr.size() == 5);
- Parameters:
size – New size
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &shrink_to_fit()#
Shrink capacity to match size.
fp::raii::dynarray<int> arr; arr.reserve(1000); for(int i = 0; i < 100; i++) arr.push_back(i); assert(arr.capacity() == 1000); arr.shrink_to_fit(); assert(arr.capacity() == 100);
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &swap_range(size_t start1, size_t start2, size_t count)#
Swap two ranges of elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_range(0, 7, 3); // Swapped [0,1,2] with [7,8,9]
- Parameters:
start1 – Start of first range
start2 – Start of second range
count – Number of elements to swap
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &swap(size_t pos1, size_t pos2)#
Swap two elements.
fp::raii::dynarray<int> arr = {10, 20, 30}; arr.swap(0, 2); // arr: [30, 20, 10]
- Parameters:
pos1 – First position
pos2 – Second position
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &swap_delete_range(size_t pos, size_t count)#
Swap range to end and delete.
O(1) deletion that doesn’t preserve order.
fp::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_delete_range(2, 2); // Deleted elements at 2-3 by swapping with end assert(arr.size() == 8);
- Parameters:
pos – Starting position
count – Number of elements
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &swap_delete(size_t pos)#
Swap element to end and delete.
Fast O(1) unordered deletion.
fp::dynarray<int> arr = {0, 10, 20, 30, 40}; arr.swap_delete(1); // arr: [0, 40, 20, 30] (40 moved to position 1)
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &swap_delete_start_end(size_t start, size_t end)#
Swap range to end and delete using start/end indices.
O(1) deletion that doesn’t preserve order.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline T &pop_front()#
Remove and return first element.
Shifts all elements left. O(n) operation.
fp::dynarray<int> queue; queue.push_back(1).push_back(2).push_back(3); queue.pop_front(); // queue: [2, 3]
- Returns:
Reference to removed element (now invalid)
-
inline dynarray<T> clone() const
Create a copy of this array.
fp::raii::dynarray<int> original; original.push_back(1); original.push_back(2); original.push_back(3); fp::raii::dynarray<int> copy = original.clone(); copy[0] = 999; // Doesn't affect original assert(original[0] == 1); assert(copy[0] == 999);
- Returns:
New array with copied data
-
inline dynarray<T> &clear()#
Clear all elements (keeps capacity)
Calls destructors for non-trivial types.
fp::raii::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); assert(strings.size() == 2); strings.clear(); assert(strings.size() == 0); assert(strings.capacity() > 0); // Capacity unchanged
- Returns:
Reference to this array for chaining
-
inline dynarray<T> &concatenate_view_in_place(const view<const T> view)#
Concatenate view to this array in place.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; arr.concatenate_view_in_place({more, 3}); // arr: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
Reference to this array for chaining
-
inline dynarray<T> concatenate_view(const view<const T> view) const#
Concatenate view (returns new array)
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; fp::raii::dynarray<int> combined = arr.concatenate_view({more, 3}); // combined: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
New array with concatenated data
-
inline dynarray<T> &concatenate_in_place(const dynarray<T> &other)#
Concatenate other array to this one in place.
fp::raii::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); arr1.concatenate_in_place(arr2); // arr1: [1, 2, 3, 4] // arr2: [3, 4] (unchanged)
- Parameters:
other – Array to append
- Returns:
Reference to this array for chaining
-
inline dynarray<T> concatenate(const dynarray<T> &other) const#
Concatenate two arrays (returns new array)
fp::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); fp::dynarray<int> combined = arr1.concatenate(arr2); // combined: [1, 2, 3, 4] // arr1 and arr2 unchanged
- Parameters:
other – Array to append
- Returns:
New array with concatenated data
-
template<typename T, typename Derived>
struct dynarray_crtp# - #include <dynarray.hpp>
CRTP base providing dynamic array operations.
This class uses the Curiously Recurring Template Pattern (CRTP) to provide dynamic array operations to derived classes. It handles automatic destructor calls for non-trivial types and provides method chaining.
- Template Parameters:
T – Element type
Derived – The derived class (CRTP pattern)
Subclassed by fp::dynarray< char >
Public Functions
-
inline bool is_dynarray() const#
Check if this is a valid dynamic array.
fp::raii::dynarray<int> arr; assert(!arr.is_dynarray()); // Empty/null arr.push_back(42); assert(arr.is_dynarray()); // Now valid
- Returns:
true if this is a dynamic array
-
inline size_t capacity() const#
Get allocated capacity.
fp::raii::dynarray<int> arr; arr.reserve(50); assert(arr.capacity() == 50); assert(arr.size() == 0); arr.push_back(1); assert(arr.capacity() == 50); // No reallocation
- Returns:
Number of elements that can be stored without reallocation
-
inline void free(bool nullify = true)#
Free the dynamic array.
Calls destructors for non-trivial types before freeing memory.
fp::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); strings.free(); // Destructors called, memory freed, ptr nulled assert(!strings);- Parameters:
nullify – If true, sets pointer to null (default: true)
-
inline void free() const#
Free the dynamic array (const version)
Warning
Does not nullify pointer. Prefer non-const version.
-
inline Derived &reserve(size_t size)#
Reserve capacity for at least size elements.
fp::raii::dynarray<int> arr; // Reserve and chain operations arr.reserve(1000) .push_back(42); arr.push_back(99); // No reallocations for next 998 elements
- Parameters:
size – Minimum capacity to reserve
- Returns:
Reference to this array for chaining
-
inline Derived &grow(size_t to_add, const T &value = {})#
Grow array by adding initialized elements.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); // Add 5 elements, all initialized to 99 arr.grow(5, 99); assert(arr.size() == 7); assert(arr[2] == 99);
- Parameters:
to_add – Number of elements to add
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline Derived &grow_uninitialized(size_t to_add)#
Grow array with uninitialized elements.
New elements are uninitialized - you must initialize them before use. Useful for performance when you’ll immediately overwrite values.
fp::raii::dynarray<int> arr; arr.push_back(1); size_t old_size = arr.size(); arr.grow_uninitialized(10); // Initialize new elements for(size_t i = old_size; i < arr.size(); i++) arr[i] = i * 10;
- Parameters:
to_add – Number of elements to add
- Returns:
Reference to this array for chaining
-
inline Derived &grow_to_size(size_t size, const T &value = {})#
Grow to exact size with initialized elements.
fp::raii::dynarray<float> data; data.grow_to_size(100, 3.14f); assert(data.size() == 100); for(auto& val : data) assert(val == 3.14f);
Note
If size is smaller than the current size, this function does nothing!
- Parameters:
size – Target size
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline Derived &grow_to_size_uninitialized(size_t size)#
Grow to exact size with uninitialized elements.
- Parameters:
size – Target size
- Returns:
Reference to this array for chaining
-
inline T &push_back(const T &value)#
Add element to end of array.
fp::raii::dynarray<std::string> names; names.push_back("Alice"); names.push_back("Bob"); std::string& ref = names.push_back("Charlie"); ref += " Smith"; // Modify in place assert(names[2] == "Charlie Smith");
- Parameters:
value – Value to add
- Returns:
Reference to the newly added element
-
template<typename ...Targs>
inline T &emplace_back(Targs... args)# Construct element in-place at end of array.
Constructs the element directly in the array without copying/moving.
struct Point { int x, y; Point(int x_, int y_) : x(x_), y(y_) {} }; fp::raii::dynarray<Point> points; // Construct directly in array points.emplace_back(10, 20); points.emplace_back(30, 40); assert(points[0].x == 10);
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to the newly constructed element
-
inline T &pop_back_n(size_t count)#
Remove last n elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.pop_back_n(3); assert(arr.size() == 7);
- Parameters:
count – Number of elements to remove
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &pop_back()#
Remove last element.
fp::raii::dynarray<int> stack; stack.push_back(10); stack.push_back(20); stack.push_back(30); stack.pop_back(); assert(stack.size() == 2); assert(stack.back() == 20);
- Returns:
Reference to removed element (now invalid)
-
inline T &pop_back_to_size(size_t size)#
Pop elements until size reaches target.
fp::raii::dynarray<int> arr; for(int i = 0; i < 100; i++) arr.push_back(i); arr.pop_back_to_size(50); assert(arr.size() == 50);
- Parameters:
size – Target size
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &insert(size_t pos, const T &value = {})#
Insert element at position.
Elements after pos are shifted right. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); arr.push_back(4); arr.insert(2, 3); // arr: [1, 2, 3, 4] assert(arr[2] == 3);
- Parameters:
pos – Position to insert at
value – Value to insert (default-constructed if omitted)
- Returns:
Reference to inserted element
-
template<typename ...Targs>
inline T &emplace(size_t pos, Targs... args)# Construct element in-place at position.
Elements after pos are shifted right. O(n) operation.
struct Widget { int id; std::string name; Widget(int i, std::string n) : id(i), name(std::move(n)) {} }; fp::raii::dynarray<Widget> widgets; widgets.emplace_back(1, "First"); widgets.emplace_back(3, "Third"); widgets.emplace(1, 2, "Second"); // widgets: [(1,"First"), (2,"Second"), (3,"Third")]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
pos – Position to insert at
args – Constructor arguments
- Returns:
Reference to inserted element
-
inline T &push_front(const T &value = {})#
Insert element at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<int> deque; deque.push_front(3); deque.push_front(2); deque.push_front(1); // deque: [1, 2, 3] assert(deque[0] == 1);
- Parameters:
value – Value to insert
- Returns:
Reference to inserted element
-
template<typename ...Targs>
inline T &emplace_front(Targs... args)# Construct element in-place at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<std::string> list; list.emplace_front("World"); list.emplace_front("Hello"); // list: ["Hello", "World"]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to newly constructed element
-
inline view<T> insert_uninitialized(size_t pos, size_t count = 1)#
Insert uninitialized elements.
Elements after pos are shifted right. O(n) operation.
fp::dynarray<int> arr; arr.push_back(1); arr.push_back(5); auto view = arr.insert_uninitialized(1, 3); view[0] = 2; view[1] = 3; view[2] = 4; // arr: [1, 2, 3, 4, 5]
- Parameters:
pos – Position to insert at
count – Number of elements to insert (default: 1)
- Returns:
View over the inserted uninitialized elements
-
inline Derived &delete_range(size_t pos, size_t count)#
Delete range of elements.
Elements after pos + count are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.delete_range(3, 4) .push_back(99); assert(arr.size() == 7);
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline Derived &delete_(size_t pos)#
Delete single element.
Elements after pos are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1).push_back(2).push_back(3); arr.delete_(1); // arr: [1, 3]
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &delete_start_end(size_t start, size_t end)#
Delete range using start and end indices.
Elements after end are shifted left. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete_range(size_t pos, size_t count)#
Delete range and shrink capacity.
Like delete_range but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete(size_t pos)#
Delete element and shrink capacity.
Like delete_ but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete_start_end(size_t start, size_t end)#
Delete range and shrink using start/end indices.
Like delete_start_end but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline Derived &resize(size_t size)#
Resize array to new size.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.resize(20); // Grow assert(arr.size() == 20); arr.resize(5); // Shrink assert(arr.size() == 5);
- Parameters:
size – New size
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_to_fit()#
Shrink capacity to match size.
fp::raii::dynarray<int> arr; arr.reserve(1000); for(int i = 0; i < 100; i++) arr.push_back(i); assert(arr.capacity() == 1000); arr.shrink_to_fit(); assert(arr.capacity() == 100);
- Returns:
Reference to this array for chaining
-
inline Derived &swap_range(size_t start1, size_t start2, size_t count)#
Swap two ranges of elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_range(0, 7, 3); // Swapped [0,1,2] with [7,8,9]
- Parameters:
start1 – Start of first range
start2 – Start of second range
count – Number of elements to swap
- Returns:
Reference to this array for chaining
-
inline Derived &swap(size_t pos1, size_t pos2)#
Swap two elements.
fp::raii::dynarray<int> arr = {10, 20, 30}; arr.swap(0, 2); // arr: [30, 20, 10]
- Parameters:
pos1 – First position
pos2 – Second position
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete_range(size_t pos, size_t count)#
Swap range to end and delete.
O(1) deletion that doesn’t preserve order.
fp::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_delete_range(2, 2); // Deleted elements at 2-3 by swapping with end assert(arr.size() == 8);
- Parameters:
pos – Starting position
count – Number of elements
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete(size_t pos)#
Swap element to end and delete.
Fast O(1) unordered deletion.
fp::dynarray<int> arr = {0, 10, 20, 30, 40}; arr.swap_delete(1); // arr: [0, 40, 20, 30] (40 moved to position 1)
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete_start_end(size_t start, size_t end)#
Swap range to end and delete using start/end indices.
O(1) deletion that doesn’t preserve order.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline T &pop_front()#
Remove and return first element.
Shifts all elements left. O(n) operation.
fp::dynarray<int> queue; queue.push_back(1).push_back(2).push_back(3); queue.pop_front(); // queue: [2, 3]
- Returns:
Reference to removed element (now invalid)
-
inline Derived clone() const#
Create a copy of this array.
fp::raii::dynarray<int> original; original.push_back(1); original.push_back(2); original.push_back(3); fp::raii::dynarray<int> copy = original.clone(); copy[0] = 999; // Doesn't affect original assert(original[0] == 1); assert(copy[0] == 999);
- Returns:
New array with copied data
-
inline Derived &clear()#
Clear all elements (keeps capacity)
Calls destructors for non-trivial types.
fp::raii::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); assert(strings.size() == 2); strings.clear(); assert(strings.size() == 0); assert(strings.capacity() > 0); // Capacity unchanged
- Returns:
Reference to this array for chaining
-
inline Derived &concatenate_view_in_place(const view<const T> view)#
Concatenate view to this array in place.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; arr.concatenate_view_in_place({more, 3}); // arr: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
Reference to this array for chaining
-
inline Derived concatenate_view(const view<const T> view) const#
Concatenate view (returns new array)
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; fp::raii::dynarray<int> combined = arr.concatenate_view({more, 3}); // combined: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
New array with concatenated data
-
inline Derived &concatenate_in_place(const Derived &other)#
Concatenate other array to this one in place.
fp::raii::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); arr1.concatenate_in_place(arr2); // arr1: [1, 2, 3, 4] // arr2: [3, 4] (unchanged)
- Parameters:
other – Array to append
- Returns:
Reference to this array for chaining
-
inline Derived concatenate(const Derived &other) const#
Concatenate two arrays (returns new array)
fp::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); fp::dynarray<int> combined = arr1.concatenate(arr2); // combined: [1, 2, 3, 4] // arr1 and arr2 unchanged
- Parameters:
other – Array to append
- Returns:
New array with concatenated data
-
template<typename T>
struct pointer : public fp::wrapped::pointer<T>, public fp::pointer_crtp<T, pointer<T>># - #include <pointer.hpp>
Main fat pointer class (fp::pointer) with manual memory management.
This is the primary fat pointer class that provides manual memory management with explicit free() calls. For automatic memory management, use fp::raii::pointer or fp::auto_free.
The pointer class combines the wrapped::pointer base (for raw pointer access) with pointer_crtp (for fat pointer operations), providing a complete interface for working with dynamically allocated arrays with bounds checking.
// Manual memory management fp::pointer<int> data = fp::malloc<int>(100); data[0] = 42; data.realloc(200); // Resize to 200 elements data.free(); // Or use clone for deep copy fp::auto_free original = fp::malloc<int>(10); original.fill(5); fp::pointer<int> copy = original.clone(); copy.free(); original.free(false); // ERROR: Using non-nullifying free on an auto_free type will result in a double free!
Iteration Examples#
fp::auto_free arr = fp::malloc<int>(50); // Range-based for loop for(int& val : arr) val = 10; // STL algorithms std::sort(arr.begin(), arr.end()); std::iota(arr.begin(), arr.end(), 0); // Manual iteration for(size_t i = 0; i < arr.size(); i++) arr[i] *= 2;
Working with Views#
fp::auto_free data = fp::malloc<int>(100); // Create view of middle section auto middle = data.view(25, 50); for(int& val : middle) { val = 999; } // Create multiple views auto first_half = data.view(0, 50); auto second_half = data.view(50, 50);
- Template Parameters:
T – Element type
Subclassed by fp::dynarray< char >, fp::dynarray< T >
Unnamed Group
Unnamed Group
Unnamed Group
Unnamed Group
-
inline size_t length() const#
Get the number of elements.
fp::auto_free arr = fp::malloc<int>(50); std::cout << "Array has " << arr.length() << " elements\n"; // Use in loops for(size_t i = 0; i < arr.length(); i++) arr[i] = i;
Unnamed Group
-
inline T *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(50); // Manual iteration for(int* it = arr.begin(); it != arr.end(); ++it) *it = 42; // Use with STL algorithms std::iota(arr.begin(), arr.end(), 0); std::sort(arr.begin(), arr.end()); std::reverse(arr.begin(), arr.end()); // Distance size_t count = std::distance(arr.begin(), arr.end()); assert(count == arr.size());
Unnamed Group
-
inline T *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); arr.fill(1); // Range-based for loop for(int& val : arr) val *= 2; // Find operations auto it = std::find(arr.begin(), arr.end(), 42); if(it != arr.end()) std::cout << "Found at index: " << (it - arr.begin()) << "\n"; // Accumulate int sum = std::accumulate(arr.begin(), arr.end(), 0);
Unnamed Group
-
inline T &operator*()
Dereference operator - access first element.
- Returns:
Reference to first element
Unnamed Group
-
inline T *operator->()
Arrow operator - access first element’s members.
- Returns:
Pointer to first element
Unnamed Group
Public Functions
-
inline constexpr pointer(T *ptr_)#
Construct from raw fat pointer.
// From C-style allocation int* c_style = fp_malloc(int, 20); fp::pointer<int> wrapper(c_style); assert(wrapper.size() == 20); wrapper.free();
- Parameters:
ptr_ – Raw fat pointer (must be null or valid fat pointer)
-
inline operator pointer<std::add_const_t<T>>() const#
Implicit conversion to const pointer.
Allows passing non-const pointers to functions expecting const pointers.
void print_data(fp::pointer<const int> data) { for(size_t i = 0; i < data.size(); i++) { std::cout << data[i] << " "; } } fp::auto_release arr = fp::malloc<int>(5).fill(42); print_data(arr); // Implicit conversion
-
inline void free(bool nullify = true)#
Free the allocated memory.
Releases the memory allocated for this fat pointer. By default, the internal pointer is set to nullptr after freeing to prevent use-after-free bugs.
This is the preferred method for freeing memory as it provides safety by default. The pointer object remains valid but will be null after this call.
fp::pointer<int> arr = fp::malloc<int>(20); // Default: nullifies after free arr.free(); assert(arr.data() == nullptr); // Explicit: don't nullify (use with caution) fp::pointer<int> arr2 = fp::malloc<int>(20); arr2.free(false); // arr2.data() is now a dangling pointer - DANGEROUS! // Better: use default behavior fp::pointer<int> arr3 = fp::malloc<int>(20); arr3.free(true); // Explicit, but default
RAII Dynarray Usage#
// If you don't want to call free() manually, use RAII { fp::raii::pointer<int> auto_arr = fp::malloc<int>(100); // or fp::auto_free auto_arr = ... // Use auto_arr... // Automatically freed when scope exits }
See also
fp::raii::pointer for automatic memory management
Warning
After calling free(), any views or references to the data become invalid.
Warning
Only call free() on heap-allocated pointers, not stack-allocated ones.
- Parameters:
nullify – If true, sets the internal pointer to nullptr after freeing (default: true)
-
inline void free() const#
Free the allocated memory (const version)
This overload is provided for const pointers and does not nullify the internal pointer. Use with extreme caution as the pointer will be left in a dangling state.
This overload exists primarily for compatibility with const contexts, but its use is discouraged. Consider restructuring your code to avoid freeing through const references.
// Dangerous usage (avoid if possible) void unsafe_free(const fp::pointer<int>& arr) { arr.free(); // Calls const version // arr.data() is now dangling but we can't nullify it }
See also
free(bool) for the safer, non-const version
Warning
This version does not nullify the pointer, making it dangerous. Prefer the non-const version whenever possible.
Warning
The pointer becomes invalid but the const object cannot be modified.
-
inline pointer &realloc(size_t new_count)#
Reallocate with a new size.
Existing data is preserved up to the minimum of old and new sizes. The pointer address may change, but the reference is updated automatically.
fp::pointer<int> arr = fp::malloc<int>(10); for(size_t i = 0; i < arr.size(); i++) arr[i] = i; // Expand to 20 elements (first 10 preserved) arr.realloc(20); assert(arr.size() == 20); assert(arr[5] == 5); // Old data still there // Shrink to 5 elements arr.realloc(5); assert(arr.size() == 5); arr.free();
- Parameters:
new_count – New number of elements
- Returns:
Reference to this pointer (may have new address)
-
inline pointer clone() const#
Create a copy of this pointer.
Creates an independent copy of the data. Modifications to the clone do not affect the original.
fp::auto_free original = fp::malloc<int>(5).fill(42); fp::pointer<int> copy = original.clone(); copy[0] = 99; // Doesn't affect original assert(original[0] == 42); assert(copy[0] == 99); copy.free();
- Returns:
New pointer with copied data (must be freed separately)
-
inline T *data()
Get the raw pointer.
-
inline T *release()#
Release ownership of the pointer.
After calling release(), the pointer object no longer owns the memory. The caller becomes responsible for freeing it.
fp::auto_free arr = fp::malloc<int>(10).fill(42); // Transfer ownership int* raw = arr.release(); assert(arr.data() == nullptr); // Now we must manually free fp_free(raw);
- Returns:
The raw pointer (ownership transferred to caller)
-
inline bool is_fp() const#
Check if this is a valid fat pointer.
int regular[10]; fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; assert(arr.is_fp()); assert(!null_ptr.is_fp());
-
inline bool stack_allocated() const#
Check if this is stack-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(stack_arr.stack_allocated()); assert(!heap_arr.stack_allocated());
-
inline bool heap_allocated() const#
Check if this is heap-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(!stack_arr.heap_allocated()); assert(heap_arr.heap_allocated());
-
inline operator bool() const#
Check if pointer is non-null.
fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; if(arr) std::cout << "Array is valid\n"; if(!null_ptr) std::cout << "Null pointer\n"; // Safe access pattern if(arr && arr.size() > 0) arr[0] = 42;
-
inline bool empty() const#
Check if the pointer is empty.
fp::auto_free arr1 = fp::malloc<int>(10); fp::auto_free arr2 = fp::malloc<int>(0); assert(!arr1.empty()); assert(arr2.empty()); // Safe access pattern if(!arr1.empty()) arr1[0] = 42;
-
inline view_t view(size_t start, size_t length)#
Create a view of a portion of this pointer.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20-39 auto v = arr.view(20, 20); v.fill(999); assert(arr[20] == 999); assert(arr[39] == 999); assert(arr[19] != 999); // Outside view // Process data in chunks for(size_t i = 0; i < arr.size(); i += 10) { auto chunk = arr.view(i, 10); process_chunk(chunk); }
- Parameters:
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
inline view_t view_full()#
Create a view of the entire pointer.
fp::auto_free arr = fp::malloc<int>(50); // Create full view auto v = arr.view_full(); assert(v.size() == arr.size()); // Useful for passing to functions expecting views void process_view(fp::view<int> data) { for(auto& val : data) val *= 2; } process_view(arr.view_full());
- Returns:
View over all elements
-
inline view_t full_view()#
Alias for view_full.
fp::auto_free arr = fp::malloc<int>(50); // Both are equivalent auto v1 = arr.view_full(); auto v2 = arr.full_view(); assert(v1.size() == v2.size());
-
inline view_t view_start_end(size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10 through 20 (inclusive) - 11 elements auto v = arr.view_start_end(10, 20); assert(v.size() == 11); // Process quarters size_t quarter = arr.size() / 4; auto q1 = arr.view_start_end(0, quarter - 1); auto q2 = arr.view_start_end(quarter, 2 * quarter - 1); auto q3 = arr.view_start_end(2 * quarter, 3 * quarter - 1); auto q4 = arr.view_start_end(3 * quarter, arr.size() - 1);
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
inline const view_t view_start_end(size_t start, size_t end) const#
Create a view with start/end indices (const version)
-
inline T &front()#
Get reference to first element.
fp::auto_free arr = fp::malloc<int>(10).fill(5); arr.front() = 100; assert(arr[0] == 100); // Useful for algorithms int first = arr.front(); int last = arr.back();
-
inline T &back()#
Get reference to last element.
fp::auto_free arr = fp::malloc<int>(10); arr.fill(5); arr.back() = 999; assert(arr[arr.size() - 1] == 999); // Access both ends if(!arr.empty()) { arr.front() = 1; arr.back() = 100; }
-
inline pointer<T> &fill(const T &value = {})#
Fill all elements with a value.
fp::auto_free arr = fp::malloc<int>(100); // Fill with specific value arr.fill(42); assert(arr[0] == 42); assert(arr[99] == 42); // Fill with default value (0 for int) arr.fill(); assert(arr[0] == 0); // Method chaining fp::auto_free data = fp::malloc<float>(50).fill(3.14f); // Fill with custom types struct Point { int x = 0, y = 0; }; fp::auto_free points = fp::malloc<Point>(10); points.fill(Point{5, 10});
- Parameters:
value – Value to fill with (default-constructed if not provided)
- Returns:
Reference to derived class for chaining
-
template<typename T, typename Derived>
struct pointer_crtp# - #include <pointer.hpp>
CRTP base providing common fat pointer operations.
This class uses the Curiously Recurring Template Pattern (CRTP) to provide common fat pointer operations to derived classes. It expects the derived class to provide a ptr() method that returns a reference to the underlying fat pointer.
template<typename T> struct my_pointer : public pointer_crtp<T, my_pointer<T>> { T* raw_ptr; protected: T*& ptr() { return raw_ptr; } const T* const& ptr() const { return raw_ptr; } }; // Now my_pointer has all fat pointer operations my_pointer<int> p; p.raw_ptr = fp_malloc(int, 10); assert(p.size() == 10); p.fill(42); fp_free(p.data());
- Template Parameters:
T – Element type
Derived – The derived class (CRTP pattern)
Subclassed by fp::pointer< char >
Unnamed Group
Unnamed Group
Unnamed Group
-
inline size_t length() const#
Get the number of elements.
fp::auto_free arr = fp::malloc<int>(50); std::cout << "Array has " << arr.length() << " elements\n"; // Use in loops for(size_t i = 0; i < arr.length(); i++) arr[i] = i;
Unnamed Group
-
inline T *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(50); // Manual iteration for(int* it = arr.begin(); it != arr.end(); ++it) *it = 42; // Use with STL algorithms std::iota(arr.begin(), arr.end(), 0); std::sort(arr.begin(), arr.end()); std::reverse(arr.begin(), arr.end()); // Distance size_t count = std::distance(arr.begin(), arr.end()); assert(count == arr.size());
Unnamed Group
-
inline T *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); arr.fill(1); // Range-based for loop for(int& val : arr) val *= 2; // Find operations auto it = std::find(arr.begin(), arr.end(), 42); if(it != arr.end()) std::cout << "Found at index: " << (it - arr.begin()) << "\n"; // Accumulate int sum = std::accumulate(arr.begin(), arr.end(), 0);
Unnamed Group
Unnamed Group
Unnamed Group
Public Functions
-
inline T *release()#
Release ownership of the pointer.
After calling release(), the pointer object no longer owns the memory. The caller becomes responsible for freeing it.
fp::auto_free arr = fp::malloc<int>(10).fill(42); // Transfer ownership int* raw = arr.release(); assert(arr.data() == nullptr); // Now we must manually free fp_free(raw);
- Returns:
The raw pointer (ownership transferred to caller)
-
inline bool is_fp() const#
Check if this is a valid fat pointer.
int regular[10]; fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; assert(arr.is_fp()); assert(!null_ptr.is_fp());
-
inline bool stack_allocated() const#
Check if this is stack-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(stack_arr.stack_allocated()); assert(!heap_arr.stack_allocated());
-
inline bool heap_allocated() const#
Check if this is heap-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(!stack_arr.heap_allocated()); assert(heap_arr.heap_allocated());
-
inline operator bool() const#
Check if pointer is non-null.
fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; if(arr) std::cout << "Array is valid\n"; if(!null_ptr) std::cout << "Null pointer\n"; // Safe access pattern if(arr && arr.size() > 0) arr[0] = 42;
-
inline bool empty() const#
Check if the pointer is empty.
fp::auto_free arr1 = fp::malloc<int>(10); fp::auto_free arr2 = fp::malloc<int>(0); assert(!arr1.empty()); assert(arr2.empty()); // Safe access pattern if(!arr1.empty()) arr1[0] = 42;
-
inline view_t view(size_t start, size_t length)#
Create a view of a portion of this pointer.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20-39 auto v = arr.view(20, 20); v.fill(999); assert(arr[20] == 999); assert(arr[39] == 999); assert(arr[19] != 999); // Outside view // Process data in chunks for(size_t i = 0; i < arr.size(); i += 10) { auto chunk = arr.view(i, 10); process_chunk(chunk); }
- Parameters:
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
inline view_t view_full()#
Create a view of the entire pointer.
fp::auto_free arr = fp::malloc<int>(50); // Create full view auto v = arr.view_full(); assert(v.size() == arr.size()); // Useful for passing to functions expecting views void process_view(fp::view<int> data) { for(auto& val : data) val *= 2; } process_view(arr.view_full());
- Returns:
View over all elements
-
inline view_t full_view()#
Alias for view_full.
fp::auto_free arr = fp::malloc<int>(50); // Both are equivalent auto v1 = arr.view_full(); auto v2 = arr.full_view(); assert(v1.size() == v2.size());
-
inline view_t view_start_end(size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10 through 20 (inclusive) - 11 elements auto v = arr.view_start_end(10, 20); assert(v.size() == 11); // Process quarters size_t quarter = arr.size() / 4; auto q1 = arr.view_start_end(0, quarter - 1); auto q2 = arr.view_start_end(quarter, 2 * quarter - 1); auto q3 = arr.view_start_end(2 * quarter, 3 * quarter - 1); auto q4 = arr.view_start_end(3 * quarter, arr.size() - 1);
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
inline const view_t view_start_end(size_t start, size_t end) const#
Create a view with start/end indices (const version)
-
inline T &front()#
Get reference to first element.
fp::auto_free arr = fp::malloc<int>(10).fill(5); arr.front() = 100; assert(arr[0] == 100); // Useful for algorithms int first = arr.front(); int last = arr.back();
-
inline T &back()#
Get reference to last element.
fp::auto_free arr = fp::malloc<int>(10); arr.fill(5); arr.back() = 999; assert(arr[arr.size() - 1] == 999); // Access both ends if(!arr.empty()) { arr.front() = 1; arr.back() = 100; }
-
inline Derived &fill(const T &value = {})#
Fill all elements with a value.
fp::auto_free arr = fp::malloc<int>(100); // Fill with specific value arr.fill(42); assert(arr[0] == 42); assert(arr[99] == 42); // Fill with default value (0 for int) arr.fill(); assert(arr[0] == 0); // Method chaining fp::auto_free data = fp::malloc<float>(50).fill(3.14f); // Fill with custom types struct Point { int x = 0, y = 0; }; fp::auto_free points = fp::malloc<Point>(10); points.fill(Point{5, 10});
- Parameters:
value – Value to fill with (default-constructed if not provided)
- Returns:
Reference to derived class for chaining
-
struct string : public fp::dynarray<char>, public fp::string_crtp<string>#
Subclassed by fp::auto_free< string >
Unnamed Group
-
inline T *data()#
Get raw pointer to data.
fp::auto_free arr = fp::malloc<int>(10); int* raw = arr.data(); // Use with C functions memset(raw, 0, arr.size() * sizeof(int)); // Pass to C APIs qsort(arr.data(), arr.size(), sizeof(int), compare_func);
Unnamed Group
-
inline T &operator*()#
Dereference operator.
- Returns:
Reference to the pointed-to value
Unnamed Group
-
inline T &operator*()
Dereference operator - access first element.
- Returns:
Reference to first element
Unnamed Group
-
inline T *operator->()#
Arrow operator for member access.
- Returns:
Raw pointer
Unnamed Group
-
inline T *operator->()
Arrow operator - access first element’s members.
- Returns:
Pointer to first element
Unnamed Group
-
inline explicit operator T*()#
Explicit conversion to raw pointer.
Requires explicit cast to prevent accidental implicit conversions.
fp::auto_free arr = fp::malloc<int>(10); // Explicit cast required int* ptr = (int*)arr; // Won't compile (good!): // int* ptr2 = arr;
Unnamed Group
-
inline size_t length() const#
Get the number of elements.
fp::auto_free arr = fp::malloc<int>(50); std::cout << "Array has " << arr.length() << " elements\n"; // Use in loops for(size_t i = 0; i < arr.length(); i++) arr[i] = i;
Unnamed Group
-
inline T *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(50); // Manual iteration for(int* it = arr.begin(); it != arr.end(); ++it) *it = 42; // Use with STL algorithms std::iota(arr.begin(), arr.end(), 0); std::sort(arr.begin(), arr.end()); std::reverse(arr.begin(), arr.end()); // Distance size_t count = std::distance(arr.begin(), arr.end()); assert(count == arr.size());
Unnamed Group
-
inline T *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); arr.fill(1); // Range-based for loop for(int& val : arr) val *= 2; // Find operations auto it = std::find(arr.begin(), arr.end(), 42); if(it != arr.end()) std::cout << "Found at index: " << (it - arr.begin()) << "\n"; // Accumulate int sum = std::accumulate(arr.begin(), arr.end(), 0);
Unnamed Group
-
inline T &operator[](size_t i)#
Subscript operator - access element by index.
Note
Bounds checked in debug!
- Parameters:
i – Index
- Returns:
Reference to element at index
Public Types
-
using view_t = fp::view<T>#
View type for this pointer.
Public Functions
-
inline operator dynarray<std::add_const_t<char>>() const#
Implicit conversion to const dynarray.
Allows passing non-const arrays to functions expecting const arrays.
void print_numbers(const fp::dynarray<const int>& arr) { for(auto& n : arr) std::cout << n << " "; } fp::dynarray<int> numbers = {1, 2, 3}; print_numbers(numbers); // Implicit conversion numbers.free();
-
inline operator pointer<std::add_const_t<T>>() const#
Implicit conversion to const pointer.
Allows passing non-const pointers to functions expecting const pointers.
void print_data(fp::pointer<const int> data) { for(size_t i = 0; i < data.size(); i++) { std::cout << data[i] << " "; } } fp::auto_release arr = fp::malloc<int>(5).fill(42); print_data(arr); // Implicit conversion
-
inline void free(bool nullify = true)#
Free the allocated memory.
Releases the memory allocated for this fat pointer. By default, the internal pointer is set to nullptr after freeing to prevent use-after-free bugs.
This is the preferred method for freeing memory as it provides safety by default. The pointer object remains valid but will be null after this call.
fp::pointer<int> arr = fp::malloc<int>(20); // Default: nullifies after free arr.free(); assert(arr.data() == nullptr); // Explicit: don't nullify (use with caution) fp::pointer<int> arr2 = fp::malloc<int>(20); arr2.free(false); // arr2.data() is now a dangling pointer - DANGEROUS! // Better: use default behavior fp::pointer<int> arr3 = fp::malloc<int>(20); arr3.free(true); // Explicit, but default
RAII Dynarray Usage#
// If you don't want to call free() manually, use RAII { fp::raii::pointer<int> auto_arr = fp::malloc<int>(100); // or fp::auto_free auto_arr = ... // Use auto_arr... // Automatically freed when scope exits }
See also
fp::raii::pointer for automatic memory management
Warning
After calling free(), any views or references to the data become invalid.
Warning
Only call free() on heap-allocated pointers, not stack-allocated ones.
- Parameters:
nullify – If true, sets the internal pointer to nullptr after freeing (default: true)
-
inline void free() const#
Free the allocated memory (const version)
This overload is provided for const pointers and does not nullify the internal pointer. Use with extreme caution as the pointer will be left in a dangling state.
This overload exists primarily for compatibility with const contexts, but its use is discouraged. Consider restructuring your code to avoid freeing through const references.
// Dangerous usage (avoid if possible) void unsafe_free(const fp::pointer<int>& arr) { arr.free(); // Calls const version // arr.data() is now dangling but we can't nullify it }
See also
free(bool) for the safer, non-const version
Warning
This version does not nullify the pointer, making it dangerous. Prefer the non-const version whenever possible.
Warning
The pointer becomes invalid but the const object cannot be modified.
-
inline void free(bool nullify = true)
Free the dynamic array.
Calls destructors for non-trivial types before freeing memory.
fp::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); strings.free(); // Destructors called, memory freed, ptr nulled assert(!strings);- Parameters:
nullify – If true, sets pointer to null (default: true)
-
inline void free() const
Free the dynamic array (const version)
Warning
Does not nullify pointer. Prefer non-const version.
-
inline pointer &realloc(size_t new_count)#
Reallocate with a new size.
Existing data is preserved up to the minimum of old and new sizes. The pointer address may change, but the reference is updated automatically.
fp::pointer<int> arr = fp::malloc<int>(10); for(size_t i = 0; i < arr.size(); i++) arr[i] = i; // Expand to 20 elements (first 10 preserved) arr.realloc(20); assert(arr.size() == 20); assert(arr[5] == 5); // Old data still there // Shrink to 5 elements arr.realloc(5); assert(arr.size() == 5); arr.free();
- Parameters:
new_count – New number of elements
- Returns:
Reference to this pointer (may have new address)
-
inline pointer clone() const#
Create a copy of this pointer.
Creates an independent copy of the data. Modifications to the clone do not affect the original.
fp::auto_free original = fp::malloc<int>(5).fill(42); fp::pointer<int> copy = original.clone(); copy[0] = 99; // Doesn't affect original assert(original[0] == 42); assert(copy[0] == 99); copy.free();
- Returns:
New pointer with copied data (must be freed separately)
-
inline Derived clone() const
Create a copy of this array.
fp::raii::dynarray<int> original; original.push_back(1); original.push_back(2); original.push_back(3); fp::raii::dynarray<int> copy = original.clone(); copy[0] = 999; // Doesn't affect original assert(original[0] == 1); assert(copy[0] == 999);
- Returns:
New array with copied data
-
inline T *data()
Get the raw pointer.
-
inline const T *data() const#
Get the raw pointer (const version)
-
inline T *release()#
Release ownership of the pointer.
After calling release(), the pointer object no longer owns the memory. The caller becomes responsible for freeing it.
fp::auto_free arr = fp::malloc<int>(10).fill(42); // Transfer ownership int* raw = arr.release(); assert(arr.data() == nullptr); // Now we must manually free fp_free(raw);
- Returns:
The raw pointer (ownership transferred to caller)
-
inline bool is_fp() const#
Check if this is a valid fat pointer.
int regular[10]; fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; assert(arr.is_fp()); assert(!null_ptr.is_fp());
-
inline bool stack_allocated() const#
Check if this is stack-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(stack_arr.stack_allocated()); assert(!heap_arr.stack_allocated());
-
inline bool heap_allocated() const#
Check if this is heap-allocated.
fp::array<int, 10> stack_arr; fp::auto_free heap_arr = fp::malloc<int>(10); assert(!stack_arr.heap_allocated()); assert(heap_arr.heap_allocated());
-
inline operator bool() const#
Check if pointer is non-null.
fp::auto_free arr = fp::malloc<int>(10); fp::pointer<int> null_ptr; if(arr) std::cout << "Array is valid\n"; if(!null_ptr) std::cout << "Null pointer\n"; // Safe access pattern if(arr && arr.size() > 0) arr[0] = 42;
-
inline bool empty() const#
Check if the pointer is empty.
fp::auto_free arr1 = fp::malloc<int>(10); fp::auto_free arr2 = fp::malloc<int>(0); assert(!arr1.empty()); assert(arr2.empty()); // Safe access pattern if(!arr1.empty()) arr1[0] = 42;
-
inline view_t view(size_t start, size_t length)#
Create a view of a portion of this pointer.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20-39 auto v = arr.view(20, 20); v.fill(999); assert(arr[20] == 999); assert(arr[39] == 999); assert(arr[19] != 999); // Outside view // Process data in chunks for(size_t i = 0; i < arr.size(); i += 10) { auto chunk = arr.view(i, 10); process_chunk(chunk); }
- Parameters:
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
inline view_t view_full()#
Create a view of the entire pointer.
fp::auto_free arr = fp::malloc<int>(50); // Create full view auto v = arr.view_full(); assert(v.size() == arr.size()); // Useful for passing to functions expecting views void process_view(fp::view<int> data) { for(auto& val : data) val *= 2; } process_view(arr.view_full());
- Returns:
View over all elements
-
inline view_t full_view()#
Alias for view_full.
fp::auto_free arr = fp::malloc<int>(50); // Both are equivalent auto v1 = arr.view_full(); auto v2 = arr.full_view(); assert(v1.size() == v2.size());
-
inline view_t view_start_end(size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10 through 20 (inclusive) - 11 elements auto v = arr.view_start_end(10, 20); assert(v.size() == 11); // Process quarters size_t quarter = arr.size() / 4; auto q1 = arr.view_start_end(0, quarter - 1); auto q2 = arr.view_start_end(quarter, 2 * quarter - 1); auto q3 = arr.view_start_end(2 * quarter, 3 * quarter - 1); auto q4 = arr.view_start_end(3 * quarter, arr.size() - 1);
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
inline const view_t view_start_end(size_t start, size_t end) const#
Create a view with start/end indices (const version)
-
inline T &front()#
Get reference to first element.
fp::auto_free arr = fp::malloc<int>(10).fill(5); arr.front() = 100; assert(arr[0] == 100); // Useful for algorithms int first = arr.front(); int last = arr.back();
-
inline T &back()#
Get reference to last element.
fp::auto_free arr = fp::malloc<int>(10); arr.fill(5); arr.back() = 999; assert(arr[arr.size() - 1] == 999); // Access both ends if(!arr.empty()) { arr.front() = 1; arr.back() = 100; }
-
inline pointer<T> &fill(const T &value = {})#
Fill all elements with a value.
fp::auto_free arr = fp::malloc<int>(100); // Fill with specific value arr.fill(42); assert(arr[0] == 42); assert(arr[99] == 42); // Fill with default value (0 for int) arr.fill(); assert(arr[0] == 0); // Method chaining fp::auto_free data = fp::malloc<float>(50).fill(3.14f); // Fill with custom types struct Point { int x = 0, y = 0; }; fp::auto_free points = fp::malloc<Point>(10); points.fill(Point{5, 10});
- Parameters:
value – Value to fill with (default-constructed if not provided)
- Returns:
Reference to derived class for chaining
-
inline bool is_dynarray() const#
Check if this is a valid dynamic array.
fp::raii::dynarray<int> arr; assert(!arr.is_dynarray()); // Empty/null arr.push_back(42); assert(arr.is_dynarray()); // Now valid
- Returns:
true if this is a dynamic array
-
inline size_t capacity() const#
Get allocated capacity.
fp::raii::dynarray<int> arr; arr.reserve(50); assert(arr.capacity() == 50); assert(arr.size() == 0); arr.push_back(1); assert(arr.capacity() == 50); // No reallocation
- Returns:
Number of elements that can be stored without reallocation
-
inline Derived &reserve(size_t size)#
Reserve capacity for at least size elements.
fp::raii::dynarray<int> arr; // Reserve and chain operations arr.reserve(1000) .push_back(42); arr.push_back(99); // No reallocations for next 998 elements
- Parameters:
size – Minimum capacity to reserve
- Returns:
Reference to this array for chaining
-
inline Derived &grow(size_t to_add, const T &value = {})#
Grow array by adding initialized elements.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); // Add 5 elements, all initialized to 99 arr.grow(5, 99); assert(arr.size() == 7); assert(arr[2] == 99);
- Parameters:
to_add – Number of elements to add
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline Derived &grow_uninitialized(size_t to_add)#
Grow array with uninitialized elements.
New elements are uninitialized - you must initialize them before use. Useful for performance when you’ll immediately overwrite values.
fp::raii::dynarray<int> arr; arr.push_back(1); size_t old_size = arr.size(); arr.grow_uninitialized(10); // Initialize new elements for(size_t i = old_size; i < arr.size(); i++) arr[i] = i * 10;
- Parameters:
to_add – Number of elements to add
- Returns:
Reference to this array for chaining
-
inline Derived &grow_to_size(size_t size, const T &value = {})#
Grow to exact size with initialized elements.
fp::raii::dynarray<float> data; data.grow_to_size(100, 3.14f); assert(data.size() == 100); for(auto& val : data) assert(val == 3.14f);
Note
If size is smaller than the current size, this function does nothing!
- Parameters:
size – Target size
value – Value to initialize new elements with (default-constructed if omitted)
- Returns:
Reference to this array for chaining
-
inline Derived &grow_to_size_uninitialized(size_t size)#
Grow to exact size with uninitialized elements.
- Parameters:
size – Target size
- Returns:
Reference to this array for chaining
-
inline T &push_back(const T &value)#
Add element to end of array.
fp::raii::dynarray<std::string> names; names.push_back("Alice"); names.push_back("Bob"); std::string& ref = names.push_back("Charlie"); ref += " Smith"; // Modify in place assert(names[2] == "Charlie Smith");
- Parameters:
value – Value to add
- Returns:
Reference to the newly added element
-
template<typename ...Targs>
inline T &emplace_back(Targs... args)# Construct element in-place at end of array.
Constructs the element directly in the array without copying/moving.
struct Point { int x, y; Point(int x_, int y_) : x(x_), y(y_) {} }; fp::raii::dynarray<Point> points; // Construct directly in array points.emplace_back(10, 20); points.emplace_back(30, 40); assert(points[0].x == 10);
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to the newly constructed element
-
inline T &pop_back_n(size_t count)#
Remove last n elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.pop_back_n(3); assert(arr.size() == 7);
- Parameters:
count – Number of elements to remove
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &pop_back()#
Remove last element.
fp::raii::dynarray<int> stack; stack.push_back(10); stack.push_back(20); stack.push_back(30); stack.pop_back(); assert(stack.size() == 2); assert(stack.back() == 20);
- Returns:
Reference to removed element (now invalid)
-
inline T &pop_back_to_size(size_t size)#
Pop elements until size reaches target.
fp::raii::dynarray<int> arr; for(int i = 0; i < 100; i++) arr.push_back(i); arr.pop_back_to_size(50); assert(arr.size() == 50);
- Parameters:
size – Target size
- Returns:
Reference to first element removed (one after the new last element)
-
inline T &insert(size_t pos, const T &value = {})#
Insert element at position.
Elements after pos are shifted right. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); arr.push_back(4); arr.insert(2, 3); // arr: [1, 2, 3, 4] assert(arr[2] == 3);
- Parameters:
pos – Position to insert at
value – Value to insert (default-constructed if omitted)
- Returns:
Reference to inserted element
-
template<typename ...Targs>
inline T &emplace(size_t pos, Targs... args)# Construct element in-place at position.
Elements after pos are shifted right. O(n) operation.
struct Widget { int id; std::string name; Widget(int i, std::string n) : id(i), name(std::move(n)) {} }; fp::raii::dynarray<Widget> widgets; widgets.emplace_back(1, "First"); widgets.emplace_back(3, "Third"); widgets.emplace(1, 2, "Second"); // widgets: [(1,"First"), (2,"Second"), (3,"Third")]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
pos – Position to insert at
args – Constructor arguments
- Returns:
Reference to inserted element
-
inline T &push_front(const T &value = {})#
Insert element at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<int> deque; deque.push_front(3); deque.push_front(2); deque.push_front(1); // deque: [1, 2, 3] assert(deque[0] == 1);
- Parameters:
value – Value to insert
- Returns:
Reference to inserted element
-
template<typename ...Targs>
inline T &emplace_front(Targs... args)# Construct element in-place at front.
All current elements are shifted right. O(n) operation.
fp::raii::dynarray<std::string> list; list.emplace_front("World"); list.emplace_front("Hello"); // list: ["Hello", "World"]
- Template Parameters:
Targs – Constructor argument types
- Parameters:
args – Constructor arguments
- Returns:
Reference to newly constructed element
-
inline view<T> insert_uninitialized(size_t pos, size_t count = 1)#
Insert uninitialized elements.
Elements after pos are shifted right. O(n) operation.
fp::dynarray<int> arr; arr.push_back(1); arr.push_back(5); auto view = arr.insert_uninitialized(1, 3); view[0] = 2; view[1] = 3; view[2] = 4; // arr: [1, 2, 3, 4, 5]
- Parameters:
pos – Position to insert at
count – Number of elements to insert (default: 1)
- Returns:
View over the inserted uninitialized elements
-
inline Derived &delete_range(size_t pos, size_t count)#
Delete range of elements.
Elements after pos + count are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.delete_range(3, 4) .push_back(99); assert(arr.size() == 7);
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline Derived &delete_(size_t pos)#
Delete single element.
Elements after pos are shifted left. O(n) operation.
fp::raii::dynarray<int> arr; arr.push_back(1).push_back(2).push_back(3); arr.delete_(1); // arr: [1, 3]
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &remove(size_t pos)#
Alias for delete_.
-
inline Derived &delete_start_end(size_t start, size_t end)#
Delete range using start and end indices.
Elements after end are shifted left. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete_range(size_t pos, size_t count)#
Delete range and shrink capacity.
Like delete_range but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Starting position
count – Number of elements to delete
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete(size_t pos)#
Delete element and shrink capacity.
Like delete_ but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_delete_start_end(size_t start, size_t end)#
Delete range and shrink using start/end indices.
Like delete_start_end but also reallocates to free unused capacity. All elements are copied. O(n) operation.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline Derived &resize(size_t size)#
Resize array to new size.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.resize(20); // Grow assert(arr.size() == 20); arr.resize(5); // Shrink assert(arr.size() == 5);
- Parameters:
size – New size
- Returns:
Reference to this array for chaining
-
inline Derived &shrink_to_fit()#
Shrink capacity to match size.
fp::raii::dynarray<int> arr; arr.reserve(1000); for(int i = 0; i < 100; i++) arr.push_back(i); assert(arr.capacity() == 1000); arr.shrink_to_fit(); assert(arr.capacity() == 100);
- Returns:
Reference to this array for chaining
-
inline Derived &swap_range(size_t start1, size_t start2, size_t count)#
Swap two ranges of elements.
fp::raii::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_range(0, 7, 3); // Swapped [0,1,2] with [7,8,9]
- Parameters:
start1 – Start of first range
start2 – Start of second range
count – Number of elements to swap
- Returns:
Reference to this array for chaining
-
inline Derived &swap(size_t pos1, size_t pos2)#
Swap two elements.
fp::raii::dynarray<int> arr = {10, 20, 30}; arr.swap(0, 2); // arr: [30, 20, 10]
- Parameters:
pos1 – First position
pos2 – Second position
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete_range(size_t pos, size_t count)#
Swap range to end and delete.
O(1) deletion that doesn’t preserve order.
fp::dynarray<int> arr; for(int i = 0; i < 10; i++) arr.push_back(i); arr.swap_delete_range(2, 2); // Deleted elements at 2-3 by swapping with end assert(arr.size() == 8);
- Parameters:
pos – Starting position
count – Number of elements
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete(size_t pos)#
Swap element to end and delete.
Fast O(1) unordered deletion.
fp::dynarray<int> arr = {0, 10, 20, 30, 40}; arr.swap_delete(1); // arr: [0, 40, 20, 30] (40 moved to position 1)
- Parameters:
pos – Position to delete
- Returns:
Reference to this array for chaining
-
inline Derived &swap_delete_start_end(size_t start, size_t end)#
Swap range to end and delete using start/end indices.
O(1) deletion that doesn’t preserve order.
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Reference to this array for chaining
-
inline T &pop_front()#
Remove and return first element.
Shifts all elements left. O(n) operation.
fp::dynarray<int> queue; queue.push_back(1).push_back(2).push_back(3); queue.pop_front(); // queue: [2, 3]
- Returns:
Reference to removed element (now invalid)
-
inline Derived &clear()#
Clear all elements (keeps capacity)
Calls destructors for non-trivial types.
fp::raii::dynarray<std::string> strings; strings.push_back("Hello"); strings.push_back("World"); assert(strings.size() == 2); strings.clear(); assert(strings.size() == 0); assert(strings.capacity() > 0); // Capacity unchanged
- Returns:
Reference to this array for chaining
-
inline Derived &concatenate_view_in_place(const view<const T> view)#
Concatenate view to this array in place.
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; arr.concatenate_view_in_place({more, 3}); // arr: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
Reference to this array for chaining
-
inline Derived concatenate_view(const view<const T> view) const#
Concatenate view (returns new array)
fp::raii::dynarray<int> arr; arr.push_back(1); arr.push_back(2); int more[] = {3, 4, 5}; fp::raii::dynarray<int> combined = arr.concatenate_view({more, 3}); // combined: [1, 2, 3, 4, 5]
- Parameters:
view – View to append
- Returns:
New array with concatenated data
-
inline Derived &concatenate_in_place(const Derived &other)#
Concatenate other array to this one in place.
fp::raii::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); arr1.concatenate_in_place(arr2); // arr1: [1, 2, 3, 4] // arr2: [3, 4] (unchanged)
- Parameters:
other – Array to append
- Returns:
Reference to this array for chaining
-
inline Derived concatenate(const Derived &other) const#
Concatenate two arrays (returns new array)
fp::dynarray<int> arr1, arr2; arr1.push_back(1); arr1.push_back(2); arr2.push_back(3); arr2.push_back(4); fp::dynarray<int> combined = arr1.concatenate(arr2); // combined: [1, 2, 3, 4] // arr1 and arr2 unchanged
- Parameters:
other – Array to append
- Returns:
New array with concatenated data
Public Members
-
T *raw#
Raw pointer to data.
-
inline T *data()#
-
template<typename Derived>
struct string_crtp : public fp::string_crtp_common<Derived, Derived># Subclassed by fp::string
-
template<typename Derived, typename Dynamic>
struct string_crtp_common# Subclassed by fp::string_crtp< string >, fp::string_crtp< Derived >, fp::wrapped::string
-
struct string_view : public fp::view<char>#
Unnamed Group
-
inline char *data()#
Get pointer to the data.
fp::auto_free arr = fp::malloc<int>(10); fp::view<int> v = arr.view_full(); int* ptr = v.data(); ptr[0] = 42; // Direct pointer access // Pass to C functions qsort(v.data(), v.size(), sizeof(int), compare_func);
Unnamed Group
-
inline view<std::byte> byte_view()#
Create a byte view of this view’s memory.
struct Point { int x, y; }; fp::auto_free points = fp::malloc<Point>(10); fp::view<Point> v = points.view_full(); // Access raw bytes fp::view<std::byte> bytes = v.byte_view(); assert(bytes.size() == 10 * sizeof(Point)); // Useful for serialization void write_binary(fp::view<std::byte> data) { fwrite(data.data(), 1, data.size(), file); } write_binary(v.byte_view());
- Returns:
View of the underlying bytes
Unnamed Group
-
inline char &operator*()#
Dereference operator - access first element.
- Returns:
Reference to first element
Unnamed Group
-
inline char *operator->()#
Arrow operator - access first element’s members.
- Returns:
Pointer to first element
Unnamed Group
-
inline char &operator[](size_t i)#
Subscript operator - access element by index.
- Parameters:
i – Index
- Returns:
Reference to element at index
Public Functions
-
inline operator view<std::add_const_t<char>>() const#
Implicit conversion to const view.
Allows passing non-const views to functions expecting const views.
-
inline struct __fp_view &raw()#
Get the underlying C-style view.
fp::view<int> v = ...; fp_view(int)& c_style = v.raw(); // Can now use C-style fp_view functions
-
inline size_t length() const#
Get the number of elements in the view.
fp::auto_free arr = fp::malloc<int>(100); fp::view<int> v1 = arr.view(0, 50); fp::view<int> v2 = arr.view(50, 50); assert(v1.length() == 50); assert(v2.length() == 50); assert(v1.length() + v2.length() == arr.size());
-
inline size_t size() const#
Get the number of elements in the view (alias for length)
-
inline bool empty() const#
Check if the view is empty.
fp::auto_free arr = fp::malloc<int>(10); fp::view<int> full = arr.view_full(); assert(!full.empty()); fp::view<int> empty = arr.view(5, 0); assert(empty.empty()); if(!full.empty()) full[0] = 42; // Safe to access
-
inline view<char> subview(size_t start, size_t length) const#
Create a subview (const version)
-
inline view<char> subview(size_t start) const#
Create a subview from start to end (const version)
-
inline view<char> subview_max_size(size_t start, size_t length) const#
Create a subview with max size (const version)
-
inline view<char> subview_start_end(size_t start, size_t end) const#
Create a subview with start/end indices (const version)
-
inline char *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(10); fp::view<int> v = arr.view_full(); // Manual iteration for(int* it = v.begin(); it != v.end(); ++it) *it = 42; // Use with STL algorithms std::sort(v.begin(), v.end()); std::reverse(v.begin(), v.end());
-
inline char *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); fp::view<int> v = arr.view_full(); // Find first element > 50 auto it = std::find_if(v.begin(), v.end(), [](int x) { return x > 50; }); if(it != v.end()) std::cout << "Found: " << *it << "\n";
-
inline size_t compare(const view other) const#
Compare this view with another.
fp::auto_free arr1 = fp::malloc<int>(5); fp::auto_free arr2 = fp::malloc<int>(5); arr1.fill(1); arr2.fill(2); fp::view<int> v1 = arr1.view_full(); fp::view<int> v2 = arr2.view_full(); auto result = v1.compare(v2); if(result < 0) std::cout << "v1 < v2\n"; else if(result > 0) std::cout << "v1 > v2\n"; else std::cout << "v1 == v2\n";
- Parameters:
other – View to compare with
- Returns:
Comparison result (negative, 0, or positive)
-
inline std::strong_ordering operator<=>(const view o) const#
Three-way comparison operator.
fp::auto_free arr1 = fp::malloc<int>(5); fp::auto_free arr2 = fp::malloc<int>(5); arr1.fill(10); arr2.fill(20); fp::view<int> v1 = arr1.view_full(); fp::view<int> v2 = arr2.view_full(); if(v1 < v2) std::cout << "v1 is less\n"; if(v1 <= v2) std::cout << "v1 is less or equal\n"; if(v1 > v2) std::cout << "v1 is greater\n";
- Parameters:
o – View to compare with
- Returns:
std::strong_ordering result
-
inline bool operator==(const view o) const#
Equality comparison.
fp::auto_free arr1 = fp::malloc<int>(5); fp::auto_free arr2 = fp::malloc<int>(5); arr1.fill(42); arr2.fill(42); fp::view<int> v1 = arr1.view_full(); fp::view<int> v2 = arr2.view_full(); if(v1 == v2) std::cout << "Views contain identical data\n";
- Parameters:
o – View to compare with
- Returns:
true if views are equal
Public Static Functions
-
static inline view make(char *p, size_t start, size_t length)#
Create a view from a fat pointer with start index and length.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10-29 (20 elements starting at index 10) fp::view<int> v = fp::view<int>::make(arr.data(), 10, 20); assert(v.size() == 20); // Modify through view for(size_t i = 0; i < v.size(); i++) { v[i] = 999; } assert(arr[10] == 999); // Original array modified
- Parameters:
p – Fat pointer
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
static inline view make_full(char *p)#
Create a view over an entire fat pointer.
fp::auto_free data = fp::malloc<float>(50); data.fill(3.14f); // Create view of entire array fp::view<float> full = fp::view<float>::make_full(data.data()); assert(full.size() == 50); // View references original data full[0] = 2.71f; assert(data[0] == 2.71f);
- Parameters:
p – Fat pointer
- Returns:
View covering all elements
-
static inline view make_start_end(char *p, size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20 through 30 (inclusive) - 11 elements total fp::view<int> v = fp::view<int>::make_start_end(arr.data(), 20, 30); assert(v.size() == 11); v.fill(42); assert(arr[20] == 42); assert(arr[30] == 42);
- Parameters:
p – Fat pointer
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
static inline view from_variable(char &var)#
Create a view from a single variable.
int x = 42; fp::view<int> v = fp::view<int>::from_variable(x); assert(v.size() == 1); assert(v[0] == 42); v[0] = 99; assert(x == 99); // Variable modified through view // Useful for generic functions template<typename T> void process_view(fp::view<T> data) { for(auto& val : data) val *= 2; } int single = 10; process_view(fp::view<int>::from_variable(single)); assert(single == 20);
- Parameters:
var – Variable to view
- Returns:
View with size 1
-
inline char *data()#
- template<typename T> fp::fp::view : public struct __fp_view
- #include <pointer.hpp>
Non-owning view (fp::view) over a contiguous sequence of elements.
A view is a lightweight, non-owning reference to a contiguous block of memory. It stores a pointer and size but does not manage the lifetime of the data. Views support subviews, iteration, and conversion to/from std::span (if previously included).
fp::auto_free arr = fp::malloc<int>(100); // Create view of entire array fp::view<int> full = fp::view<int>::make_full(arr.data()); // Create view of subset fp::view<int> partial = full.subview(10, 20); // Iterate for(int& val : partial) val = 2; // Access elements partial[0] = 999;
- Template Parameters:
T – Element type
Unnamed Group
-
inline T *data()#
Get pointer to the data.
fp::auto_free arr = fp::malloc<int>(10); fp::view<int> v = arr.view_full(); int* ptr = v.data(); ptr[0] = 42; // Direct pointer access // Pass to C functions qsort(v.data(), v.size(), sizeof(int), compare_func);
Unnamed Group
-
inline view<std::byte> byte_view()#
Create a byte view of this view’s memory.
struct Point { int x, y; }; fp::auto_free points = fp::malloc<Point>(10); fp::view<Point> v = points.view_full(); // Access raw bytes fp::view<std::byte> bytes = v.byte_view(); assert(bytes.size() == 10 * sizeof(Point)); // Useful for serialization void write_binary(fp::view<std::byte> data) { fwrite(data.data(), 1, data.size(), file); } write_binary(v.byte_view());
- Returns:
View of the underlying bytes
Unnamed Group
-
inline T &operator*()#
Dereference operator - access first element.
- Returns:
Reference to first element
Unnamed Group
-
inline T *operator->()#
Arrow operator - access first element’s members.
- Returns:
Pointer to first element
Unnamed Group
-
inline T &operator[](size_t i)#
Subscript operator - access element by index.
- Parameters:
i – Index
- Returns:
Reference to element at index
Public Functions
-
inline operator view<std::add_const_t<T>>() const#
Implicit conversion to const view.
Allows passing non-const views to functions expecting const views.
-
inline struct __fp_view &raw()#
Get the underlying C-style view.
fp::view<int> v = ...; fp_view(int)& c_style = v.raw(); // Can now use C-style fp_view functions
-
inline size_t length() const#
Get the number of elements in the view.
fp::auto_free arr = fp::malloc<int>(100); fp::view<int> v1 = arr.view(0, 50); fp::view<int> v2 = arr.view(50, 50); assert(v1.length() == 50); assert(v2.length() == 50); assert(v1.length() + v2.length() == arr.size());
-
inline size_t size() const#
Get the number of elements in the view (alias for length)
-
inline bool empty() const#
Check if the view is empty.
fp::auto_free arr = fp::malloc<int>(10); fp::view<int> full = arr.view_full(); assert(!full.empty()); fp::view<int> empty = arr.view(5, 0); assert(empty.empty()); if(!full.empty()) full[0] = 42; // Safe to access
-
inline view subview(size_t start, size_t length)#
Create a subview with specified start and length.
fp::auto_free arr = fp::malloc<int>(100); fp::view<int> v = arr.view_full(); // Create subview of elements 10-29 fp::view<int> sub = v.subview(10, 20); assert(sub.size() == 20); // Subviews can be chained fp::view<int> subsub = sub.subview(5, 10); assert(subsub.size() == 10); // All views reference the same data subsub[0] = 999; assert(arr[15] == 999); // 10 + 5 = index 15 in original
- Parameters:
start – Starting index
length – Number of elements
- Returns:
Subview of this view
-
inline view subview_max_size(size_t start, size_t length)#
Create a subview with maximum available length.
fp::auto_free arr = fp::malloc<int>(100); fp::view<int> v = arr.view_full(); // Request 30 elements starting at index 80 // Only 20 available, so view will have 20 elements fp::view<int> clamped = v.subview_max_size(80, 30); assert(clamped.size() == 20); // Clamped to available size // Useful when you don't know exact bounds for(size_t i = 0; i < v.size(); i += 25) { fp::view<int> chunk = v.subview_max_size(i, 25); process_chunk(chunk); // Always valid, size may vary }
- Parameters:
start – Starting index
length – Maximum number of elements (clamped to available size)
- Returns:
Subview of this view
-
inline view subview(size_t start)#
Create a subview from start to end of view.
fp::pointer<int> arr = fp::malloc<int>(100); fp::view<int> v = arr.view_full(); // Get everything from index 50 to end fp::view<int> tail = v.subview(50); assert(tail.size() == 50); // Useful for skipping a header struct Header { int magic; size_t count; }; fp::pointer<char> buffer = fp::malloc<char>(1024); fp::view<char> v_buf = buffer.view_full(); // Skip header and get remaining data fp::view<char> data = v_buf.subview(sizeof(Header)); buffer.free(); arr.free();
- Parameters:
start – Starting index
- Returns:
Subview from start to end
-
inline view subview_start_end(size_t start, size_t end)#
Create a subview using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); fp::view<int> v = arr.view_full(); // Elements 20 through 30 (inclusive) - 11 elements fp::view<int> sub = v.subview_start_end(20, 30); assert(sub.size() == 11); // Split view into thirds size_t third = v.size() / 3; fp::view<int> first = v.subview_start_end(0, third - 1); fp::view<int> second = v.subview_start_end(third, 2 * third - 1); fp::view<int> third_part = v.subview_start_end(2 * third, v.size() - 1);
- Parameters:
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
Subview over the range [start, end]
-
inline view<T> subview(size_t start, size_t length) const#
Create a subview (const version)
-
inline view<T> subview_max_size(size_t start, size_t length) const#
Create a subview with max size (const version)
-
inline view<T> subview(size_t start) const#
Create a subview from start to end (const version)
-
inline view<T> subview_start_end(size_t start, size_t end) const#
Create a subview with start/end indices (const version)
-
inline T *begin()#
Get iterator to beginning.
fp::auto_free arr = fp::malloc<int>(10); fp::view<int> v = arr.view_full(); // Manual iteration for(int* it = v.begin(); it != v.end(); ++it) *it = 42; // Use with STL algorithms std::sort(v.begin(), v.end()); std::reverse(v.begin(), v.end());
-
inline T *end()#
Get iterator to end.
fp::auto_free arr = fp::malloc<int>(100); fp::view<int> v = arr.view_full(); // Find first element > 50 auto it = std::find_if(v.begin(), v.end(), [](int x) { return x > 50; }); if(it != v.end()) std::cout << "Found: " << *it << "\n";
-
inline size_t compare(const view other) const#
Compare this view with another.
fp::auto_free arr1 = fp::malloc<int>(5); fp::auto_free arr2 = fp::malloc<int>(5); arr1.fill(1); arr2.fill(2); fp::view<int> v1 = arr1.view_full(); fp::view<int> v2 = arr2.view_full(); auto result = v1.compare(v2); if(result < 0) std::cout << "v1 < v2\n"; else if(result > 0) std::cout << "v1 > v2\n"; else std::cout << "v1 == v2\n";
- Parameters:
other – View to compare with
- Returns:
Comparison result (negative, 0, or positive)
-
inline std::strong_ordering operator<=>(const view o) const#
Three-way comparison operator.
fp::auto_free arr1 = fp::malloc<int>(5); fp::auto_free arr2 = fp::malloc<int>(5); arr1.fill(10); arr2.fill(20); fp::view<int> v1 = arr1.view_full(); fp::view<int> v2 = arr2.view_full(); if(v1 < v2) std::cout << "v1 is less\n"; if(v1 <= v2) std::cout << "v1 is less or equal\n"; if(v1 > v2) std::cout << "v1 is greater\n";
- Parameters:
o – View to compare with
- Returns:
std::strong_ordering result
-
inline bool operator==(const view o) const#
Equality comparison.
fp::auto_free arr1 = fp::malloc<int>(5); fp::auto_free arr2 = fp::malloc<int>(5); arr1.fill(42); arr2.fill(42); fp::view<int> v1 = arr1.view_full(); fp::view<int> v2 = arr2.view_full(); if(v1 == v2) std::cout << "Views contain identical data\n";
- Parameters:
o – View to compare with
- Returns:
true if views are equal
Public Static Functions
-
static inline view make(T *p, size_t start, size_t length)#
Create a view from a fat pointer with start index and length.
fp::auto_free arr = fp::malloc<int>(100); // View elements 10-29 (20 elements starting at index 10) fp::view<int> v = fp::view<int>::make(arr.data(), 10, 20); assert(v.size() == 20); // Modify through view for(size_t i = 0; i < v.size(); i++) { v[i] = 999; } assert(arr[10] == 999); // Original array modified
- Parameters:
p – Fat pointer
start – Starting index
length – Number of elements
- Returns:
View over the specified range
-
static inline view make_full(T *p)#
Create a view over an entire fat pointer.
fp::auto_free data = fp::malloc<float>(50); data.fill(3.14f); // Create view of entire array fp::view<float> full = fp::view<float>::make_full(data.data()); assert(full.size() == 50); // View references original data full[0] = 2.71f; assert(data[0] == 2.71f);
- Parameters:
p – Fat pointer
- Returns:
View covering all elements
-
static inline view make_start_end(T *p, size_t start, size_t end)#
Create a view using start and end indices.
fp::auto_free arr = fp::malloc<int>(100); // View elements 20 through 30 (inclusive) - 11 elements total fp::view<int> v = fp::view<int>::make_start_end(arr.data(), 20, 30); assert(v.size() == 11); v.fill(42); assert(arr[20] == 42); assert(arr[30] == 42);
- Parameters:
p – Fat pointer
start – Starting index (inclusive)
end – Ending index (inclusive)
- Returns:
View over the range [start, end]
-
static inline view from_variable(T &var)#
Create a view from a single variable.
int x = 42; fp::view<int> v = fp::view<int>::from_variable(x); assert(v.size() == 1); assert(v[0] == 42); v[0] = 99; assert(x == 99); // Variable modified through view // Useful for generic functions template<typename T> void process_view(fp::view<T> data) { for(auto& val : data) val *= 2; } int single = 10; process_view(fp::view<int>::from_variable(single)); assert(single == 20);
- Parameters:
var – Variable to view
- Returns:
View with size 1