Added shadow tag registry
This commit is contained in:
parent
324d5e427c
commit
726c231561
28
action.bash
28
action.bash
|
@ -11,6 +11,12 @@ RELEASE_CC_OPTIONS="-O3 -Wall"
|
|||
MAIN_OBJECTS_FOLDER="$REPOSITORY_FOLDER/.build/objects"
|
||||
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 {
|
||||
echo "================ Cloning Dependencies! ================"
|
||||
mkdir -p .build/depends/libRR
|
||||
|
@ -116,10 +122,10 @@ function compile_module_c_sources {
|
|||
cd $REPOSITORY_FOLDER
|
||||
}
|
||||
|
||||
function get_linkage_path_configuration() {
|
||||
function get_test_linkage_path_configuration() {
|
||||
TEST_PATH=$1
|
||||
|
||||
LINKAGE_PATHS=$DEFAULT_LINKAGE_PATHS
|
||||
LINKAGE_PATHS=$DEFAULT_TEST_LINKAGE_PATHS
|
||||
if [[ -f "$TEST_PATH/linkage_paths.txt" ]]
|
||||
then
|
||||
for LINKAGE_ITEM in $(cat "$TEST_PATH/linkage_paths.txt")
|
||||
|
@ -129,6 +135,17 @@ function get_linkage_path_configuration() {
|
|||
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() {
|
||||
TEST_PATH=$1
|
||||
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.
|
||||
|
||||
get_include_path_configuration $TEST_PATH
|
||||
get_linkage_path_configuration $TEST_PATH
|
||||
gcc $CC_OPTIONS -o $TEST_PATH/$TEST_NAME.elf $TEST_PATH/*.c $LINKAGE_PATHS $INCLUDE_STATEMENTS
|
||||
get_test_include_path_configuration $TEST_PATH
|
||||
get_test_linkage_path_configuration $TEST_PATH
|
||||
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() {
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
tests/internal/shadow-tag
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -0,0 +1 @@
|
|||
core/inc-c
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue