Added shadow tag registry

This commit is contained in:
Eric-Paul Ickhorn 2024-02-20 07:35:53 +01:00
parent 324d5e427c
commit 726c231561
8 changed files with 446 additions and 5 deletions

View File

@ -11,6 +11,12 @@ RELEASE_CC_OPTIONS="-O3 -Wall"
MAIN_OBJECTS_FOLDER="$REPOSITORY_FOLDER/.build/objects" MAIN_OBJECTS_FOLDER="$REPOSITORY_FOLDER/.build/objects"
CONFIG_FILE_INCLUDE_PATHS="build-config/include_paths.txt" CONFIG_FILE_INCLUDE_PATHS="build-config/include_paths.txt"
DEFAULT_TEST_LINKAGE_PATHS=".build/maintree-core.a .build/librr-core.a .build/librr-platform.a"
DEFAULT_TEST_INCLUDE_STATEMENTS="
-I .build/depends/libRR/Core/core/exports
-I .build/depends/libRR/Core/platform/exports
"
function clone_dependencies { function clone_dependencies {
echo "================ Cloning Dependencies! ================" echo "================ Cloning Dependencies! ================"
mkdir -p .build/depends/libRR mkdir -p .build/depends/libRR
@ -116,10 +122,10 @@ function compile_module_c_sources {
cd $REPOSITORY_FOLDER cd $REPOSITORY_FOLDER
} }
function get_linkage_path_configuration() { function get_test_linkage_path_configuration() {
TEST_PATH=$1 TEST_PATH=$1
LINKAGE_PATHS=$DEFAULT_LINKAGE_PATHS LINKAGE_PATHS=$DEFAULT_TEST_LINKAGE_PATHS
if [[ -f "$TEST_PATH/linkage_paths.txt" ]] if [[ -f "$TEST_PATH/linkage_paths.txt" ]]
then then
for LINKAGE_ITEM in $(cat "$TEST_PATH/linkage_paths.txt") for LINKAGE_ITEM in $(cat "$TEST_PATH/linkage_paths.txt")
@ -129,6 +135,17 @@ function get_linkage_path_configuration() {
fi fi
} }
function get_test_include_path_configuration() {
INCLUDE_PATHS=$DEFAULT_TEST_INCLUDE_STATEMENTS
if [[ -f "$TEST_PATH/include_paths.txt" ]]
then
for INCLUDE_ITEM in $(cat "$TEST_PATH/include_paths.txt")
do
INCLUDE_PATHS="$INCLUDE_PATHS -I $REPOSITORY_FOLDER/$INCLUDE_ITEM"
done
fi
}
function compile_single_test() { function compile_single_test() {
TEST_PATH=$1 TEST_PATH=$1
TEST_NAME=$(basename $TEST_PATH) TEST_NAME=$(basename $TEST_PATH)
@ -137,9 +154,10 @@ function compile_single_test() {
# TODO: As a small improvement, the tests could be able to have multiple sub-folders for sources. # TODO: As a small improvement, the tests could be able to have multiple sub-folders for sources.
get_include_path_configuration $TEST_PATH get_test_include_path_configuration $TEST_PATH
get_linkage_path_configuration $TEST_PATH get_test_linkage_path_configuration $TEST_PATH
gcc $CC_OPTIONS -o $TEST_PATH/$TEST_NAME.elf $TEST_PATH/*.c $LINKAGE_PATHS $INCLUDE_STATEMENTS echo $INCLUDE_PATHS
gcc $CC_OPTIONS -o $TEST_PATH/$TEST_NAME.elf $TEST_PATH/*.c $LINKAGE_PATHS $INCLUDE_PATHS
} }
function compile_all_tests_of_module() { function compile_all_tests_of_module() {

View File

@ -0,0 +1 @@
tests/internal/shadow-tag

13
core/inc-c/context.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef MT_CONTEXT_H
#define MT_CONTEXT_H
#include <librr/types.h>
#include <shadow-tag.h>
typedef struct MtContext
{
MtShadowTagSystem shadow_tag_system;
} MtContext;
#endif // MT_CONTEXT_H

24
core/inc-c/entity.h Normal file
View File

@ -0,0 +1,24 @@
#ifndef MT_ENTITY_H
#define MT_ENTITY_H
#include <librr/types.h>
typedef struct MtEntity MtEntity;
/// @brief: An MtEntity is a frontend descriptor which stands in
/// the place of internal data without the need to reference
/// actual internal data.
struct MtEntity
{
/// @brief: The context which this MtEntity belongs to. This is
/// also the context which is referenced each time a function
/// uses the entity and needs to find its shadow.
void *context;
/// @brief: The identifier of the background structure "shadow".
/// This is used for resolving this entity to its actual data.
u32_t shadow_id;
};
#endif // MT_ENTITY_H

117
core/inc-c/shadow-tag.h Normal file
View File

@ -0,0 +1,117 @@
#ifndef MT_SHADOW_TAG_H
#define MT_SHADOW_TAG_H
#include <librr/types.h>
#include <librr/linear_algebra.h>
#include <entity.h>
typedef struct MtShadowTag MtShadowTag;
typedef struct MtShadowTagPool MtShadowTagPool;
typedef struct MtShadowTagName MtShadowTagName;
typedef struct MtShadowTagNameArena MtShadowTagNameArena;
typedef struct MtShadowTagNameRegistry MtShadowTagNameRegistry;
typedef struct MtShadowTagSystem MtShadowTagSystem;
typedef enum
{
MT_SHADOW_TAG_INTEGER,
MT_SHADOW_TAG_BOOLEAN,
MT_SHADOW_TAG_DECIMAL,
MT_SHADOW_TAG_STRING,
MT_SHADOW_TAG_RAW_POINTER,
MT_SHADOW_TAG_VECTOR_2,
MT_SHADOW_TAG_VECTOR_3,
MT_SHADOW_TAG_VECTOR_4,
MT_SHADOW_TAG_SUB_ENTITY,
MT_SHADOW_TAG_RESOURCE
} MtShadowTagType;
struct MtShadowTag
{
MtShadowTagPool *pool;
MtShadowTag *next;
MtShadowTagType type;
u32_t name_identifier;
union MtShadowTagData
{
bool_t boolean;
i64_t integer;
f64_t decimal;
char *string;
void *raw_pointer;
rr_vec2f_s vec2f;
rr_vec3f_s vec3f;
rr_vec4f_s vec4f;
MtEntity entity;
} data;
};
struct MtShadowTagPool
{
usz_t capacity;
MtShadowTag *allocation;
MtShadowTag *first_free;
MtShadowTagPool *continuation;
};
struct MtShadowTagNameArena
{
usz_t capacity;
usz_t usage;
char *allocation;
MtShadowTagNameArena *continuation;
};
struct MtShadowTagName
{
char *string_in_arena;
u32_t identifier;
};
struct MtShadowTagNameRegistry
{
usz_t names_capacity;
usz_t num_names;
MtShadowTagName *names;
u32_t id_counter;
MtShadowTagNameArena *root_arena;
};
struct MtShadowTagSystem
{
MtShadowTagNameRegistry name_registry;
MtShadowTagPool root_pool;
};
void mt_init_shadow_tag_system(MtShadowTagSystem *tag_system);
void mt_cleanup_shadow_tag_system(MtShadowTagSystem *tag_system);
MtShadowTagPool * mt_new_shadow_tag_pool(usz_t capacity);
/// @brief Crates a new MtShadowTagPool with a given capacity.
/// @warning Don't use `mt_free_shadow_tag_pool()` with use created with this method.
/// It will result in a call to `free()` for the given pool, which may cause a crash.
/// @param pool A pointer to the location at which the pool should be created.
/// @param capacity The number of entity shadow tags which should be able to reside in
/// the first instance of the pool. The pool will allocate more once needed.
void mt_init_shadow_tag_pool(MtShadowTagPool *pool, usz_t capacity);
void mt_free_shadow_tag_pool(MtShadowTagPool *pool);
MtShadowTag * mt_alloc_shadow_tag(void *context_ptr);
MtShadowTag * mt_alloc_shadow_tag_in_pool(MtShadowTagPool *pool);
/// @brief Crates as new MtShadowTag, makes it the new first of the chain given as input and
/// returns the new chain start. The chain start should be set to the returned value
/// @param chain_start The current start of the singly linked list of tags which are
/// attached to a shadow (the start of the tag chain).
/// @return The new tag chain's start.
MtShadowTag * mt_alloc_shadow_tag_before(MtShadowTag *chain_start);
void mt_free_shadow_tag_chain(MtShadowTag *tag);
u32_t mt_tag_name_to_id(void *context_ptr, const char *tag_name);
#endif // MT_SHADOW_TAG_H

187
core/src-c/shadow-tag.c Normal file
View File

@ -0,0 +1,187 @@
#include <shadow-tag.h>
#include <context.h>
#include <librr/memory.h>
#include <librr/strutil.h>
#include <stdlib.h>
void mt_init_shadow_tag_pool_allocation(MtShadowTagPool *pool, usz_t capacity)
{
usz_t slot_index = 0;
while(slot_index < capacity)
{
pool->allocation[slot_index].pool = pool;
pool->allocation[slot_index].next = &pool->allocation[slot_index+1];
++slot_index;
}
pool->allocation[capacity - 1].next = NULL;
}
void mt_init_shadow_tag_pool(MtShadowTagPool *pool, usz_t capacity)
{
pool->capacity = capacity;
pool->allocation = calloc(sizeof(MtShadowTag), capacity);
pool->first_free = pool->allocation;
pool->continuation = NULL;
mt_init_shadow_tag_pool_allocation(pool, capacity);
}
MtShadowTagPool * mt_new_shadow_tag_pool(usz_t capacity)
{
MtShadowTagPool *pool = malloc(sizeof(MtShadowTagPool));
mt_init_shadow_tag_pool(pool, capacity * 2);
return pool;
}
void mt_free_shadow_tag_pool(MtShadowTagPool *pool)
{
if(pool->continuation != NULL)
mt_free_shadow_tag_pool(pool->continuation);
free(pool->allocation);
free(pool);
}
MtShadowTag * mt_alloc_shadow_tag_in_pool(MtShadowTagPool *pool)
{
if(pool->first_free == NULL)
{
if(pool->continuation == NULL)
pool->continuation = mt_new_shadow_tag_pool(pool->capacity * 2);
return mt_alloc_shadow_tag_in_pool(pool->continuation);
}
MtShadowTag *allocated_tag = pool->first_free;
pool->first_free = allocated_tag->next;
// Reset the tag's old data
rr_memset(allocated_tag, sizeof(MtShadowTag), 0x00);
allocated_tag->pool = pool;
return allocated_tag;
}
MtShadowTag * mt_alloc_shadow_tag(void *context_ptr)
{
MtContext *context = context_ptr;
return mt_alloc_shadow_tag_in_pool(&context->shadow_tag_system.root_pool);
}
MtShadowTag * mt_alloc_shadow_tag_before(MtShadowTag *chain_start)
{
MtShadowTag *tag = mt_alloc_shadow_tag_in_pool(chain_start->pool);
tag->next = chain_start;
return tag;
}
void mt_free_shadow_tag_chain(MtShadowTag *tag)
{
MtShadowTagPool *pool = tag->pool;
MtShadowTag *last_tag = tag;
while(last_tag->next != NULL)
{
last_tag = last_tag->next;
}
last_tag->next = pool->first_free;
pool->first_free = tag;
}
void mt_init_shadow_tag_name_arena(MtShadowTagNameArena *arena, usz_t size)
{
arena->usage = 0;
arena->capacity = size;
arena->allocation = malloc(size);
arena->continuation = NULL;
}
MtShadowTagNameArena * mt_new_shadow_tag_name_arena(usz_t size)
{
MtShadowTagNameArena *arena = malloc(sizeof(MtShadowTagNameArena));
mt_init_shadow_tag_name_arena(arena, size);
return arena;
}
void mt_free_shadow_tag_name_arena(MtShadowTagNameArena *arena)
{
if(arena->continuation != NULL)
mt_free_shadow_tag_name_arena(arena->continuation);
free(arena->allocation);
free(arena);
}
void mt_init_shadow_tag_name_registry(MtShadowTagNameRegistry *name_registry)
{
name_registry->root_arena = mt_new_shadow_tag_name_arena(4096);
name_registry->id_counter = 1;
name_registry->num_names = 0;
name_registry->names_capacity = 256;
name_registry->names = calloc(sizeof(MtShadowTagName), name_registry->names_capacity);
}
void mt_cleanup_shadow_tag_name_registry(MtShadowTagNameRegistry *name_registry)
{
mt_free_shadow_tag_name_arena(name_registry->root_arena);
free(name_registry->names);
}
void mt_init_shadow_tag_system(MtShadowTagSystem *tag_system)
{
mt_init_shadow_tag_name_registry(&tag_system->name_registry);
mt_init_shadow_tag_pool(&tag_system->root_pool, 8192);
}
void mt_cleanup_shadow_tag_system(MtShadowTagSystem *tag_system)
{
mt_free_shadow_tag_pool(&tag_system->root_pool);
mt_cleanup_shadow_tag_name_registry(&tag_system->name_registry);
}
char * mt_shadow_tag_name_arena_alloc(MtShadowTagNameArena *arena, usz_t num_bytes)
{
usz_t end_size = arena->usage + num_bytes;
if(end_size >= arena->capacity)
{
if(arena->continuation == NULL)
arena->continuation = mt_new_shadow_tag_name_arena(arena->capacity * 2);
return mt_shadow_tag_name_arena_alloc(arena->continuation, num_bytes);
}
char *allocation = arena->allocation + arena->usage;
arena->usage = end_size;
return allocation;
}
u32_t mt_force_create_new_tag_name_entry(MtShadowTagNameRegistry *name_registry, const char *tag_name)
{
if(name_registry->num_names >= name_registry->names_capacity)
{
name_registry->names_capacity *= 2;
name_registry->names = realloc(name_registry->names, sizeof(MtShadowTagName) * name_registry->names_capacity);
}
MtShadowTagName *name_entry = &name_registry->names[name_registry->num_names++];
usz_t len_tag_name = rr_measure_string(tag_name);
char *tag_name_copy = mt_shadow_tag_name_arena_alloc(name_registry->root_arena, len_tag_name+1);
rr_memcopy(tag_name_copy, tag_name, len_tag_name + 1);
name_entry->string_in_arena = tag_name_copy;
name_entry->identifier = name_registry->id_counter++;
return name_entry->identifier;
}
u32_t mt_tag_name_to_id(void *context_ptr, const char *tag_name)
{
MtContext *context = context_ptr;
MtShadowTagNameRegistry *name_registry = &context->shadow_tag_system.name_registry;
usz_t name_index = 0;
while(name_index < name_registry->num_names)
{
if(rr_strings_equal(name_registry->names[name_index].string_in_arena, tag_name))
return name_registry->names[name_index].identifier;
++name_index;
}
return mt_force_create_new_tag_name_entry(name_registry, tag_name);
}

View File

@ -0,0 +1 @@
core/inc-c

View File

@ -0,0 +1,80 @@
#include <shadow-tag.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
typedef enum
{
TEST_CASE_NONE = 0,
TEST_CASE_SHADOW_TAG_POOL_CREATION,
TEST_CASE_SHADOW_TAG_CHAIN_CREATION,
TEST_CASE_SHADOW_TAG_CHAIN_PREPEND,
TEST_CASE_FREE_SHADOW_TAG_CHAIN,
TEST_CASE_STRESSTEST
} TestCase;
TestCase g_current_test_case = TEST_CASE_NONE;
int g_stresstest_iteration = 0;
const char * stringify_test_case(TestCase test_case)
{
switch(test_case)
{
case TEST_CASE_NONE: return "NONE";
case TEST_CASE_SHADOW_TAG_POOL_CREATION: return "SHADOW_TAG_POOL_CREATION";
case TEST_CASE_SHADOW_TAG_CHAIN_CREATION: return "SHADOW_TAG_CHAIN_CREATION";
case TEST_CASE_SHADOW_TAG_CHAIN_PREPEND: return "SHADOW_TAG_CHAIN_PREPEND";
case TEST_CASE_FREE_SHADOW_TAG_CHAIN: return "FREE_SHADOW_TAG_CHAIN";
case TEST_CASE_STRESSTEST: return "STRESSTEST";
}
return "?";
}
void signal_handler(int number)
{
printf("FAIL: The program crashed because of a memory error in test: %s\n",
stringify_test_case(g_current_test_case));
if(g_current_test_case == TEST_CASE_STRESSTEST)
printf("Iteration: %d\n", g_stresstest_iteration);
exit(-1);
}
void test_heavy_use()
{
g_current_test_case = TEST_CASE_STRESSTEST;
MtShadowTagPool *pool = mt_new_shadow_tag_pool(1024);
MtShadowTag *tag_chain = mt_alloc_shadow_tag_in_pool(pool);
while(g_stresstest_iteration < (1024 * 1024))
{
tag_chain = mt_alloc_shadow_tag_before(tag_chain);
++g_stresstest_iteration;
}
mt_free_shadow_tag_chain(tag_chain);
mt_free_shadow_tag_pool(pool);
}
void test_functionality()
{
g_current_test_case = TEST_CASE_SHADOW_TAG_POOL_CREATION;
MtShadowTagPool *pool = mt_new_shadow_tag_pool(1024);
g_current_test_case = TEST_CASE_SHADOW_TAG_CHAIN_CREATION;
MtShadowTag *tag_chain = mt_alloc_shadow_tag_in_pool(pool);
g_current_test_case = TEST_CASE_SHADOW_TAG_CHAIN_PREPEND;
tag_chain = mt_alloc_shadow_tag_before(tag_chain);
g_current_test_case = TEST_CASE_FREE_SHADOW_TAG_CHAIN;
mt_free_shadow_tag_chain(tag_chain);
mt_free_shadow_tag_pool(pool);
}
int main(int argc, char **argv)
{
signal(SIGSEGV, &signal_handler);
test_functionality();
test_heavy_use();
puts("Success.");
return 0;
}