Welcome to LibFP’s Documentorial!#
This documentation page is designed less like a direct reference and more like a tutorial.
If you would instead prefer a reference… full generated documentation can be found here.
LibFP pointers are designed to be fully compliant C pointers.
int* x = fp_malloc(int, 10);
fp_free_and_null(x);
Additionally we provide a C++ wrapper around our C apis:
-
template<typename T>
struct pointer : public fp::wrapped::pointer<T>, public fp::pointer_crtp<T, pointer<T>> Main fat pointer class 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_and_null(); // Preferred over .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_and_null(); // ERROR: Using 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_and_null();
- 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()#
Free the allocated memory.
fp::pointer<int> arr = fp::malloc<int>(10); arr.free(); // arr is now invalid - do not use!
Warning
Pointer becomes invalid after this call. Accessing it is undefined behavior. Consider using free_and_null() for safer cleanup.
-
inline void free_and_null()#
Free the allocated memory and set pointer to null.
Safer than free() as it prevents use-after-free by nulling the pointer.
fp::pointer<int> arr = fp::malloc<int>(10); arr.free_and_null(); assert(arr.data() == nullptr); assert(!arr); // Boolean conversion returns false
-
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_and_null();
- 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_and_null();
- 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
If desirable there is also a stack allocated version (comparable to std::array):
-
template<typename T, size_t N>
struct array : public fp::pointer_crtp<T, array<T, N>> Fixed-size 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 Integration#
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.