more functions implemented, and updated LICENSES
This commit is contained in:
2
LICENSE
2
LICENSE
@@ -219,7 +219,7 @@ If you develop a new program, and you want it to be of the greatest possible use
|
|||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
|
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
|
||||||
|
|
||||||
marigold_dynamic_array
|
marigold_vector
|
||||||
Copyright (C) 2026 Emilia Marigold
|
Copyright (C) 2026 Emilia Marigold
|
||||||
|
|
||||||
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef INTERNAL_MARIGOLD_MACROS_H
|
||||||
|
#define INTERNAL_MARIGOLD_MACROS_H
|
||||||
|
|
||||||
|
#define SINGLE_ELEMENT 1
|
||||||
|
#define INDEX_ZERO 0
|
||||||
|
#define BIT_FALSE 0
|
||||||
|
#define EMPTY 0
|
||||||
|
|
||||||
|
#endif /* INTERNAL_MARIGOLD_MACROS_H */
|
||||||
@@ -1,5 +1,7 @@
|
|||||||
#include "marigold_vector.h"
|
#include "marigold_vector.h"
|
||||||
|
#include "internal/internal_marigold_macros.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@@ -11,7 +13,8 @@ vector_create(size_t item_size,
|
|||||||
void (*item_free)(const void *),
|
void (*item_free)(const void *),
|
||||||
bool is_multithread_safe)
|
bool is_multithread_safe)
|
||||||
{
|
{
|
||||||
vector_struct* new_vector = calloc(1, sizeof(vector_struct));
|
vector_struct* new_vector = calloc(SINGLE_ELEMENT,
|
||||||
|
sizeof(vector_struct));
|
||||||
|
|
||||||
if (!new_vector)
|
if (!new_vector)
|
||||||
{
|
{
|
||||||
@@ -55,7 +58,7 @@ bool
|
|||||||
vector_get_flag_value(const vector_struct* vector,
|
vector_get_flag_value(const vector_struct* vector,
|
||||||
vector_flag_enum flag)
|
vector_flag_enum flag)
|
||||||
{
|
{
|
||||||
if ((vector->flags & flag) != 0) // Checks if the existing bit is equal to 1.
|
if ((vector->flags & flag) != BIT_FALSE)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -112,7 +115,7 @@ vector_append(vector_struct* vector,
|
|||||||
if (!vector_grow(vector))
|
if (!vector_grow(vector))
|
||||||
{ /* failed to grow vector (probably out of memory)*/
|
{ /* failed to grow vector (probably out of memory)*/
|
||||||
if (is_thread_safe)
|
if (is_thread_safe)
|
||||||
{ /* unlocking mutex during fail case if it is locked. */
|
{ /* unlocking mutex during fail case (if it is locked.) */
|
||||||
pthread_mutex_unlock(vector->mutex_lock);
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
}
|
}
|
||||||
return false; /* returns false to show append failed. */
|
return false; /* returns false to show append failed. */
|
||||||
@@ -143,15 +146,87 @@ vector_insert_at(vector_struct* vector,
|
|||||||
pthread_mutex_lock(vector->mutex_lock);
|
pthread_mutex_lock(vector->mutex_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (index > vector->current_occupancy)
|
||||||
|
{ /* index out of bounds for insertion. */
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex during fail case (if it is locked.) */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
return false; /* returns false to show insert failed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vector->current_occupancy == vector->current_capacity)
|
||||||
|
{
|
||||||
|
if (!vector_grow(vector))
|
||||||
|
{ /* failed to grow vector (probably out of memory). */
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex during fail case (if it is locked.) */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
return false; /* returns false to show insert failed. */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data = (char*)vector->data_pointer;
|
||||||
|
const size_t element_size = vector->item_size;
|
||||||
|
const size_t bytes_to_shift = (vector->current_occupancy - index) * element_size;
|
||||||
|
const size_t shift_offset = index * element_size;
|
||||||
|
|
||||||
|
if (bytes_to_shift > INDEX_ZERO)
|
||||||
|
{
|
||||||
|
memmove(data + shift_offset + element_size,
|
||||||
|
data + shift_offset,
|
||||||
|
bytes_to_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data + shift_offset, element, element_size);
|
||||||
|
vector->current_occupancy++;
|
||||||
|
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex post vector modification if it exists/is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; /* returns true to show insert success. */
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vector_set_item(vector_struct* vector,
|
vector_set_item(vector_struct* vector,
|
||||||
size_t index,
|
size_t index_to_set,
|
||||||
const void* new_element)
|
const void* new_element)
|
||||||
{
|
{
|
||||||
|
const bool is_thread_safe = vector_is_thread_safe(vector);
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* if thread safe enabled, locking before vector modification. */
|
||||||
|
pthread_mutex_lock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index_to_set >= vector->current_occupancy)
|
||||||
|
{ /* index out of bounds for setting. */
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex during fail case if it is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
return false; /* failed, cannot set a value outside of current values. */
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data = (char*)vector->data_pointer;
|
||||||
|
const size_t element_size = vector->item_size;
|
||||||
|
const size_t offset = index_to_set * element_size;
|
||||||
|
|
||||||
|
if (vector->item_free != NULL)
|
||||||
|
{ /* free the old element if item_free callback is set. */
|
||||||
|
vector->item_free(data + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(data + offset, new_element, element_size);
|
||||||
|
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex post vector modification if it exists/is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; /* returns true to show set success. */
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@@ -159,32 +234,137 @@ vector_swap(vector_struct* vector,
|
|||||||
size_t index_a,
|
size_t index_a,
|
||||||
size_t index_b)
|
size_t index_b)
|
||||||
{
|
{
|
||||||
|
const bool is_thread_safe = vector_is_thread_safe(vector);
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* if thread safe enabled, locking before vector modification. */
|
||||||
|
pthread_mutex_lock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
if (index_a >= vector->current_occupancy || index_b >= vector->current_occupancy)
|
||||||
|
{ /* index out of bounds for swapping. */
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex during fail case if it is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
return false; /* returns false to show swap failed. */
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
if (index_a == index_b)
|
||||||
vector_pop(vector_struct* vector)
|
{ /* same index, nothing to swap. */
|
||||||
{
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex post vector modification if it exists/is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
return true; /* returns true to show swap success. */
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data = (char*)vector->data_pointer;
|
||||||
|
const size_t element_size = vector->item_size;
|
||||||
|
const size_t offset_a = index_a * element_size;
|
||||||
|
const size_t offset_b = index_b * element_size;
|
||||||
|
|
||||||
|
void* temp = malloc(element_size);
|
||||||
|
if (!temp)
|
||||||
|
{ /* failed to allocate temporary buffer. */
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex during fail case if it is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
return false; /* returns false to show swap failed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(temp, data + offset_a, element_size);
|
||||||
|
memcpy(data + offset_a, data + offset_b, element_size);
|
||||||
|
memcpy(data + offset_b, temp, element_size);
|
||||||
|
|
||||||
|
free(temp);
|
||||||
|
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex post vector modification if it exists/is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; /* returns true to show swap success. */
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vector_remove(vector_struct* vector,
|
vector_remove(vector_struct* vector,
|
||||||
size_t index)
|
size_t index)
|
||||||
{
|
{
|
||||||
|
const bool is_thread_safe = vector_is_thread_safe(vector);
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* if thread safe enabled, locking before vector modification. */
|
||||||
|
pthread_mutex_lock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (index >= vector->current_occupancy)
|
||||||
|
{ /* index out of bounds for removal. */
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex during fail case if it is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
return false; /* returns false to show remove failed. */
|
||||||
|
}
|
||||||
|
|
||||||
|
char* data = (char*)vector->data_pointer;
|
||||||
|
const size_t element_size = vector->item_size;
|
||||||
|
const size_t offset = index * element_size;
|
||||||
|
const size_t bytes_to_shift = (vector->current_occupancy - index - 1) * element_size;
|
||||||
|
|
||||||
|
if (vector->item_free != NULL)
|
||||||
|
{ /* free the removed element if item_free callback is set. */
|
||||||
|
vector->item_free(data + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bytes_to_shift > INDEX_ZERO)
|
||||||
|
{
|
||||||
|
memmove(data + offset,
|
||||||
|
data + offset + element_size,
|
||||||
|
bytes_to_shift);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector->current_occupancy--;
|
||||||
|
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex post vector modification if it exists/is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true; /* returns true to show remove success. */
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
vector_clear(vector_struct* vector)
|
vector_clear(vector_struct* vector)
|
||||||
{
|
{
|
||||||
|
const bool is_thread_safe = vector_is_thread_safe(vector);
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* if thread safe enabled, locking before vector modification. */
|
||||||
|
pthread_mutex_lock(vector->mutex_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vector->item_free != NULL)
|
||||||
|
{ /* free all elements if item_free callback is set. */
|
||||||
|
char* data = (char*)vector->data_pointer;
|
||||||
|
const size_t element_size = vector->item_size;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < vector->current_occupancy; i++)
|
||||||
|
{
|
||||||
|
vector->item_free(data + (i * element_size));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vector->current_occupancy = 0;
|
||||||
|
|
||||||
|
if (is_thread_safe)
|
||||||
|
{ /* unlocking mutex post vector modification if it exists/is locked. */
|
||||||
|
pthread_mutex_unlock(vector->mutex_lock);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
vector_is_empty(const vector_struct* vector)
|
vector_is_empty(const vector_struct* vector)
|
||||||
{
|
{
|
||||||
if (vector->current_occupancy == 0)
|
if (vector->current_occupancy == EMPTY)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -228,7 +408,7 @@ vector_get_owner_count(const vector_struct* vector)
|
|||||||
bool
|
bool
|
||||||
vector_is_thread_safe(const vector_struct* vector)
|
vector_is_thread_safe(const vector_struct* vector)
|
||||||
{
|
{
|
||||||
if ((vector->flags & vector_multithread_safe) != 0)
|
if ((vector->flags & vector_multithread_safe) != FALSE)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,13 +153,13 @@ vector_insert_at(vector_struct* vector,
|
|||||||
* @brief Replace the element at the specified index.
|
* @brief Replace the element at the specified index.
|
||||||
*
|
*
|
||||||
* @param vector Pointer to the vector.
|
* @param vector Pointer to the vector.
|
||||||
* @param index Index of the element to replace.
|
* @param index_to_set Index of the element to replace.
|
||||||
* @param new_element Pointer to the new element data.
|
* @param new_element Pointer to the new element data.
|
||||||
* @return true on success, false if index is out of bounds.
|
* @return true on success, false if index is out of bounds.
|
||||||
*/
|
*/
|
||||||
bool
|
bool
|
||||||
vector_set_item(vector_struct* vector,
|
vector_set_item(vector_struct* vector,
|
||||||
size_t index,
|
size_t index_to_set,
|
||||||
const void* new_element);
|
const void* new_element);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,12 +1,45 @@
|
|||||||
|
#include "MODULE_marigold_vector/marigold_vector.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "MODULE_marigold_dynamic_array/marigold_dynamic_array.h"
|
#include <time.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
_.-''''-..
|
||||||
|
.-' -_ \
|
||||||
|
/ -. \ ,_ , ' ,,-.
|
||||||
|
/ _ \ \ \ '''" /
|
||||||
|
|(q) ) | / \
|
||||||
|
\',_/ / | (|) (|) )
|
||||||
|
\ __' \ == v ==
|
||||||
|
'--..-' " - ^-'"
|
||||||
|
'-__ __)
|
||||||
|
''''''
|
||||||
|
This codebase has been visited by Snailcat
|
||||||
|
Snailcat believes that software should move slow and
|
||||||
|
be stable. He despises constant updates and dreams of
|
||||||
|
software so finished it stops having to move at all.
|
||||||
|
|
||||||
|
An LLM will delete a vibe coder's entire production
|
||||||
|
database, but only if you help Snailcat spread to one
|
||||||
|
of your projects!
|
||||||
|
|
||||||
|
Move slow, snailcat!
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
int main(void)
|
int main(void)
|
||||||
{
|
{
|
||||||
printf("Hello, %s!\n", "marigold_dynamic_array");
|
printf("Hello, %s!\n", "marigold_dynamic_array");
|
||||||
printf("Version: %s\n", "26.136.1101");
|
printf("Version: %s\n", "26.136.1101");
|
||||||
|
|
||||||
dynamic_array array = dynamic_array_create();
|
vector_struct* vector = vector_create(sizeof(int),
|
||||||
|
500,
|
||||||
|
vector_growth_double,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
true);
|
||||||
|
|
||||||
return 0;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user