Compare commits
2 Commits
7de4fbdd4f
...
23dea850c4
| Author | SHA1 | Date | |
|---|---|---|---|
| 23dea850c4 | |||
| a1fdf5f0c6 |
@@ -1,3 +1,4 @@
|
||||
# marigold_dynamic_array
|
||||
# marigold_vector
|
||||
|
||||
dynamic_array implementation in C (likely will be C99 or C17) with toggle-able thread-safety via mutex locks.
|
||||
vector datatype (dynamic/static array) implementation in C99 with toggle-able thread-safety via mutex locks.
|
||||
designed to fit within 1 cache line (at or under 64btes on a 64bit system, and at or under 32bytes on a 32bit system.)
|
||||
|
||||
@@ -1,594 +0,0 @@
|
||||
#ifndef MARIGOLD_DYNAMIC_ARRAY_H
|
||||
#define MARIGOLD_DYNAMIC_ARRAY_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum
|
||||
dynamic_array_flag_enum
|
||||
{
|
||||
dynamic_array_multithread_safe = 1 << 0,
|
||||
dynamic_array_read_only = 1 << 1,
|
||||
dynamic_array_certainly_sorted = 1 << 2,
|
||||
dynamic_array_marked_for_free = 1 << 3,
|
||||
dynamic_array_debug_has_function_call_rolled_over = 1 << 4,
|
||||
dynamic_array_debug_has_owner_count_rolled_over = 1 << 5,
|
||||
dynamic_array_debug_has_been_resized = 1 << 6,
|
||||
dynamic_array_debug_has_been_resized_rolled_over = 1 << 7
|
||||
}
|
||||
dynamic_array_flag_enum;
|
||||
|
||||
typedef enum
|
||||
dynamic_array_growth_rate_enum
|
||||
{
|
||||
dynamic_array_growth_static = 0,
|
||||
dynamic_array_growth_linear = 1,
|
||||
dynamic_array_growth_double = 2,
|
||||
dynamic_array_growth_triple = 3,
|
||||
dynamic_array_growth_quadruple = 4,
|
||||
dynamic_array_growth_quintuple = 5
|
||||
}
|
||||
dynamic_array_growth_rate_enum;
|
||||
|
||||
typedef struct
|
||||
dynamic_array_struct
|
||||
{
|
||||
size_t item_size;
|
||||
size_t current_capacity;
|
||||
size_t current_occupancy;
|
||||
void* data_pointer;
|
||||
int (*comparator)(const void *, const void *);
|
||||
void (*item_free)(const void *);
|
||||
pthread_mutex_t* mutex_lock;
|
||||
unsigned short owner_count;
|
||||
uint8_t growth_strategy;
|
||||
uint8_t flags;
|
||||
#ifdef MARIGOLD_DEBUG
|
||||
uint8_t debug_flags;
|
||||
uint32_t debug_resize_count;
|
||||
uint32_t debug_function_call_count;
|
||||
uint32_t debug_last_error_code;
|
||||
uint32_t debug_allocation_failures;
|
||||
|
||||
#endif // MARIGOLD_DEBUG.
|
||||
}
|
||||
dynamic_array_struct;
|
||||
|
||||
/**
|
||||
* @brief Create a new dynamic array, it then internally does all the
|
||||
* initialization.
|
||||
*
|
||||
* Creates a dynamic array with the specified item size and starting capacity.
|
||||
* The growth_strategy determines how the array expands when capacity is
|
||||
* exceeded.
|
||||
*
|
||||
* If is_multithread_safe is true, the internal mutex is created and initialized
|
||||
* here.
|
||||
*
|
||||
* @param item_size Size of each element in bytes.
|
||||
* @param starting_capacity Initial number of elements to allocate space for.
|
||||
* @param growth_strategy Growth strategy enum.
|
||||
* @param comparator Function to compare two elements. May be NULL if not
|
||||
* needed.
|
||||
* @param is_multithread_safe If true, enables thread-safe operations.
|
||||
* @return Pointer to the initialized dynamic_array, or NULL on failure.
|
||||
*/
|
||||
dynamic_array_struct*
|
||||
dynamic_array_create(size_t item_size,
|
||||
size_t starting_capacity,
|
||||
dynamic_array_growth_rate_enum growth_rate,
|
||||
int (*comparator)(const void*, const void*),
|
||||
void (*item_free)(const void *),
|
||||
bool is_multithread_safe);
|
||||
|
||||
/**
|
||||
* @brief Explicitly destroy the dynamic array and free its memory.
|
||||
*
|
||||
* Checks the owner count. If it is 0 or 1, deallocates the internal memory
|
||||
* and the struct itself. Use this for explicit cleanup. For reference-counted
|
||||
* shared ownership, prefer dynamic_array_release().
|
||||
*
|
||||
* If the array is thread-safe, the internal mutex is destroyed and freed here.
|
||||
*
|
||||
* @param array_to_destroy is the dynamic array being deallocated/destroyed.
|
||||
* @return true on successful destroy, false on failure.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_destroy(dynamic_array_struct* array_to_destroy);
|
||||
|
||||
/**
|
||||
* @brief Set or clear a specific flag on the dynamic array.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param flag The flag to modify.
|
||||
* @param value true to set the flag, false to clear it.
|
||||
*/
|
||||
void
|
||||
dynamic_array_set_flag(dynamic_array_struct* array,
|
||||
dynamic_array_flag_enum flag,
|
||||
bool value);
|
||||
|
||||
/**
|
||||
* @brief Get a specific flag on the dynamic array.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param flag The flag to get.
|
||||
*
|
||||
* @return value of flag as bool (true or false)
|
||||
*/
|
||||
bool
|
||||
dynamic_array_get_flag_value(const dynamic_array_struct* array,
|
||||
dynamic_array_flag_enum flag);
|
||||
|
||||
/**
|
||||
* @brief Get the number of elements currently in the array.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return Number of elements (current_occupancy).
|
||||
*/
|
||||
size_t
|
||||
dynamic_array_get_occupancy(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Get the total capacity of the array.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return Total capacity (current_capacity).
|
||||
*/
|
||||
size_t
|
||||
dynamic_array_get_capacity(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the element at the specified index.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param index Index of the element to access.
|
||||
* @return Pointer to the element, or NULL if index is out of bounds.
|
||||
*/
|
||||
void*
|
||||
dynamic_array_get_pointer_to_index(dynamic_array_struct* array,
|
||||
size_t index);
|
||||
|
||||
/**
|
||||
* @brief Get a const pointer to the element at the specified index.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param index Index of the element to access.
|
||||
* @return Const pointer to the element, or NULL if index is out of bounds.
|
||||
*/
|
||||
const void*
|
||||
dynamic_array_get_const_pointer_to_index(const dynamic_array_struct* array,
|
||||
size_t index);
|
||||
|
||||
/**
|
||||
* @brief Get a direct pointer to the underlying memory block.
|
||||
*
|
||||
* Useful for direct iteration or passing to C APIs expecting raw arrays.
|
||||
* Does not perform bounds checking.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return Pointer to the raw memory block, or NULL if empty.
|
||||
*/
|
||||
void*
|
||||
dynamic_array_get_raw_data_pointer(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Append an element to the end of the array.
|
||||
*
|
||||
* Automatically resizes if current_occupancy equals current_capacity.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param element Pointer to the element to append.
|
||||
* @return true on success, false on allocation failure.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_append(dynamic_array_struct* array, const void* element);
|
||||
|
||||
/**
|
||||
* @brief Insert an element at the specified index.
|
||||
*
|
||||
* Shifts existing elements at and after the index to the right.
|
||||
* Automatically resizes if capacity is exceeded.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param index Index at which to insert the element.
|
||||
* @param element Pointer to the element to insert.
|
||||
* @return true on success, false if index is out of bounds or allocation fails.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_insert_at(dynamic_array_struct* array,
|
||||
size_t index,
|
||||
const void* element);
|
||||
|
||||
/**
|
||||
* @brief Replace the element at the specified index.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param index Index of the element to replace.
|
||||
* @param new_element Pointer to the new element data.
|
||||
* @return true on success, false if index is out of bounds.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_set_item(dynamic_array_struct* array,
|
||||
size_t index,
|
||||
const void* new_element);
|
||||
|
||||
/**
|
||||
* @brief Swap the elements at two indices.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param index_a First index.
|
||||
* @param index_b Second index.
|
||||
* @return true on success, false if either index is out of bounds.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_swap(dynamic_array_struct* array,
|
||||
size_t index_a,
|
||||
size_t index_b);
|
||||
|
||||
/**
|
||||
* @brief Remove the last element from the array.
|
||||
*
|
||||
* Decrements current_occupancy. Does not free the memory block.
|
||||
* If item_free is set, it will be called on the removed element.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return true on success, false if array is empty.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_pop(dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Remove an element at the specified index.
|
||||
*
|
||||
* Shifts subsequent elements down to fill the gap.
|
||||
* If item_free is set, it will be called on the removed element.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param index Index of the element to remove.
|
||||
* @return true on success, false if index is out of bounds.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_remove(dynamic_array_struct* array,
|
||||
size_t index);
|
||||
|
||||
/**
|
||||
* @brief Clear all elements from the array.
|
||||
*
|
||||
* Sets current_occupancy to 0. Does not free the memory block.
|
||||
* If item_free is set, it will be called on all removed elements.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
*/
|
||||
void
|
||||
dynamic_array_clear(dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Check if the array is empty.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return true if current_occupancy is 0, false otherwise.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_is_empty(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Reserve additional capacity without changing elements.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param new_capacity Desired capacity.
|
||||
* @return true on success, false on allocation failure.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_increase_capacity(dynamic_array_struct* array,
|
||||
size_t new_capacity);
|
||||
|
||||
/**
|
||||
* @brief Shrink the array capacity to match current occupancy.
|
||||
*
|
||||
* Frees unused memory while keeping all elements intact.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return true on success, false on allocation failure.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_shrink_to_fit(dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Increment the owner count for shared ownership.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return true on success, false if owner_count would overflow.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_acquire(dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Decrement the owner count for shared ownership.
|
||||
*
|
||||
* If owner_count reaches 0, the array is automatically destroyed.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return true if owner_count > 0 after decrement, false if destroyed.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_release(dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Get the current owner count.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return Current owner_count value.
|
||||
*/
|
||||
unsigned short
|
||||
dynamic_array_get_owner_count(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Check if the array is thread-safe.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return true if is_multithread_safe is set, false otherwise.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_is_thread_safe(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Creates a shallow copy of the array.
|
||||
*
|
||||
* The new array will have the same capacity and occupancy, but the elements
|
||||
* themselves are not copied (pointers are copied).
|
||||
*
|
||||
* @param array_to_copy Pointer to the array being copied.
|
||||
* @return Pointer to the new shallow copy, or NULL on failure.
|
||||
*/
|
||||
dynamic_array_struct*
|
||||
dynamic_array_shallow_copy(const dynamic_array_struct* array_to_copy);
|
||||
|
||||
/**
|
||||
* @brief Creates a deep copy of the array.
|
||||
*
|
||||
* Uses the provided item_copy function to duplicate each element.
|
||||
*
|
||||
* @param array_to_copy Pointer to the array being copied.
|
||||
* @param item_copy Function pointer to copy a single element.
|
||||
* @return Pointer to the new deep copy, or NULL on failure.
|
||||
*/
|
||||
dynamic_array_struct*
|
||||
dynamic_array_deep_copy(const dynamic_array_struct* array_to_copy,
|
||||
void* (*item_copy)(const void* item));
|
||||
|
||||
/**
|
||||
* @brief Creates a shallow copy of a slice of an array.
|
||||
*
|
||||
* @param array_to_copy Pointer to the array being copied/sliced.
|
||||
* @param starting_point Index to start the slice at.
|
||||
* @param ending_point Index to end the slice at.
|
||||
* @param is_start_inclusive Boolean indicator of if the starting index should
|
||||
* be included.
|
||||
* @param is_end_inclusive Boolean indicator of if the ending index should
|
||||
* be included.
|
||||
* @return Pointer to the new shallow copy of the slice, or NULL on failure.
|
||||
*/
|
||||
dynamic_array_struct*
|
||||
dynamic_array_shallow_copy_slice(const dynamic_array_struct* array_to_copy,
|
||||
size_t starting_point,
|
||||
size_t ending_point,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive);
|
||||
|
||||
/**
|
||||
* @brief Creates a deep copy of a slice of an array.
|
||||
*
|
||||
* Uses the provided item_copy function to duplicate each element in the slice.
|
||||
*
|
||||
* @param array_to_copy Pointer to the array being copied/sliced.
|
||||
* @param item_copy Function pointer to copy a single element.
|
||||
* @param starting_point Index to start the slice at.
|
||||
* @param ending_point Index to end the slice at.
|
||||
* @param is_start_inclusive Boolean indicator of if the starting index should
|
||||
* be included.
|
||||
* @param is_end_inclusive Boolean indicator of if the ending index should
|
||||
* be included.
|
||||
* @return Pointer to the new deep copy of the slice, or NULL on failure.
|
||||
*/
|
||||
dynamic_array_struct*
|
||||
dynamic_array_deep_copy_slice(const dynamic_array_struct* array_to_copy,
|
||||
void* (*item_copy)(const void* item),
|
||||
size_t starting_point,
|
||||
size_t ending_point,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive);
|
||||
|
||||
/**
|
||||
* @brief Modifies the array in place so that it is sorted.
|
||||
*
|
||||
* @param array_to_sort Pointer to the array to be sorted.
|
||||
* @param should_reverse_sort If true, inverts the order of the array.
|
||||
*/
|
||||
void
|
||||
dynamic_array_sort_in_place(dynamic_array_struct* array_to_sort,
|
||||
bool should_reverse_sort);
|
||||
|
||||
/**
|
||||
* @brief Sorts a slice of the array in place.
|
||||
*
|
||||
* @param array_to_sort Pointer to the array to be sorted.
|
||||
* @param starting_point Index to start the slice at.
|
||||
* @param ending_point Index to end the slice at.
|
||||
* @param is_start_inclusive Boolean indicator of if the starting index should
|
||||
* be included.
|
||||
* @param is_end_inclusive Boolean indicator of if the ending index should
|
||||
* be included.
|
||||
* @param should_reverse_sort If true, inverts the order of the slice.
|
||||
*/
|
||||
void
|
||||
dynamic_array_sort_slice(dynamic_array_struct* array_to_sort,
|
||||
size_t starting_point,
|
||||
size_t ending_point,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive,
|
||||
bool should_reverse_sort);
|
||||
|
||||
/**
|
||||
* @brief Creates a new sorted shallow copy of the array without modifying the original.
|
||||
*
|
||||
* @param array_to_sort Pointer to the array to be sorted.
|
||||
* @param should_reverse_sort If true, inverts the order of the copy.
|
||||
* @return Pointer to the new sorted array, or NULL on failure.
|
||||
*/
|
||||
dynamic_array_struct*
|
||||
dynamic_array_get_sorted_copy(const dynamic_array_struct* array,
|
||||
bool should_reverse_sort);
|
||||
|
||||
/**
|
||||
* @brief Reverses the order of elements in the array in place.
|
||||
*
|
||||
* @param array_to_reverse Pointer to the array to be reversed.
|
||||
*/
|
||||
void
|
||||
dynamic_array_reverse(dynamic_array_struct* array_to_reverse);
|
||||
|
||||
/**
|
||||
* @brief Check if the array contains a specific value.
|
||||
*
|
||||
* Requires a valid comparator function to be set.
|
||||
*
|
||||
* @param array_to_search Pointer to the array to search.
|
||||
* @param pointer_of_value_to_find Pointer to the value to find.
|
||||
* @return true if the value is found, false otherwise.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_contains(const dynamic_array_struct* array_to_search,
|
||||
const void* pointer_of_value_to_find);
|
||||
|
||||
/**
|
||||
* @brief Find the first index of a value in the array.
|
||||
*
|
||||
* Requires a valid comparator function to be set.
|
||||
*
|
||||
* @param array_to_search Pointer to the array to search.
|
||||
* @param pointer_of_value_to_find Pointer to the value to find.
|
||||
* @return Index of the first occurrence, or SIZE_MAX if not found.
|
||||
*/
|
||||
size_t
|
||||
dynamic_array_find_first_index_of(const dynamic_array_struct* array_to_search,
|
||||
const void* pointer_of_value_to_find);
|
||||
|
||||
/**
|
||||
* @brief Find the last index of a value in the array.
|
||||
*
|
||||
* Requires a valid comparator function to be set.
|
||||
*
|
||||
* @param array_to_search Pointer to the array to search.
|
||||
* @param pointer_of_value_to_find Pointer to the value to find.
|
||||
* @return Index of the last occurrence, or SIZE_MAX if not found.
|
||||
*/
|
||||
size_t
|
||||
dynamic_array_find_final_index_of(const dynamic_array_struct* array_to_search,
|
||||
const void* pointer_of_value_to_find);
|
||||
|
||||
/**
|
||||
* @brief Set or change the comparator function used for sorting and searching.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param comparator Function to compare two elements.
|
||||
*/
|
||||
void
|
||||
dynamic_array_set_comparator_function(dynamic_array_struct *array,
|
||||
int (*comparator)(const void*, const void*));
|
||||
|
||||
/**
|
||||
* @brief Copies the element at the specified index into a user-provided buffer.
|
||||
*
|
||||
* Performs bounds checking and uses memcpy to safely extract the element's
|
||||
* data. Useful when you need a standalone copy of an element rather than a
|
||||
* temporary pointer.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param index Index of the element to retrieve.
|
||||
* @param out_buffer Pointer to a buffer large enough to hold one element (at
|
||||
* least item_size bytes).
|
||||
* @return true on success, false if index is out of bounds or out_buffer is
|
||||
* NULL.
|
||||
*/
|
||||
bool
|
||||
dynamic_array_get_item(const dynamic_array_struct* array,
|
||||
size_t index,
|
||||
void* out_buffer);
|
||||
|
||||
/**
|
||||
* @brief Iterates over a specific range of the array.
|
||||
*
|
||||
* Calls the callback function for each element in the specified range.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param callback Function to call for each element.
|
||||
* @param starting_index Index to start iteration from.
|
||||
* @param ending_index Index to end iteration at.
|
||||
* @param is_start_inclusive If true, includes the starting_index in iteration.
|
||||
* @param is_end_inclusive If true, includes the ending_index in iteration.
|
||||
*/
|
||||
void
|
||||
dynamic_array_iterate_over(dynamic_array_struct* array,
|
||||
void (*callback)(void* element, void* user_data),
|
||||
size_t starting_index,
|
||||
size_t ending_index,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive);
|
||||
|
||||
/**
|
||||
* @brief Iterates over every element in the array.
|
||||
*
|
||||
* Calls the callback function for each element in the array.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param callback Function to call for each element.
|
||||
*/
|
||||
void
|
||||
dynamic_array_foreach(dynamic_array_struct* array,
|
||||
void (*callback)(void* element, void* user_data));
|
||||
|
||||
/**
|
||||
* @brief Performs a binary search on the array.
|
||||
*
|
||||
* If the array is not marked as sorted, a temporary sorted copy is created.
|
||||
* For repeated searches on unsorted data, sort the array in-place first for
|
||||
* better performance.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @param value Pointer to the value to search for.
|
||||
* @return Index of the element if found, or SIZE_MAX if not found.
|
||||
*/
|
||||
size_t
|
||||
dynamic_array_binary_search(const dynamic_array_struct* array,
|
||||
const void* value);
|
||||
|
||||
#ifdef MARIGOLD_DEBUG
|
||||
/**
|
||||
* @brief Prints debug statistics about the array to stdout.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
*/
|
||||
void dynamic_array_debug_print_stats(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Dumps the contents of the array to stdout.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
*/
|
||||
void dynamic_array_debug_dump_array(const dynamic_array_struct* array);
|
||||
|
||||
/**
|
||||
* @brief Validates the internal integrity of the array.
|
||||
*
|
||||
* Checks for consistency in capacity, occupancy, and pointers.
|
||||
*
|
||||
* @param array Pointer to the dynamic_array.
|
||||
* @return true if the array is valid, false otherwise.
|
||||
*/
|
||||
bool dynamic_array_validate_integrity(const dynamic_array_struct* array);
|
||||
#endif /* MARIGOLD_DEBUG */
|
||||
|
||||
#endif /* MARIGOLD_DYNAMIC_ARRAY_H */
|
||||
597
source_code/MODULE_marigold_vector/marigold_vector.h
Normal file
597
source_code/MODULE_marigold_vector/marigold_vector.h
Normal file
@@ -0,0 +1,597 @@
|
||||
#ifndef MARIGOLD_VECTOR_H
|
||||
#define MARIGOLD_VECTOR_H
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef enum
|
||||
vector_flag_enum
|
||||
{
|
||||
vector_multithread_safe = 1 << 0,
|
||||
vector_read_only = 1 << 1,
|
||||
vector_certainly_sorted = 1 << 2,
|
||||
vector_marked_for_free = 1 << 3,
|
||||
vector_debug_has_function_call_rolled_over = 1 << 4,
|
||||
vector_debug_has_owner_count_rolled_over = 1 << 5,
|
||||
vector_debug_has_been_resized = 1 << 6,
|
||||
vector_debug_has_been_resized_rolled_over = 1 << 7
|
||||
}
|
||||
vector_flag_enum;
|
||||
|
||||
typedef enum
|
||||
vector_growth_rate_enum
|
||||
{
|
||||
vector_growth_none = 0,
|
||||
vector_growth_linear = 1,
|
||||
vector_growth_double = 2,
|
||||
vector_growth_triple = 3,
|
||||
vector_growth_quadruple = 4,
|
||||
vector_growth_quintuple = 5
|
||||
}
|
||||
vector_growth_rate_enum;
|
||||
|
||||
typedef struct
|
||||
vector_struct
|
||||
{
|
||||
size_t item_size;
|
||||
size_t current_capacity;
|
||||
size_t current_occupancy;
|
||||
void* data_pointer;
|
||||
int (*comparator)(const void *, const void *);
|
||||
void (*item_free)(const void *);
|
||||
pthread_mutex_t* mutex_lock;
|
||||
unsigned short owner_count;
|
||||
uint8_t growth_strategy;
|
||||
uint8_t flags;
|
||||
#ifdef MARIGOLD_DEBUG
|
||||
uint8_t debug_flags;
|
||||
uint32_t debug_resize_count;
|
||||
uint32_t debug_function_call_count;
|
||||
uint32_t debug_last_error_code;
|
||||
uint32_t debug_allocation_failures;
|
||||
|
||||
#endif /* MARIGOLD_DEBUG. */
|
||||
}
|
||||
vector_struct;
|
||||
|
||||
/**
|
||||
* @brief Create a new dynamic vector, it then internally does all the
|
||||
* initialization.
|
||||
*
|
||||
* Creates a dynamic vector with the specified item size and starting capacity.
|
||||
* The growth_strategy determines how the vector expands when capacity is
|
||||
* exceeded.
|
||||
*
|
||||
* If is_multithread_safe is true, the internal mutex is created and initialized
|
||||
* here.
|
||||
*
|
||||
* @param item_size Size of each element in bytes.
|
||||
* @param starting_capacity Initial number of elements to allocate space for.
|
||||
* @param growth_strategy Growth strategy enum.
|
||||
* @param comparator Function to compare two elements. May be NULL if not
|
||||
* needed.
|
||||
* @param is_multithread_safe If true, enables thread-safe operations.
|
||||
* @return Pointer to the initialized vector, or NULL on failure.
|
||||
*/
|
||||
vector_struct*
|
||||
vector_create(size_t item_size,
|
||||
size_t starting_capacity,
|
||||
vector_growth_rate_enum growth_rate,
|
||||
int (*comparator)(const void*, const void*),
|
||||
void (*item_free)(const void *),
|
||||
bool is_multithread_safe);
|
||||
|
||||
/**
|
||||
* @brief Explicitly destroy the dynamic vector and free its memory.
|
||||
*
|
||||
* Checks the owner count. If it is 0 or 1, deallocates the internal memory
|
||||
* and the struct itself. Use this for explicit cleanup. For reference-counted
|
||||
* shared ownership, prefer vector_release().
|
||||
*
|
||||
* If the vector is thread-safe, the internal mutex is destroyed and freed here.
|
||||
*
|
||||
* @param vector_to_destroy is the dynamic vector being deallocated/destroyed.
|
||||
* @return true on successful destroy, false on failure.
|
||||
*/
|
||||
bool
|
||||
vector_destroy(vector_struct* vector_to_destroy);
|
||||
|
||||
/**
|
||||
* @brief Set or clear a specific flag on the dynamic vector.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param flag The flag to modify.
|
||||
* @param value true to set the flag, false to clear it.
|
||||
*/
|
||||
void
|
||||
vector_set_flag(vector_struct* vector,
|
||||
vector_flag_enum flag,
|
||||
bool value);
|
||||
|
||||
/**
|
||||
* @brief Get a specific flag on the dynamic vector.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param flag The flag to get.
|
||||
*
|
||||
* @return value of flag as bool (true or false)
|
||||
*/
|
||||
bool
|
||||
vector_get_flag_value(const vector_struct* vector,
|
||||
vector_flag_enum flag);
|
||||
|
||||
/**
|
||||
* @brief Get the number of elements currently in the vector.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return Number of elements (current_occupancy).
|
||||
*/
|
||||
size_t
|
||||
vector_get_occupancy(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Get the total capacity of the vector.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return Total capacity (current_capacity).
|
||||
*/
|
||||
size_t
|
||||
vector_get_capacity(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the element at the specified index.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param index Index of the element to access.
|
||||
* @return Pointer to the element, or NULL if index is out of bounds.
|
||||
*/
|
||||
void*
|
||||
vector_get_pointer_to_index(vector_struct* vector,
|
||||
size_t index);
|
||||
|
||||
/**
|
||||
* @brief Get a const pointer to the element at the specified index.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param index Index of the element to access.
|
||||
* @return Const pointer to the element, or NULL if index is out of bounds.
|
||||
*/
|
||||
const void*
|
||||
vector_get_const_pointer_to_index(const vector_struct* vector,
|
||||
size_t index);
|
||||
|
||||
/**
|
||||
* @brief Get a direct pointer to the underlying memory block.
|
||||
*
|
||||
* Useful for direct iteration or passing to C APIs expecting raw vectors.
|
||||
* Does not perform bounds checking.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return Pointer to the raw memory block, or NULL if empty.
|
||||
*/
|
||||
void*
|
||||
vector_get_raw_data_pointer(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Append an element to the end of the vector.
|
||||
*
|
||||
* Automatically resizes if current_occupancy equals current_capacity.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param element Pointer to the element to append.
|
||||
* @return true on success, false on allocation failure.
|
||||
*/
|
||||
bool
|
||||
vector_append(vector_struct* vector, const void* element);
|
||||
|
||||
/**
|
||||
* @brief Insert an element at the specified index.
|
||||
*
|
||||
* Shifts existing elements at and after the index to the right.
|
||||
* Automatically resizes if capacity is exceeded.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param index Index at which to insert the element.
|
||||
* @param element Pointer to the element to insert.
|
||||
* @return true on success, false if index is out of bounds or allocation fails.
|
||||
*/
|
||||
bool
|
||||
vector_insert_at(vector_struct* vector,
|
||||
size_t index,
|
||||
const void* element);
|
||||
|
||||
/**
|
||||
* @brief Replace the element at the specified index.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param index Index of the element to replace.
|
||||
* @param new_element Pointer to the new element data.
|
||||
* @return true on success, false if index is out of bounds.
|
||||
*/
|
||||
bool
|
||||
vector_set_item(vector_struct* vector,
|
||||
size_t index,
|
||||
const void* new_element);
|
||||
|
||||
/**
|
||||
* @brief Swap the elements at two indices.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param index_a First index.
|
||||
* @param index_b Second index.
|
||||
* @return true on success, false if either index is out of bounds.
|
||||
*/
|
||||
bool
|
||||
vector_swap(vector_struct* vector,
|
||||
size_t index_a,
|
||||
size_t index_b);
|
||||
|
||||
/**
|
||||
* @brief Remove the last element from the vector.
|
||||
*
|
||||
* Decrements current_occupancy. Does not free the memory block.
|
||||
* If item_free is set, it will be called on the removed element.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return true on success, false if vector is empty.
|
||||
*/
|
||||
bool
|
||||
vector_pop(vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Remove an element at the specified index.
|
||||
*
|
||||
* Shifts subsequent elements down to fill the gap.
|
||||
* If item_free is set, it will be called on the removed element.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param index Index of the element to remove.
|
||||
* @return true on success, false if index is out of bounds.
|
||||
*/
|
||||
bool
|
||||
vector_remove(vector_struct* vector,
|
||||
size_t index);
|
||||
|
||||
/**
|
||||
* @brief Clear all elements from the vector.
|
||||
*
|
||||
* Sets current_occupancy to 0. Does not free the memory block.
|
||||
* If item_free is set, it will be called on all removed elements.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
*/
|
||||
void
|
||||
vector_clear(vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Check if the vector is empty.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return true if current_occupancy is 0, false otherwise.
|
||||
*/
|
||||
bool
|
||||
vector_is_empty(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Reserve additional capacity without changing elements.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param new_capacity Desired capacity.
|
||||
* @return true on success, false on allocation failure.
|
||||
*/
|
||||
bool
|
||||
vector_increase_capacity(vector_struct* vector,
|
||||
size_t new_capacity);
|
||||
|
||||
/**
|
||||
* @brief Shrink the vector capacity to match current occupancy.
|
||||
*
|
||||
* Frees unused memory while keeping all elements intact.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return true on success, false on allocation failure.
|
||||
*/
|
||||
bool
|
||||
vector_shrink_to_fit(vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Increment the owner count for shared ownership.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return true on success, false if owner_count would overflow.
|
||||
*/
|
||||
bool
|
||||
vector_acquire(vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Decrement the owner count for shared ownership.
|
||||
*
|
||||
* If owner_count reaches 0, the vector is automatically destroyed.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return true if owner_count > 0 after decrement, false if destroyed.
|
||||
*/
|
||||
bool
|
||||
vector_release(vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Get the current owner count.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return Current owner_count value.
|
||||
*/
|
||||
unsigned short
|
||||
vector_get_owner_count(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Check if the vector is thread-safe.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return true if is_multithread_safe is set, false otherwise.
|
||||
*/
|
||||
bool
|
||||
vector_is_thread_safe(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Creates a shallow copy of the vector.
|
||||
*
|
||||
* The new vector will have the same capacity and occupancy, but the elements
|
||||
* themselves are not copied (pointers are copied).
|
||||
*
|
||||
* @param vector_to_copy Pointer to the vector being copied.
|
||||
* @return Pointer to the new shallow copy, or NULL on failure.
|
||||
*/
|
||||
vector_struct*
|
||||
vector_shallow_copy(const vector_struct* vector_to_copy);
|
||||
|
||||
/**
|
||||
* @brief Creates a deep copy of the vector.
|
||||
*
|
||||
* Uses the provided item_copy function to duplicate each element.
|
||||
*
|
||||
* @param vector_to_copy Pointer to the vector being copied.
|
||||
* @param item_copy Function pointer to copy a single element.
|
||||
* @return Pointer to the new deep copy, or NULL on failure.
|
||||
*/
|
||||
vector_struct*
|
||||
vector_deep_copy(const vector_struct* vector_to_copy,
|
||||
void* (*item_copy)(const void* item));
|
||||
|
||||
/**
|
||||
* @brief Creates a shallow copy of a slice of a vector.
|
||||
*
|
||||
* @param vector_to_copy Pointer to the vector being copied/sliced.
|
||||
* @param starting_point Index to start the slice at.
|
||||
* @param ending_point Index to end the slice at.
|
||||
* @param is_start_inclusive Boolean indicator of if the starting index should
|
||||
* be included.
|
||||
* @param is_end_inclusive Boolean indicator of if the ending index should
|
||||
* be included.
|
||||
* @return Pointer to the new shallow copy of the slice, or NULL on failure.
|
||||
*/
|
||||
vector_struct*
|
||||
vector_shallow_copy_slice(const vector_struct* vector_to_copy,
|
||||
size_t starting_point,
|
||||
size_t ending_point,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive);
|
||||
|
||||
/**
|
||||
* @brief Creates a deep copy of a slice of a vector.
|
||||
*
|
||||
* Uses the provided item_copy function to duplicate each element in the slice.
|
||||
*
|
||||
* @param vector_to_copy Pointer to the vector being copied/sliced.
|
||||
* @param item_copy Function pointer to copy a single element.
|
||||
* @param starting_point Index to start the slice at.
|
||||
* @param ending_point Index to end the slice at.
|
||||
* @param is_start_inclusive Boolean indicator of if the starting index should
|
||||
* be included.
|
||||
* @param is_end_inclusive Boolean indicator of if the ending index should
|
||||
* be included.
|
||||
* @return Pointer to the new deep copy of the slice, or NULL on failure.
|
||||
*/
|
||||
vector_struct*
|
||||
vector_deep_copy_slice(const vector_struct* vector_to_copy,
|
||||
void* (*item_copy)(const void* item),
|
||||
size_t starting_point,
|
||||
size_t ending_point,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive);
|
||||
|
||||
/**
|
||||
* @brief Modifies the vector in place so that it is sorted.
|
||||
*
|
||||
* @param vector_to_sort Pointer to the vector to be sorted.
|
||||
* @param should_reverse_sort If true, inverts the order of the vector.
|
||||
*/
|
||||
void
|
||||
vector_sort_in_place(vector_struct* vector_to_sort,
|
||||
bool should_reverse_sort);
|
||||
|
||||
/**
|
||||
* @brief Sorts a slice of the vector in place.
|
||||
*
|
||||
* @param vector_to_sort Pointer to the vector to be sorted.
|
||||
* @param starting_point Index to start the slice at.
|
||||
* @param ending_point Index to end the slice at.
|
||||
* @param is_start_inclusive Boolean indicator of if the starting index should
|
||||
* be included.
|
||||
* @param is_end_inclusive Boolean indicator of if the ending index should
|
||||
* be included.
|
||||
* @param should_reverse_sort If true, inverts the order of the slice.
|
||||
*/
|
||||
void
|
||||
vector_sort_slice(vector_struct* vector_to_sort,
|
||||
size_t starting_point,
|
||||
size_t ending_point,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive,
|
||||
bool should_reverse_sort);
|
||||
|
||||
/**
|
||||
* @brief Creates a new sorted shallow copy of the vector without modifying the original.
|
||||
*
|
||||
* @param vector_to_sort Pointer to the vector to be sorted.
|
||||
* @param should_reverse_sort If true, inverts the order of the copy.
|
||||
* @return Pointer to the new sorted vector, or NULL on failure.
|
||||
*/
|
||||
vector_struct*
|
||||
vector_get_sorted_copy(const vector_struct* vector,
|
||||
bool should_reverse_sort);
|
||||
|
||||
/**
|
||||
* @brief Reverses the order of elements in the vector in place.
|
||||
*
|
||||
* @param vector_to_reverse Pointer to the vector to be reversed.
|
||||
*/
|
||||
void
|
||||
vector_reverse(vector_struct* vector_to_reverse);
|
||||
|
||||
/**
|
||||
* @brief Check if the vector contains a specific value.
|
||||
*
|
||||
* Requires a valid comparator function to be set.
|
||||
*
|
||||
* @param vector_to_search Pointer to the vector to search.
|
||||
* @param pointer_of_value_to_find Pointer to the value to find.
|
||||
* @return true if the value is found, false otherwise.
|
||||
*/
|
||||
bool
|
||||
vector_contains(const vector_struct* vector_to_search,
|
||||
const void* pointer_of_value_to_find);
|
||||
|
||||
/**
|
||||
* @brief Find the first index of a value in the vector.
|
||||
*
|
||||
* Requires a valid comparator function to be set.
|
||||
*
|
||||
* @param vector_to_search Pointer to the vector to search.
|
||||
* @param pointer_of_value_to_find Pointer to the value to find.
|
||||
* @return Index of the first occurrence, or SIZE_MAX if not found.
|
||||
*/
|
||||
size_t
|
||||
vector_find_first_index_of(const vector_struct* vector_to_search,
|
||||
const void* pointer_of_value_to_find);
|
||||
|
||||
/**
|
||||
* @brief Find the last index of a value in the vector.
|
||||
*
|
||||
* Requires a valid comparator function to be set.
|
||||
*
|
||||
* @param vector_to_search Pointer to the vector to search.
|
||||
* @param pointer_of_value_to_find Pointer to the value to find.
|
||||
* @return Index of the last occurrence, or SIZE_MAX if not found.
|
||||
*/
|
||||
size_t
|
||||
vector_find_final_index_of(const vector_struct* vector_to_search,
|
||||
const void* pointer_of_value_to_find);
|
||||
|
||||
/**
|
||||
* @brief Set or change the comparator function used for sorting and searching.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param comparator Function to compare two elements.
|
||||
*/
|
||||
void
|
||||
vector_set_comparator_function(vector_struct *vector,
|
||||
int (*comparator)(const void*, const void*));
|
||||
|
||||
/**
|
||||
* @brief Copies the element at the specified index into a user-provided buffer.
|
||||
*
|
||||
* Performs bounds checking and uses memcpy to safely extract the element's
|
||||
* data. Useful when you need a standalone copy of an element rather than a
|
||||
* temporary pointer.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param index Index of the element to retrieve.
|
||||
* @param out_buffer Pointer to a buffer large enough to hold one element (at
|
||||
* least item_size bytes).
|
||||
* @return true on success, false if index is out of bounds or out_buffer is
|
||||
* NULL.
|
||||
*/
|
||||
bool
|
||||
vector_get_item(const vector_struct* vector,
|
||||
size_t index,
|
||||
void* out_buffer);
|
||||
|
||||
/**
|
||||
* @brief Iterates over a specific range of the vector.
|
||||
*
|
||||
* Calls the callback function for each element in the specified range.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param callback Function to call for each element.
|
||||
* @param starting_index Index to start iteration from.
|
||||
* @param ending_index Index to end iteration at.
|
||||
* @param is_start_inclusive If true, includes the starting_index in iteration.
|
||||
* @param is_end_inclusive If true, includes the ending_index in iteration.
|
||||
*/
|
||||
void
|
||||
vector_iterate_over(vector_struct* vector,
|
||||
void (*callback)(void* element, void* user_data),
|
||||
size_t starting_index,
|
||||
size_t ending_index,
|
||||
bool is_start_inclusive,
|
||||
bool is_end_inclusive);
|
||||
|
||||
/**
|
||||
* @brief Iterates over every element in the vector.
|
||||
*
|
||||
* Calls the callback function for each element in the vector.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param callback Function to call for each element.
|
||||
*/
|
||||
void
|
||||
vector_foreach(vector_struct* vector,
|
||||
void (*callback)(void* element, void* user_data));
|
||||
|
||||
/**
|
||||
* @brief Performs a binary search on the vector.
|
||||
*
|
||||
* If the vector is not marked as sorted, a temporary sorted copy is created.
|
||||
* For repeated searches on unsorted data, sort the vector in-place first for
|
||||
* better performance.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @param value Pointer to the value to search for.
|
||||
* @return Index of the element if found, or SIZE_MAX if not found.
|
||||
*/
|
||||
size_t
|
||||
vector_binary_search(const vector_struct* vector,
|
||||
const void* value);
|
||||
|
||||
#ifdef MARIGOLD_DEBUG
|
||||
/**
|
||||
* @brief Prints debug statistics about the vector to stdout.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
*/
|
||||
void
|
||||
vector_debug_print_stats(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Dumps the contents of the vector to stdout.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
*/
|
||||
void
|
||||
vector_debug_dump_vector(const vector_struct* vector);
|
||||
|
||||
/**
|
||||
* @brief Validates the internal integrity of the vector.
|
||||
*
|
||||
* Checks for consistency in capacity, occupancy, and pointers.
|
||||
*
|
||||
* @param vector Pointer to the vector.
|
||||
* @return true if the vector is valid, false otherwise.
|
||||
*/
|
||||
bool
|
||||
vector_validate_integrity(const vector_struct* vector);
|
||||
#endif /* MARIGOLD_DEBUG */
|
||||
|
||||
#endif /* MARIGOLD_VECTOR_H */
|
||||
Reference in New Issue
Block a user