From 06da0818935a3a2def2be565d55be25e1dbac6df Mon Sep 17 00:00:00 2001 From: epochryphon Date: Sun, 17 May 2026 23:53:17 -0500 Subject: [PATCH] api version 1, still needs to update growth factor to use enum probably, none, linear, double, triple, quadruple, quintuple or something --- .../marigold_dynamic_array.h | 288 +++++++++++++----- source_code/main.c | 2 +- 2 files changed, 214 insertions(+), 76 deletions(-) diff --git a/source_code/MODULE_marigold_dynamic_array/marigold_dynamic_array.h b/source_code/MODULE_marigold_dynamic_array/marigold_dynamic_array.h index 7c5754a..8b57c8e 100644 --- a/source_code/MODULE_marigold_dynamic_array/marigold_dynamic_array.h +++ b/source_code/MODULE_marigold_dynamic_array/marigold_dynamic_array.h @@ -6,24 +6,20 @@ #include #include -typedef struct dynamic_array +typedef struct dynamic_array_struct { size_t item_size; - size_t starting_capacity; size_t current_capacity; - size_t current_size; - void* memory_block_pointer; + size_t current_occupancy; + void* data_pointer; int (*comparator)(const void*, const void*); pthread_mutex_t* mutex_lock; - unsigned short owner_count; + unsigned short function_call_count; unsigned short growth_steps; - unsigned char growth_factor; - bool is_multithread_safe; - bool is_read_only; - bool is_certainly_sorted; -} dynamic_array; + uint8_t flags; // is_multithread_safe, is_read_only, is_certainly_sorted, has_owner_count_rolled_over, has_function_call_count_rolled_over, has_growth_steps_rolled_over, has_been_resized, is_array_full (occupancy == capacity) +} dynamic_array_struct; /** * @brief Create a new dynamic array, it then internally does all the initalization. @@ -33,33 +29,37 @@ typedef struct dynamic_array * * @param item_size Size of each element in bytes. * @param starting_capacity Initial number of elements to allocate space for. - * @param growth_factor Growth strategy: 0 = linear (+starting_capacity), - * 1 = 1.5x, 2+ = multiplier (2 = 2x, 3 = 3x, etc.) + * @param growth_factor Growth strategy: 0 = no growth. 1 = linear (+starting_capacity), + * 2+ = multiplier (2 = 2x, 3 = 3x, etc.) + * @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* dynamic_array_create(size_t item_size, - unsigned int starting_capacity, - unsigned char growth_factor, - int (*comparator)(const void*, const void*), - bool is_multithread_safe); +dynamic_array_struct* dynamic_array_create(size_t item_size, + size_t starting_capacity, + unsigned char growth_factor, + int (*comparator)(const void*, const void*), + bool is_multithread_safe); /** - * @brief This function checks to make sure the owner count 1 or 0 - * then deallocates what needs to be deallocated, before destorying it. + * @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(). * * @param array_to_destroy is the dynamic array being deallocated/destroyed. * @return true on successful destory, false on failure. */ -bool dynamic_array_destroy(dynamic_array* array_to_destroy); +bool dynamic_array_destroy(dynamic_array_struct* array_to_destroy); /** * @brief Get the number of elements currently in the array. * * @param array Pointer to the dynamic_array. - * @return Number of elements (current_size). + * @return Number of elements (current_occupancy). */ -unsigned int dynamic_array_get_occupancy(const dynamic_array* array); +size_t dynamic_array_get_occupancy(const dynamic_array_struct* array); /** * @brief Get the total capacity of the array. @@ -67,7 +67,7 @@ unsigned int dynamic_array_get_occupancy(const dynamic_array* array); * @param array Pointer to the dynamic_array. * @return Total capacity (current_capacity). */ -unsigned int dynamic_array_get_capacity(const dynamic_array* array); +size_t dynamic_array_get_capacity(const dynamic_array_struct* array); /** * @brief Get a pointer to the element at the specified index. @@ -76,8 +76,8 @@ unsigned int dynamic_array_get_capacity(const dynamic_array* 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(const dynamic_array* array, - const unsigned int index); +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. @@ -86,30 +86,80 @@ void* dynamic_array_get_pointer_to_index(const dynamic_array* 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* array, - const unsigned int index); +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_size equals current_capacity. + * 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* array, +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_size. Does not free the memory block. + * Decrements current_occupancy. Does not free the memory block. * * @param array Pointer to the dynamic_array. * @return true on success, false if array is empty. */ -bool dynamic_array_pop(dynamic_array* array); +bool dynamic_array_pop(dynamic_array_struct* array); /** * @brief Remove an element at the specified index. @@ -120,25 +170,25 @@ bool dynamic_array_pop(dynamic_array* 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* array, - const unsigned int index); +bool dynamic_array_remove(dynamic_array_struct* array, + size_t index); /** * @brief Clear all elements from the array. * - * Sets current_size to 0. Does not free the memory block. + * Sets current_occupancy to 0. Does not free the memory block. * * @param array Pointer to the dynamic_array. */ -void dynamic_array_clear(dynamic_array* 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_size is 0, false otherwise. + * @return true if current_occupancy is 0, false otherwise. */ -bool dynamic_array_is_empty(const dynamic_array* array); +bool dynamic_array_is_empty(const dynamic_array_struct* array); /** * @brief Reserve additional capacity without changing size. @@ -147,8 +197,30 @@ bool dynamic_array_is_empty(const dynamic_array* array); * @param new_capacity Desired capacity. * @return true on success, false on allocation failure. */ -bool dynamic_array_increase_capacity(dynamic_array* array, - const unsigned int new_capacity); +bool dynamic_array_increase_capacity(dynamic_array_struct* array, + size_t new_capacity); + +/** + * @brief Resize the array capacity to the specified value. + * + * Can grow or shrink the underlying allocation. Occupancy remains unchanged. + * + * @param array Pointer to the dynamic_array. + * @param new_capacity Desired capacity. + * @return true on success, false on allocation failure or if new_capacity < occupancy. + */ +bool dynamic_array_resize(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. @@ -156,7 +228,7 @@ bool dynamic_array_increase_capacity(dynamic_array* array, * @param array Pointer to the dynamic_array. * @return true on success, false if owner_count would overflow. */ -bool dynamic_array_acquire(dynamic_array* array); +bool dynamic_array_acquire(dynamic_array_struct* array); /** * @brief Decrement the owner count for shared ownership. @@ -166,7 +238,7 @@ bool dynamic_array_acquire(dynamic_array* array); * @param array Pointer to the dynamic_array. * @return true if owner_count > 0 after decrement, false if destroyed. */ -bool dynamic_array_release(dynamic_array* array); +bool dynamic_array_release(dynamic_array_struct* array); /** * @brief Get the current owner count. @@ -174,7 +246,7 @@ bool dynamic_array_release(dynamic_array* array); * @param array Pointer to the dynamic_array. * @return Current owner_count value. */ -unsigned short dynamic_array_get_owner_count(const dynamic_array* array); +unsigned short dynamic_array_get_owner_count(const dynamic_array_struct* array); /** * @brief Check if the array is thread-safe. @@ -182,67 +254,133 @@ unsigned short dynamic_array_get_owner_count(const dynamic_array* array); * @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* array); +bool dynamic_array_is_thread_safe(const dynamic_array_struct* array); /** * @brief Creates a deep copy of the array. * * @param array_to_copy Pointer to the array being copied. - * - * @return returns the new deep copy as a pointer. + * @return Pointer to the new deep copy, or NULL on failure. */ -dynamic_array* dynamic_array_clone(const dynamic_array* array_to_copy); +dynamic_array_struct* dynamic_array_clone(const dynamic_array_struct* array_to_copy); /** - * @brief Creates a deep copy of a slice of an array + * @brief Creates a deep copy of a slice of an array. * - * @param array_to_copy_and_slice Pointer to the array being copied/sliced. + * @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 in the slice. - * @param is_end_inclusive Boolean indicator of if the ending index should be - * included in the slice. - * - * @return returns the new deep copy of the array as a pointer to a new array. + * @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* dynamic_array_clone_slice(const dynamic_array* array_to_copy_and_slice, - const size_t starting_point, - const size_t ending_point, - const bool is_start_inclusive, - const bool is_end_inclusive); +dynamic_array_struct* dynamic_array_clone_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 Modifies the list so that it is sorted, and can invert the sorting function. + * @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* array_to_sort, - const bool should_reverse_sort); +void dynamic_array_sort_in_place(dynamic_array_struct* array_to_sort, + bool should_reverse_sort); -void dynamic_array_sort_slice(dynamic_array* array_to_sort, - const size_t starting_point, - const size_t ending_point, - const bool is_start_inclusive, - const bool is_end_inclusive, - const 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); -dynamic_array* dynamic_array_get_sorted_copy(dynamic_array* array_to_sort, - const bool should_reverse_sort); +/** + * @brief Creates a new sorted 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(dynamic_array_struct* array_to_sort, + bool should_reverse_sort); -void dynamic_array_reverse(dynamic_array* array_to_reverse); +/** + * @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); -bool dynamic_array_contains(dynamic_array* array_to_search, +/** + * @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(dynamic_array_struct* array_to_search, void* pointer_of_value_to_find); -size_t dynamic_array_find_first_index_of(dynamic_array* array_to_search, +/** + * @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(dynamic_array_struct* array_to_search, void* pointer_of_value_to_find); -size_t dynamic_array_find_final_index_of(dynamic_array* array_to_search, +/** + * @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(dynamic_array_struct* array_to_search, void* pointer_of_value_to_find); -void dynamic_array_set_comparator_function(dynamic_array* array, +/** + * @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); + #endif /* MARIGOLD_DYNAMIC_ARRAY_H */ diff --git a/source_code/main.c b/source_code/main.c index fb15d6e..705b2f5 100644 --- a/source_code/main.c +++ b/source_code/main.c @@ -6,7 +6,7 @@ int main(void) printf("Hello, %s!\n", "marigold_dynamic_array"); printf("Version: %s\n", "26.136.1101"); - dynamic_array array = init_dynamic_array(); + dynamic_array array = dynamic_array_create(); return 0; }