Compare commits

..

No commits in common. "b1dd9baf98ba5496a606cced00ca7ccde0df36db" and "457de07ecb02822d5e309c188bdcdba1ce2cdc59" have entirely different histories.

8 changed files with 458 additions and 427 deletions

View File

@ -8,21 +8,22 @@
#include "display.h"
#include "errors.h"
int create_asset(asset_t *asset, va_list args)
asset_t *create_asset(asset_type_t asset_type)
{
asset_t *asset = malloc(sizeof(asset_t));
if(!asset)
{
error_printf("Failed to allocate memory : %d", errno);
return EXIT_FAILURE;
return NULL;
}
asset->type = va_arg(args, asset_type_t);
asset->type = asset_type;
asset->nb_refs = 0;
return EXIT_SUCCESS;
return asset;
}
int destroy_asset(asset_t *asset)
void destroy_asset(asset_t *asset)
{
free(asset->name);
@ -37,22 +38,21 @@ int destroy_asset(asset_t *asset)
break;
}
return EXIT_SUCCESS;
free(asset);
}
int destroy_asset_header_def(asset_header_def_t *asset_header_def)
void destroy_asset_header_def(asset_header_def_t *asset_header_def)
{
free(asset_header_def->name);
return EXIT_SUCCESS;
free(asset_header_def);
}
int asset_manager_init(asset_manager_t *asset_manager)
{
assert("Asset manager cannot be NULL" && asset_manager);
linked_list_init(&asset_manager->assets, sizeof(asset_t), (allocator_t)create_asset, (deleter_t)destroy_asset);
linked_list_init(&asset_manager->assets_header_defs, sizeof(asset_header_def_t), NULL, (deleter_t)destroy_asset_header_def);
linked_list_init(&asset_manager->assets, sizeof(asset_t), (deleter_t)destroy_asset);
linked_list_init(&asset_manager->assets_header_defs, sizeof(asset_header_def_t), (deleter_t)destroy_asset_header_def);
asset_manager->asset_file = fopen(ASSET_FILE_NAME, "rb");
if(!asset_manager->asset_file)
@ -69,34 +69,28 @@ int asset_manager_init(asset_manager_t *asset_manager)
return EXIT_FAILURE;
}
if(linked_list_reserve(&asset_manager->assets_header_defs, nb_assets + 1)) return EXIT_FAILURE;
for(size_t i = 0; i < nb_assets; i++)
{
elem_t *asset_header_def_elem = create_elem(&asset_manager->assets_header_defs);
if(!asset_header_def_elem) return EXIT_FAILURE;
asset_header_def_t *asset_header_def = asset_header_def_elem->data;
elem_t *elem = elem_create(&asset_manager->assets_header_defs);
if(!elem) return EXIT_FAILURE;
size_t cap = 0;
char *asset_name;
ret = getdelim(&asset_name, &cap, '\0', asset_manager->asset_file);
ret = getdelim(&((asset_header_def_t *)elem->data)->name, &cap, '\0', asset_manager->asset_file);
if(ret == SIZE_MAX)
{
error_printf("Failed to read asset file.");
return EXIT_FAILURE;
}
asset_header_def->name = calloc(strlen(asset_name) + 1, sizeof(char));
strcpy(asset_header_def->name, asset_name);
ret = fread(&asset_header_def->start, sizeof(asset_header_def->start), 1, asset_manager->asset_file);
ret = fread(&((asset_header_def_t *)elem->data)->start, sizeof(((asset_header_def_t *)elem->data)->start), 1, asset_manager->asset_file);
if(ret != 1)
{
error_printf("Failed to read asset file.");
return EXIT_FAILURE;
}
if(linked_list_push_back(&asset_manager->assets_header_defs, asset_header_def_elem)) return EXIT_FAILURE;
if(linked_list_push_back_elem(&asset_manager->assets_header_defs, elem)) return EXIT_FAILURE;
}
debug_printf("Initialized asset manager.");
@ -107,8 +101,8 @@ int asset_manager_exit(asset_manager_t *asset_manager)
{
assert("Asset manager cannot be NULL" && asset_manager);
if(linked_list_clear(&asset_manager->assets_header_defs)) return EXIT_FAILURE;
if(linked_list_clear(&asset_manager->assets)) return EXIT_FAILURE;
linked_list_clear(&asset_manager->assets_header_defs);
linked_list_clear(&asset_manager->assets);
if(fclose(asset_manager->asset_file))
{
@ -131,9 +125,7 @@ inline int asset_manager_collect_garbage(asset_manager_t *asset_manager)
{
assert("Asset manager cannot be NULL" && asset_manager);
if(linked_list_remove_if(&asset_manager->assets, condition_is_asset_unused)) return EXIT_FAILURE;
return EXIT_SUCCESS;
return linked_list_remove_if(&asset_manager->assets, condition_is_asset_unused);
}
// Only for this file
@ -218,31 +210,21 @@ int asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_n
assert("Asset manager cannot be NULL" && asset_manager);
// Check if asset has alread been loaded.
elem_t *asset_elem = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
if(asset_elem)
{
((asset_t *)asset_elem->data)->nb_refs++;
debug_printf("Asset \"%s\" has already been loaded, nb refs : %lu", ((asset_t *)asset_elem->data)->name, ((asset_t *)asset_elem->data)->nb_refs);
return EXIT_SUCCESS;
}
else
asset_t *asset = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
if(!asset)
{
// If it didn't, load it
elem_t *asset_header_def_elem = linked_list_get_if(&asset_manager->assets_header_defs, condition_is_asset_header_def_name, asset_name);
if(!asset_header_def_elem)
asset_header_def_t *asset_header_def = linked_list_get_if(&asset_manager->assets_header_defs, condition_is_asset_header_def_name, asset_name);
if(!asset_header_def)
{
error_printf("Asset doesn't exist in asset file : %s", asset_name);
return EXIT_FAILURE;
}
asset_header_def_t *asset_header_def = asset_header_def_elem->data;
asset_elem = create_elem(&asset_manager->assets, asset_type);
if(!asset_elem) return EXIT_FAILURE;
asset_t *asset = asset_elem->data;
asset = create_asset(asset_type);
if(!asset) return EXIT_FAILURE;
asset->name = calloc(strlen(asset_name) + 1, sizeof(char));
asset->name = malloc(strlen(asset_name) + 1);
if(!asset->name)
{
error_printf("Failed to allocate memory for asset name : %d", errno);
@ -261,56 +243,46 @@ int asset_manager_load_asset(asset_manager_t *asset_manager, const char *asset_n
default:
error_printf("Asset type doesn't exists : %d", asset_type);
destroy_asset(asset);
return EXIT_FAILURE;
}
asset->nb_refs++;
linked_list_push_back(&asset_manager->assets, asset_elem);
debug_printf("Asset \"%s\" has been loaded, nb refs : %lu", asset->name, asset->nb_refs);
return EXIT_SUCCESS;
linked_list_push_back(&asset_manager->assets, asset);
}
asset->nb_refs++;
debug_printf("Asset \"%s\" has been loaded, nb refs : %lu", asset->name, asset->nb_refs);
return EXIT_SUCCESS;
}
int asset_manager_let_go_asset(asset_manager_t *asset_manager, const char *asset_name)
{
assert("Asset manager cannot be NULL" && asset_manager);
elem_t *asset_elem = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
if(!asset_elem)
asset_t *asset = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
if(!asset)
{
error_printf("Asset doesn't exists : %s", asset_name);
return EXIT_FAILURE;
}
asset_t *asset = asset_elem->data;
asset->nb_refs--;
debug_printf("Asset \"%s\" has been let go, nb refs : %lu", asset->name, asset->nb_refs);
return EXIT_SUCCESS;
}
texture_t *asset_manager_get_texture(asset_manager_t *asset_manager, const char *texture_name)
texture_t *asset_manager_get_texture(asset_manager_t *asset_manager, const char *asset_name)
{
assert("Asset manager cannot be NULL" && asset_manager);
elem_t *asset_elem = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, texture_name);
if(!asset_elem)
asset_t *asset = linked_list_get_if(&asset_manager->assets, condition_is_asset_name, asset_name);
if(!asset)
{
error_printf("Asset \"%s\" hasn't been loaded yet.", texture_name);
error_printf("Asset \"%s\" hasn't been loaded yet.", asset_name);
return NULL;
}
asset_t *asset = asset_elem->data;
if(asset->type != ASSET_TEXTURE)
{
error_printf("Asset \"%s\" isn't of type ASSET_TEXTURE.", texture_name);
error_printf("Asset \"%s\" isn't of type ASSET_TEXTURE.", asset_name);
return NULL;
}

View File

@ -33,6 +33,8 @@ inline int display_init(void)
for(int i = 0; i < NB_DRIVERS; i++)
debug_printf("%d : %s", i, SDL_GetRenderDriver(i));
const char *DRIVERS = "vulkan,gpu,software";
warning_printf("This build of 2D_Engine_C only support the following drivers : %s", DRIVERS);
renderer = SDL_CreateRenderer(window, DRIVERS);

171
src/ecs.c
View File

@ -4,17 +4,18 @@
#include "components.h"
#include "errors.h"
int create_component(component_t *component, va_list args)
component_t *create_component(component_type_t component_type)
{
component_t *component = malloc(sizeof(component_t));
if(!component)
{
error_printf("Component cannot be NULL");
return EXIT_FAILURE;
error_printf("Failed to allocate memory : %d", errno);
return NULL;
}
component->component_type = va_arg(args, component_type_t);
component->component_type = component_type;
switch(component->component_type)
switch(component_type)
{
#define COMPONENT(NAME, PREFIX, DRAW) \
case NAME: \
@ -24,78 +25,63 @@ int create_component(component_t *component, va_list args)
component->component_data = malloc(sizeof(PREFIX##_data_t)); \
if(!component->component_data) \
{ \
free(component); \
error_printf("Failed to allocate memory : %d", errno); \
return EXIT_FAILURE; \
return NULL; \
} \
component->component_deleter = PREFIX##_destroy; \
break;
#include "components.def"
default:
error_printf("Component type doesn't exists : %d", component->component_type);
return EXIT_FAILURE;
free(component);
error_printf("Component type doesn't exists : %d", component_type);
return NULL;
}
return EXIT_SUCCESS;
}
inline int destroy_component(component_t *component)
{
if(!component)
{
error_printf("Component cannot be NULL");
return EXIT_FAILURE;
}
if(component->component_deleter(component)) return EXIT_FAILURE;
return EXIT_SUCCESS;
}
int create_entity(entity_t *entity, va_list args)
{
if(!entity)
{
error_printf("Entity cannot be NULL");
return EXIT_FAILURE;
}
entity->id = va_arg(args, size_t);
entity->draw_priority = 0;
linked_list_init(&entity->components, sizeof(component_t), (allocator_t)create_component, (deleter_t)destroy_component);
return EXIT_SUCCESS;
}
inline int destroy_entity(entity_t *entity)
{
if(!entity)
{
error_printf("Entity cannot be NULL");
return EXIT_FAILURE;
}
if(linked_list_clear(&entity->components)) return EXIT_FAILURE;
return EXIT_SUCCESS;
}
component_t *entity_new_component(entity_t *entity, component_type_t component_type)
{
elem_t *component_elem = create_elem(&entity->components, component_type);
if(!component_elem) return NULL;
component_t *component = component_elem->data;
component->entity = entity;
if(component->component_init(component)) return NULL;
if(linked_list_push_front(&entity->components, component_elem)) return NULL;
return component;
}
inline void destroy_component(component_t *component)
{
component->component_deleter(component);
free(component);
}
entity_t *create_entity(const unsigned int id)
{
entity_t *entity = malloc(sizeof(entity_t));
if(!entity)
{
error_printf("Failed to allocate memory : %d", errno);
return NULL;
}
entity->id = id;
entity->draw_priority = 0;
linked_list_init(&entity->components, sizeof(component_t), (deleter_t)destroy_component);
return entity;
}
void add_component(entity_t *entity, component_t *component, ...)
{
component->entity = entity;
va_list args, args_copy;
va_start(args, component);
va_copy(args_copy, args);
component->component_init(component, args_copy);
va_end(args_copy);
va_end(args);
linked_list_push_back(&entity->components, component);
}
// Only for this file
// Arg : component_type_t component_type
static inline bool condition_is_component_type(elem_t *elem, va_list args)
@ -103,13 +89,12 @@ static inline bool condition_is_component_type(elem_t *elem, va_list args)
return ((component_t *)elem->data)->component_type == va_arg(args, component_type_t);
}
inline component_t *entity_get_component(entity_t *entity, component_type_t component_type)
inline component_t *get_component(entity_t *entity, component_type_t component_type)
{
elem_t *elem = linked_list_get_if(&entity->components, condition_is_component_type, component_type);
component_t *component = elem->data;
component_t *component = linked_list_get_if(&entity->components, condition_is_component_type, component_type);
if(!component)
{
error_printf("Entity with id:%lu doesn't have componant of type : %d", entity->id, component_type);
error_printf("Entity with id:%d doesn't have componant of type : %d", entity->id, component_type);
return NULL;
}
@ -121,16 +106,14 @@ inline component_t *entity_get_component(entity_t *entity, component_type_t comp
static inline int action_update_component(elem_t *elem, va_list args __attribute__((unused)))
{
component_t *component = elem->data;
if(component->component_update(component)) return EXIT_FAILURE;
component->component_update(component);
return EXIT_SUCCESS;
}
inline int update_entity(entity_t *entity)
{
if(linked_list_for_each(&entity->components, action_update_component)) return EXIT_FAILURE;
return EXIT_SUCCESS;
return linked_list_for_each(&entity->components, action_update_component);
}
// Only for this file
@ -138,39 +121,39 @@ inline int update_entity(entity_t *entity)
static inline int action_draw_component(elem_t *elem, va_list args __attribute__((unused)))
{
component_t *component = elem->data;
if(component->component_draw) if(component->component_draw(component)) return EXIT_FAILURE;
if(component->component_draw) component->component_draw(component);
return EXIT_SUCCESS;
}
inline int draw_entity(entity_t *entity)
{
if(linked_list_for_each(&entity->components, action_draw_component)) return EXIT_FAILURE;
return linked_list_for_each(&entity->components, action_draw_component);
}
return EXIT_SUCCESS;
inline void destroy_entity(entity_t *entity)
{
linked_list_clear(&entity->components);
free(entity);
}
inline void entity_manager_init(entity_manager_t *entity_manager)
{
assert("Entity manager cannot be NULL" && entity_manager);
linked_list_init(&entity_manager->entities, sizeof(entity_t), (allocator_t)create_entity, (deleter_t)destroy_entity);
linked_list_init(&entity_manager->entities, sizeof(entity_t), (deleter_t)destroy_entity);
debug_printf("Initialized entity manager.");
}
inline entity_t *entity_manager_new_entity(entity_manager_t *entity_manager, size_t id)
inline int entity_manager_add_entity(entity_manager_t *entity_manager, entity_t *entity)
{
assert("Entity manager cannot be NULL" && entity_manager);
elem_t *entity_elem = create_elem(&entity_manager->entities, id);
if(!entity_elem) return NULL;
if(linked_list_push_back(&entity_manager->entities, entity)) return EXIT_FAILURE;
if(linked_list_push_back(&entity_manager->entities, entity_elem)) return NULL;
debug_printf("Added entity %d to entity manager.", entity->id);
debug_printf("Added entity %lu to entity manager.", id);
return entity_elem->data;
return EXIT_SUCCESS;
}
// Only for this file
@ -184,9 +167,7 @@ inline int entity_manager_update(entity_manager_t *entity_manager)
{
assert("Entity manager cannot be NULL" && entity_manager);
if(linked_list_for_each(&entity_manager->entities, action_update_entity)) return EXIT_FAILURE;
return EXIT_SUCCESS;
return linked_list_for_each(&entity_manager->entities, action_update_entity);
}
// Only for this file
@ -200,9 +181,7 @@ inline int entity_manager_draw(entity_manager_t *entity_manager)
{
assert("Entity manager cannot be NULL" && entity_manager);
if(linked_list_for_each(&entity_manager->entities, action_draw_entity)) return EXIT_FAILURE;
return EXIT_SUCCESS;
return linked_list_for_each(&entity_manager->entities, action_draw_entity);
}
// Only for this file
@ -216,18 +195,14 @@ inline int entity_manager_remove_entity(entity_manager_t *entity_manager, unsign
{
assert("Entity manager cannot be NULL" && entity_manager);
if(linked_list_remove_if(&entity_manager->entities, condition_is_entity_name, id)) return EXIT_FAILURE;
return EXIT_SUCCESS;
return linked_list_remove_if(&entity_manager->entities, condition_is_entity_name, id);
}
inline int entity_manager_exit(entity_manager_t *entity_manager)
inline void entity_manager_exit(entity_manager_t *entity_manager)
{
assert("Entity manager cannot be NULL" && entity_manager);
if(linked_list_clear(&entity_manager->entities)) return EXIT_FAILURE;
linked_list_clear(&entity_manager->entities);
debug_printf("Exited entity manager.");
return EXIT_SUCCESS;
}

View File

@ -25,16 +25,16 @@ typedef struct asset_t {
asset_type_t type;
} asset_t;
int create_asset(asset_t *asset, va_list args);
asset_t *create_asset(asset_type_t asset_type);
int destroy_asset(asset_t *asset);
void destroy_asset(asset_t *asset);
typedef struct asset_header_def_t {
char *name;
size_t start;
} asset_header_def_t;
int destroy_asset_header_def(asset_header_def_t *asset_header_def);
void destroy_asset_header_def(asset_header_def_t *asset_header_def);
typedef struct asset_manager_t {
linked_list_t assets_header_defs;

View File

@ -10,9 +10,6 @@
#define DISPLAY_HEIGHT 224
#define RENDER_SCALE 2
#define DRIVERS "vulkan,gpu,software"
extern SDL_Window *window;
extern SDL_Renderer *renderer;

View File

@ -14,13 +14,13 @@ typedef enum component_type_t {
typedef struct component_t component_t;
// Component init function. It is called when component added to entity. This function is necessary.
typedef int (*component_init_t)(component_t *component);
typedef int (*component_init_t)(component_t *component, va_list args);
// Component update function. It is called in the main loop to update the component. This function is necessary.
typedef int (*component_update_t)(component_t *component);
// Component draw function. It is called in the main loop to draw the component on screen. This function is not necessary.
typedef int (*component_draw_t)(component_t *component);
// Component deleter function. It is called when the component is removed. It should free the data in the component data but not the component itself.
typedef int (*component_deleter_t)(component_t *component);
typedef void (*component_deleter_t)(component_t *component);
typedef struct component_t {
component_init_t component_init;
@ -37,35 +37,35 @@ typedef struct component_t {
} component_t;
int create_component(component_t *component, va_list args);
component_t *create_component(component_type_t component_type);
int destroy_component(component_t *component);
void destroy_component(component_t *component);
typedef struct entity_t {
size_t id;
unsigned int id;
size_t draw_priority;
linked_list_t components;
} entity_t;
int create_entity(entity_t *entity, va_list args);
entity_t *create_entity(const unsigned int id);
int destroy_entity(entity_t *entity);
void add_component(entity_t *entity, component_t *component, ...);
component_t *entity_new_component(entity_t *entity, component_type_t component_type);
component_t *entity_get_component(entity_t *entity, component_type_t component_type);
component_t *get_component(entity_t *entity, component_type_t component_type);
int update_entity(entity_t *entity);
int draw_entity(entity_t *entity);
void destroy_entity(entity_t *entity);
typedef struct entity_manager_t {
linked_list_t entities;
} entity_manager_t;
void entity_manager_init(entity_manager_t *entity_manager);
entity_t *entity_manager_new_entity(entity_manager_t *entity_manager, size_t id);
int entity_manager_add_entity(entity_manager_t *entity_manager, entity_t *entity);
int entity_manager_update(entity_manager_t *entity_manager);
@ -73,6 +73,6 @@ int entity_manager_draw(entity_manager_t *entity_manager);
int entity_manager_remove_entity(entity_manager_t *entity_manager, const unsigned int id);
int entity_manager_exit(entity_manager_t *entity_manager);
void entity_manager_exit(entity_manager_t *entity_manager);
#endif // ECS_H

View File

@ -21,188 +21,174 @@ typedef struct elem_t {
} elem_t;
/**
* @brief A type for allocators used during the creation of data stored in elements' data.
*
* During the initialisation of linked lists you can pass in argument an allocator.
* You can pass NULL to the initialisation to not use an allocator.
* Your allocator_t function declaration must look like this :
*
* int name_of_your_allocator(void* data, va_list args);
*
* Then do what you need to fill your data.
*
* @param data Data to fill.
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
*/
typedef int (*allocator_t)(void *data, va_list args);
/**
* @brief A type for deleters used during the destruction of data stored in elements' data.
* @brief A type for deleters used during the destruction of data stored in elements.
*
* During the initialisation of linked lists you can pass in argument a deleter.
* You can pass NULL to the initialisation to not use a deleter.
* It is used during the destruction of an element.
* You can pass NULL to the initialisation to use the default deleter (free(elem->data)).
* Your deleter_t function declaration must look like this :
*
* void name_of_your_deleter(void *data);
*
* Then do what you need to destroy your data (don't free the data itself).
*
* @param data Data to free.
* Then do what you need to destroy your data (don't forget to free the data itself...) but not the elements.
* You should always define your function with "inline" if it's no too long.
*/
typedef int (*deleter_t)(void *data);
typedef void (*deleter_t)(void *data);
/**
* @brief A type for condition used for function like linked_list_remove_if.
* @brief A type for condition used for function like linked_list_remove_if
*
* For function like linked_list_remove_if you need a condition.
* It have two argument which are "elem_t *" and "va_list", that is because it passes the element on the actual index
* and the args passed to the function.
* Your condition_t function declaration must look like this :
*
* bool name_of_your_condition(elem_t *elem, va_list);
*
* @param elem Processed element
* @param args Arguments to pass to the function
*
* @return False, true for the element to be removed.
* Then return true if you want the element to be removed from the list or false if not.
* You should always define your function with "static", and "inline".
*/
typedef bool (*condition_t)(elem_t *elem, va_list args);
/**
* @brief A type for action used for function like linked_list_for_each
*
* For function like linked_list_for_each you need an action to do.
* It have two argument which are "elem_t *" and "va_list", that is because it passes the element on the actual index
* and the args passed to the function.
* You can use the return value to indicate an error with EXIT_SUCCESS or EXIT_FAILURE.
* Your condition_t function declaration must look like this :
*
* int name_of_your_condition(elem_t *elem, va_list);
*
* @param elem Processed element
* @param args Arguments to pass to the function
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
* Then do whatever you want with the element data, just don't free it.
* You should always define your function with "static", and "inline".
*/
typedef int (*action_t)(elem_t *elem, va_list args);
/**
* @brief Base of linked lists.
* This struct is the base for creating linked lists.
*
* @param data_size Size of the data stored in elements
* @param allocator Allocator of data when creating new elements
* @param deleter Deleter of data when removing elements
* @param first Pointer to the first element in the list
* @param last Pointer to the last element in the list
* @param size Size of the linked list
* @param reserved Pointer to the first reserved element
* @param target_max_size Total target number of elements in the list
* @param data_size Size of the data stored in elements of the linked list (used while creating new elements)
* @param first Pointer to the first element in the linked list
* @param last Pointer to the last element in the linked list
* @param size Size of the linked list
* @param deleter Deleter of the data when removing an element
*/
typedef struct linked_list_t {
size_t data_size;
allocator_t allocator;
deleter_t deleter;
elem_t *first;
elem_t *last;
size_t size;
elem_t *reserved;
size_t target_max_size;
deleter_t elem_deleter;
} linked_list_t;
/**
* @brief Init a linked list.
* @brief Init a linked list
* This function is necessary if you create a linked list.
*
* @param linked_list Pointer to a linked list
* @param data_size Data size for elements data in the linked list
* @param deleter The deleter for elem
*/
void linked_list_init(linked_list_t *linked_list, size_t data_size, const allocator_t allocator, const deleter_t deleter);
/**
* @brief Pre-allocate elements for a target size.
* If you want n more elements in your list, then you want linked_list.size + n target_size.
*
* @param linked_list Pointer to a linked list
* @param target_size Target size of linked list
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
*/
int linked_list_reserve(linked_list_t *linked_list, size_t target_size);
/**
* @brief Create an elem to insert in a linked list. The data pointer is allocated.
* If there is an element available in reserved list then it will be used.
* WARNING : It doesn't allocate the memory for you !
*
* @param linked_list Pointer to an linked list
* @param ... Arguments to pass to the allocator
*
* @return pointer to initialised elem, NULL on error.
* @param data_size Data size for elements in the linked list
* @param deleter The deleter used during destroyement of an elem
*/
elem_t *create_elem(linked_list_t *linked_list, ...);
void linked_list_init(linked_list_t *linked_list, const size_t data_size, deleter_t deleter);
/**
* @brief Create an elem to fill with data to insert in a linked list.
* This function is usefull when you want to initialise an elem with the proper data_size strored in the linked list.
*
* WARNING : Don't change the "data" ptr after calling this function or it will lead to memory leaks !
* Instead do something like this : *(int *)elem->data = 42;
*
* @param linked_list Pointer to an linked list
*
* @return Address of initialised elem, NULL on error.
*/
elem_t *elem_create(const linked_list_t *linked_list);
/**
* @brief Destroy the given element and its data.
* May move the element into the reserved list for future use depending on target size of the list.
* This function is usefull when you want to free an element.
* The deleter is used for the data only and you can pass NULL to use the default deleter.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
* @param elem_deleter Function to use to free the data
*/
int destroy_elem(linked_list_t *linked_list, elem_t *elem);
void destroy_elem(elem_t *elem, const deleter_t elem_deleter);
/**
* @brief Insert an element from the back in a linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
*/
int linked_list_push_back(linked_list_t *linked_list, elem_t *elem);
int linked_list_push_back_elem(linked_list_t *linked_list, elem_t *elem);
/**
* @brief Insert an element from the front in a linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
*/
int linked_list_push_front(linked_list_t *linked_list, elem_t *elem);
int linked_list_push_front_elem(linked_list_t *linked_list, elem_t *elem);
/**
* @brief Remove and return the last element in the given linked list, do nothing on error.
* @brief Insert an element initialised and filled with data from the back in a linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
*
* @return Pointer to element, NULL on error.
* @param data Pointer to any data
*/
elem_t *linked_list_pop_back(linked_list_t *linked_list);
int linked_list_push_back(linked_list_t *linked_list, void *data);
/**
* @brief Remove and return the first element in the given linked list, do nothing on error.
* @brief Insert an element filled with data from the front in a linked list.
*
* @param linked_list Pointer to a linked list
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
* @param data Pointer to any data
*/
elem_t *linked_list_pop_front(linked_list_t *linked_list);
int linked_list_push_front(linked_list_t *linked_list, void *data);
/**
* @brief Delete the last element in the given linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
*/
int linked_list_pop_back(linked_list_t *linked_list);
/**
* @brief Delete the first element in the given linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
*/
int linked_list_pop_front(linked_list_t *linked_list);
/**
* @brief Clear the given linked list, do nothing on error.
* May move the elements into the reserved list for future use depending on target size of the list.
*
* @brief linked_list Pointer to a linked list
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
*/
int linked_list_clear(linked_list_t *linked_list);
void linked_list_clear(linked_list_t *linked_list);
/**
* @brief Insert element at the given index in the linked list, do nothing on error.
* @brief Check if the given linked list is empty.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
* @param index Index to insert element
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
* @return True if the given linked list is empty else false.
*/
int linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index);
bool linked_list_is_empty(const linked_list_t *linked_list);
/**
* @brief Check if the given index is whithin the range of the linked list.
*
* @param linked_list Pointer to an linked_list_t
*
* @return True if index in within the range of the linked list else false.
*/
bool linked_list_is_in_bound(const linked_list_t *linked_list, const size_t index);
/**
* @brief Get element at the given index in the linked list.
@ -210,31 +196,75 @@ int linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index);
* @param linked_list Pointer to a linked list
* @param index Index of the element
*
* @return Pointer to element, NULL on error.
* @return Element, NULL on error.
*/
elem_t *linked_list_get(const linked_list_t *linked_list, size_t index);
elem_t *linked_list_get_elem(const linked_list_t *linked_list, const size_t index);
/**
* @brief Get data in the element at the given index in the linked list.
*
* @param linked_list Pointer to an linked list
* @param index Index of the wanted element
*
* @return Data, NULL on error.
*/
void *linked_list_get(const linked_list_t *linked_list, const size_t index);
/**
* @brief Insert element at the given index in the linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param elem Pointer to an element
* @param index Index to insert element
*/
int linked_list_insert_elem(linked_list_t *linked_list, elem_t *elem, const size_t index);
/**
* @brief Insert element with data at the given index in the linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param data Data to put in the new element
* @param index Index to insert the element
*/
int linked_list_insert(linked_list_t *linked_list, void *data, const size_t index);
/**
* @brief Remove the given elem in the linked list, do nothing on error.
* May move the elements into the reserved list for future use depending on target size of the list.
*
* @param linked_list Pointer to a linked list
* @param elem Element to remove
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
*/
int linked_list_remove(linked_list_t *linked_list, elem_t *elem);
int linked_list_remove_elem(linked_list_t *linked_list, elem_t *elem);
/**
* @brief Return first element that the condition verify.
* @brief Remove element at the given index in the linked list, do nothing on error.
*
* @param linked_list Pointer to a linked list
* @param index Index of the element
*/
int linked_list_remove(linked_list_t *linked_list, const size_t index);
/**
* @brief Return first element that the condition verify
*
* @param linked_list Pointer to a linked list
* @param condition Condition to verify
* @param ... Argument to pass to the condition
*
* @return Pointer to element, NULL if no element verify the condition or if an error occurred.
* @return Element, NULL if no element verify the condition or if an error ocurred.
*/
elem_t *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, ...);
elem_t *linked_list_get_elem_if(const linked_list_t *linked_list, const condition_t condition, ...);
/**
* @brief Return data in the first element that the condition verify
*
* @param linked_list Pointer to a linked list
* @param condition Condition to verify
* @param ... Argument to pass to the condition
*
* @return Element data, NULL if no element verify the condition or if an error ocurred.
*/
void *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, ...);
/**
* @brief Remove every elements that the condition verify, do nothing on error.
@ -242,20 +272,19 @@ elem_t *linked_list_get_if(const linked_list_t *linked_list, const condition_t c
* @param linked_list Pointer to an linked list
* @param condition Condition to verify
* @param ... Argument to pass to the condition
*
* @return Pointer to element, NULL if no element verify the condition or if an error occurred.
*/
int linked_list_remove_if(linked_list_t *linked_list, const condition_t condition, ...);
/**
* @brief Apply an action to every elements in the list.
* Useful for changing a value in every single element data.
* The action can be anything that doesn't destroy the element.
*
* @param linked_list Pointer to an linked list
* @param action Action to apply
* @param ... Argument to pass to the action
*
* @return EXIT_SUCCESS, EXIT_FAILURE on error.
* @return The success of the action if supported by the action.
*/
int linked_list_for_each(const linked_list_t *linked_list, const action_t action, ...);

View File

@ -3,124 +3,54 @@
#include "linked_list.h"
#include "errors.h"
elem_t *create_elem(linked_list_t *linked_list, ...)
elem_t *elem_create(const linked_list_t *linked_list)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *elem;
if(linked_list->reserved)
elem = malloc(sizeof(elem_t));
if(!elem)
{
elem = linked_list->reserved;
linked_list->reserved = elem->next;
}
else
{
elem = malloc(sizeof(elem_t));
if(!elem)
{
error_printf("Failed to allocate memory : %d", errno);
return NULL;
}
elem->data = malloc(linked_list->data_size);
if(!elem->data)
{
error_printf("Failed to allocate memory : %d", errno);
free(elem);
return NULL;
}
error_printf("Failed to allocate memory : %d", errno);
return NULL;
}
if(linked_list->allocator)
elem->data = malloc(linked_list->data_size);
if(!elem->data)
{
va_list args, args_copy;
va_start(args, linked_list);
va_copy(args_copy, args);
if(linked_list->allocator(elem->data, args_copy)) return NULL;
va_end(args_copy);
va_end(args);
error_printf("Failed to allocate memory : %d", errno);
free(elem);
return NULL;
}
return elem;
}
inline int destroy_elem(linked_list_t *linked_list, elem_t *elem)
inline void destroy_elem(elem_t *elem, const deleter_t elem_deleter)
{
assert("Linked list cannot be NULL" && linked_list);
if(!elem) return; // Not fatal
if(!elem)
{
error_printf("Elem cannot be NULL.");
return EXIT_FAILURE;
}
if(linked_list->deleter)
if(linked_list->deleter(elem->data)) return EXIT_FAILURE;
if(linked_list->size < linked_list->target_max_size)
{
elem->next = linked_list->reserved;
linked_list->reserved = elem;
}
if(elem_deleter)
elem_deleter(elem->data);
else
{
free(elem->data);
free(elem);
}
return EXIT_SUCCESS;
free(elem);
}
void linked_list_init(linked_list_t *linked_list, const size_t data_size, const allocator_t allocator, const deleter_t elem_deleter)
void linked_list_init(linked_list_t *linked_list, const size_t data_size, const deleter_t elem_deleter)
{
assert("Linked list cannot be NULL" && linked_list);
linked_list->data_size = data_size;
linked_list->allocator = allocator;
linked_list->deleter = elem_deleter;
linked_list->first = NULL;
linked_list->last = NULL;
linked_list->size = 0;
linked_list->reserved = NULL;
linked_list->target_max_size = 0;
linked_list->data_size = data_size;
linked_list->elem_deleter = elem_deleter;
}
int linked_list_reserve(linked_list_t *linked_list, size_t target_max_size)
{
assert("Linked list cannot be NULL" && linked_list);
linked_list->target_max_size = target_max_size;
for(size_t i = linked_list->size; i < target_max_size; i++)
{
elem_t *elem = malloc(sizeof(elem_t));
if(!elem)
{
error_printf("Failed to allocate memory : %d", errno);
return EXIT_FAILURE;
}
elem->data = malloc(linked_list->data_size);
if(!elem->data)
{
error_printf("Failed to allocate memory : %d", errno);
free(elem);
return EXIT_FAILURE;
}
elem->next = linked_list->reserved;
linked_list->reserved = elem;
}
return EXIT_SUCCESS;
}
int linked_list_push_back(linked_list_t *linked_list, elem_t *elem)
int linked_list_push_back_elem(linked_list_t *linked_list, elem_t *elem)
{
assert("Linked list cannot be NULL" && linked_list);
@ -145,7 +75,7 @@ int linked_list_push_back(linked_list_t *linked_list, elem_t *elem)
return EXIT_SUCCESS;
}
int linked_list_push_front(linked_list_t *linked_list, elem_t *elem)
int linked_list_push_front_elem(linked_list_t *linked_list, elem_t *elem)
{
assert("Linked list cannot be NULL" && linked_list);
@ -170,74 +100,110 @@ int linked_list_push_front(linked_list_t *linked_list, elem_t *elem)
return EXIT_SUCCESS;
}
elem_t *linked_list_pop_back(linked_list_t *linked_list)
int linked_list_push_back(linked_list_t *linked_list, void *data)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *elem = linked_list->last;
if(!elem)
elem_t *tmp = malloc(sizeof(elem_t));
if(!tmp)
{
error_printf("Failed to allocate memory : %d", errno);
return EXIT_FAILURE;
}
tmp->data = data;
if(linked_list_push_back_elem(linked_list, tmp)) return EXIT_FAILURE;
return EXIT_SUCCESS;
}
int linked_list_push_front(linked_list_t *linked_list, void *data)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *tmp = malloc(sizeof(elem_t));
if(!tmp)
{
error_printf("Failed to allocate memory : %d", errno);
return EXIT_FAILURE;
}
tmp->data = data;
if(linked_list_push_front_elem(linked_list, tmp)) return EXIT_FAILURE;
return EXIT_SUCCESS;
}
int linked_list_pop_back(linked_list_t *linked_list)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *tmp = linked_list->last;
if(!tmp)
{
error_printf("No elem to pop back.");
return NULL;
return EXIT_FAILURE;
}
linked_list->last = elem->prev;
linked_list->last = tmp->prev;
if(linked_list->last)
linked_list->last->next = NULL;
else
linked_list->first = NULL;
destroy_elem(tmp, linked_list->elem_deleter);
linked_list->size--;
return elem;
return EXIT_SUCCESS;
}
elem_t *linked_list_pop_front(linked_list_t *linked_list)
int linked_list_pop_front(linked_list_t *linked_list)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *elem = linked_list->first;
if(!elem)
elem_t *tmp = linked_list->first;
if(!tmp)
{
error_printf("No elem to pop front.");
return NULL;
return EXIT_FAILURE;
}
linked_list->first = elem->next;
linked_list->first = tmp->next;
if(linked_list->first)
linked_list->first->prev = NULL;
else
linked_list->last = NULL;
destroy_elem(tmp, linked_list->elem_deleter);
linked_list->size--;
return elem;
return EXIT_SUCCESS;
}
int linked_list_clear(linked_list_t *linked_list)
void linked_list_clear(linked_list_t *linked_list)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *current_elem = linked_list->first;
elem_t *actual_elem = linked_list->first;
elem_t *tmp;
while(current_elem)
while(actual_elem)
{
tmp = current_elem;
tmp = actual_elem;
current_elem = current_elem->next;
actual_elem = actual_elem->next;
if(destroy_elem(linked_list, tmp)) return EXIT_FAILURE;
destroy_elem(tmp, linked_list->elem_deleter);
}
linked_list->first = NULL;
linked_list->last = NULL;
linked_list->size = 0;
return EXIT_SUCCESS;
}
inline bool linked_list_is_empty(const linked_list_t *linked_list)
@ -247,11 +213,18 @@ inline bool linked_list_is_empty(const linked_list_t *linked_list)
return !linked_list->first;
}
elem_t *linked_list_get(const linked_list_t *linked_list, size_t index)
inline bool linked_list_is_in_bound(const linked_list_t *linked_list, size_t index)
{
assert("Linked list cannot be NULL" && linked_list);
if(index >= linked_list->size)
return index < linked_list->size;
}
elem_t *linked_list_get_elem(const linked_list_t *linked_list, size_t index)
{
assert("Linked list cannot be NULL" && linked_list);
if(!linked_list_is_in_bound(linked_list, index))
{
error_printf("List index out of range.");
return NULL;
@ -262,18 +235,31 @@ elem_t *linked_list_get(const linked_list_t *linked_list, size_t index)
if(index == linked_list->size - 1)
return linked_list->last;
elem_t *current_elem = linked_list->first;
if(!current_elem) return NULL;
elem_t *actual_elem = linked_list->first;
if(!actual_elem) return NULL;
for (size_t i = 0; i < index; i++)
{
current_elem = current_elem->next;
actual_elem = actual_elem->next;
}
return current_elem;
return actual_elem;
}
int linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index) // XXX TODO SIMPLIFY INSERT FUNC XXX //
void *linked_list_get(const linked_list_t *linked_list, size_t index)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *tmp = linked_list_get_elem(linked_list, index);
if(!tmp)
{
error_printf("Failed to get elem.");
return NULL;
}
return tmp->data;
}
int linked_list_insert_elem(linked_list_t *linked_list, elem_t *elem, size_t index)
{
assert("Linked list cannot be NULL" && linked_list);
@ -291,14 +277,14 @@ int linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index) /
if(index == 0)
{
return linked_list_push_front(linked_list, elem);
return linked_list_push_front_elem(linked_list, elem);
}
else if(index == linked_list->size)
{
return linked_list_push_back(linked_list, elem);
return linked_list_push_back_elem(linked_list, elem);
}
elem_t *next_insert_elem = linked_list_get(linked_list, index);
elem_t *next_insert_elem = linked_list_get_elem(linked_list, index);
if(!next_insert_elem) return EXIT_FAILURE;
elem_t *prev_insert_elem = next_insert_elem->prev;
@ -313,7 +299,22 @@ int linked_list_insert(linked_list_t *linked_list, elem_t *elem, size_t index) /
return EXIT_SUCCESS;
}
int linked_list_remove(linked_list_t *linked_list, elem_t *elem)
int linked_list_insert(linked_list_t *linked_list, void *data, size_t index)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *tmp = malloc(sizeof(elem_t));
if(!tmp)
{
error_printf("Failed to allocate memory : %d", errno);
return EXIT_FAILURE;
}
tmp->data = data;
return linked_list_insert_elem(linked_list, tmp, index);
}
int linked_list_remove_elem(linked_list_t *linked_list, elem_t *elem)
{
assert("Linked list cannot be NULL" && linked_list);
@ -323,20 +324,39 @@ int linked_list_remove(linked_list_t *linked_list, elem_t *elem)
return EXIT_FAILURE;
}
if(elem == linked_list->first)
{
return linked_list_pop_front(linked_list);
}
else if(elem == linked_list->last)
{
return linked_list_pop_back(linked_list);
}
elem_t *prev_elem = elem->prev;
elem_t *next_elem = elem->next;
if(prev_elem) prev_elem->next = next_elem;
if(next_elem) next_elem->prev = prev_elem;
prev_elem->next = next_elem;
next_elem->prev = prev_elem;
if(destroy_elem(linked_list, elem)) return EXIT_FAILURE;
destroy_elem(elem, linked_list->elem_deleter);
linked_list->size--;
return EXIT_SUCCESS;
}
elem_t *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, ...)
int linked_list_remove(linked_list_t *linked_list, size_t index)
{
assert("Linked list cannot be NULL" && linked_list);
elem_t *tmp = linked_list_get_elem(linked_list, index);
if(!tmp) return EXIT_FAILURE;
return linked_list_remove_elem(linked_list, tmp);
}
elem_t *linked_list_get_elem_if(const linked_list_t *linked_list, const condition_t condition, ...)
{
assert("Linked list cannot be NULL" && linked_list);
assert("Condition cannot be NULL" && condition);
@ -344,27 +364,63 @@ elem_t *linked_list_get_if(const linked_list_t *linked_list, const condition_t c
va_list args;
va_start(args, condition);
elem_t *current_elem = linked_list->first;
elem_t *actual_elem = linked_list->first;
elem_t *next_elem;
while(current_elem)
while(actual_elem)
{
next_elem = current_elem->next;
next_elem = actual_elem->next;
va_list args_copy;
va_copy(args_copy, args);
if(condition(current_elem, args_copy))
if(condition(actual_elem, args_copy))
{
va_end(args_copy);
va_end(args);
return current_elem;
return actual_elem;
}
va_end(args_copy);
current_elem = next_elem;
actual_elem = next_elem;
}
va_end(args);
return NULL;
}
void *linked_list_get_if(const linked_list_t *linked_list, const condition_t condition, ...)
{
assert("Linked list cannot be NULL" && linked_list);
assert("Condition cannot be NULL" && condition);
va_list args;
va_start(args, condition);
elem_t *actual_elem = linked_list->first;
elem_t *next_elem;
while(actual_elem)
{
next_elem = actual_elem->next;
va_list args_copy;
va_copy(args_copy, args);
if(condition(actual_elem, args_copy))
{
va_end(args_copy);
va_end(args);
return actual_elem->data;
}
va_end(args_copy);
actual_elem = next_elem;
}
va_end(args);
@ -392,7 +448,7 @@ int linked_list_remove_if(linked_list_t *linked_list, const condition_t conditio
if(condition(actual_elem, args_copy))
{
if(linked_list_remove(linked_list, actual_elem))
if(linked_list_remove_elem(linked_list, actual_elem))
{
va_end(args_copy);
va_end(args);
@ -419,14 +475,14 @@ int linked_list_for_each(const linked_list_t *linked_list, const action_t action
va_list args;
va_start(args, action);
elem_t *current_elem = linked_list->first;
elem_t *actual_elem = linked_list->first;
while(current_elem)
while(actual_elem)
{
va_list args_copy;
va_copy(args_copy, args);
if(action(current_elem, args_copy))
if(action(actual_elem, args_copy))
{
va_end(args_copy);
va_end(args);
@ -436,7 +492,7 @@ int linked_list_for_each(const linked_list_t *linked_list, const action_t action
va_end(args_copy);
current_elem = current_elem->next;
actual_elem = actual_elem->next;
}
va_end(args);