red-black tree implemented
This commit is contained in:
parent
d9ec3f4be2
commit
2f0722132d
9
build.sh
9
build.sh
@ -16,6 +16,7 @@ if [ -v webgl ] && [ ! -v render_flag ]; then render_flag="-DSTG_WEBGL_RENDERER"
|
|||||||
if [ -v dx11 ] && [ ! -v render_flag ]; then render_flag="-DSTG_DX11_RENDERER"; echo "[dx11 renderer]"; fi
|
if [ -v dx11 ] && [ ! -v render_flag ]; then render_flag="-DSTG_DX11_RENDERER"; echo "[dx11 renderer]"; fi
|
||||||
if [ -v dx11 ]; then render_link="-l:libdxvk_d3d11.so.0"; fi
|
if [ -v dx11 ]; then render_link="-l:libdxvk_d3d11.so.0"; fi
|
||||||
if [ ! -v render_flag ]; then render_flag="-DSTG_VULKAN_RENDERER"; vulkan="vulkan"; echo "[default renderer - vulkan]"; fi
|
if [ ! -v render_flag ]; then render_flag="-DSTG_VULKAN_RENDERER"; vulkan="vulkan"; echo "[default renderer - vulkan]"; fi
|
||||||
|
if [ -v test ]; then test_build=1; echo "[test build]"; fi
|
||||||
|
|
||||||
# source files
|
# source files
|
||||||
source_files="../src/entry_linux.c"
|
source_files="../src/entry_linux.c"
|
||||||
@ -46,16 +47,17 @@ glsl_stage_geom="-fshader-stage=geom"
|
|||||||
glsl_stage_comp="-fshader-stage=comp"
|
glsl_stage_comp="-fshader-stage=comp"
|
||||||
glsl_out="-o./shaders/glsl/"
|
glsl_out="-o./shaders/glsl/"
|
||||||
|
|
||||||
|
|
||||||
clang_common="${include_flags} ${render_flag} -g -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0"
|
clang_common="${include_flags} ${render_flag} -g -Xclang -flto-visibility-public-std -Wno-unknown-warning-option -fdiagnostics-absolute-paths -Wall -Wno-missing-braces -Wno-unused-function -Wno-writable-strings -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-register -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-single-bit-bitfield-constant-conversion -Wno-compare-distinct-pointer-types -Wno-initializer-overrides -Wno-incompatible-pointer-types-discards-qualifiers -Wno-for-loop-analysis -DVMA_STATIC_VULKAN_FUNCTIONS=0"
|
||||||
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common}"
|
clang_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${clang_common}"
|
||||||
clang_release="$compiler -g -O2 ${clang_common}"
|
clang_release="$compiler -g -O2 ${clang_common}"
|
||||||
|
clang_test="$compiler -O2 -DBUILD_TEST=1 ${clang_common}"
|
||||||
clang_link="-lpthread -lm -lrt -ldl -l:libvma.a"
|
clang_link="-lpthread -lm -lrt -ldl -l:libvma.a"
|
||||||
clang_out="-o"
|
clang_out="-o"
|
||||||
|
|
||||||
gcc_common="${include_flags} ${render_flag} -std=c99 -fuse-ld=mold -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -DVMA_STATIC_VULKAN_FUNCTIONS=0"
|
gcc_common="${include_flags} ${render_flag} -std=c99 -fuse-ld=mold -g -Wno-unknown-warning-option -Wall -Wno-missing-braces -Wno-unused-function -Wno-attributes -Wno-unused-value -Wno-unused-variable -Wno-unused-local-typedef -Wno-deprecated-declarations -Wno-unused-but-set-variable -Wno-compare-distinct-pointer-types -D_USE_MATH_DEFINES -Dstrdup=_strdup -Dgnu_printf=printf -DVMA_STATIC_VULKAN_FUNCTIONS=0"
|
||||||
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common}"
|
gcc_debug="$compiler -g -O0 -DBUILD_DEBUG=1 ${gcc_common}"
|
||||||
gcc_release="$compiler -g -O2 ${gcc_common} ${render_flag}"
|
gcc_release="$compiler -O2 ${gcc_common} ${render_flag}"
|
||||||
|
gcc_test="$compiler -O2 -DBUILD_TEST=1 ${gcc_common} ${render_flag}"
|
||||||
gcc_link="-lpthread -lm -lrt -ldl ${render_link} -lstdc++"
|
gcc_link="-lpthread -lm -lrt -ldl ${render_link} -lstdc++"
|
||||||
gcc_out="-o"
|
gcc_out="-o"
|
||||||
|
|
||||||
@ -64,16 +66,19 @@ link_os_gfx="-lxcb -lX11 -lX11-xcb -lvulkan"
|
|||||||
|
|
||||||
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
|
if [ -v gcc ]; then compile_debug="$gcc_debug"; fi
|
||||||
if [ -v gcc ]; then compile_release="$gcc_release"; fi
|
if [ -v gcc ]; then compile_release="$gcc_release"; fi
|
||||||
|
if [ -v gcc ]; then compile_test="$gcc_test"; fi
|
||||||
if [ -v gcc ]; then compile_link="$gcc_link"; fi
|
if [ -v gcc ]; then compile_link="$gcc_link"; fi
|
||||||
if [ -v gcc ]; then out="$gcc_out"; fi
|
if [ -v gcc ]; then out="$gcc_out"; fi
|
||||||
|
|
||||||
if [ -v clang ]; then compile_debug="$clang_debug"; fi
|
if [ -v clang ]; then compile_debug="$clang_debug"; fi
|
||||||
if [ -v clang ]; then compile_release="$clang_release"; fi
|
if [ -v clang ]; then compile_release="$clang_release"; fi
|
||||||
|
if [ -v clang ]; then compile_test="$clang_debug"; fi
|
||||||
if [ -v clang ]; then compile_link="$clang_link"; fi
|
if [ -v clang ]; then compile_link="$clang_link"; fi
|
||||||
if [ -v clang ]; then out="$clang_out"; fi
|
if [ -v clang ]; then out="$clang_out"; fi
|
||||||
|
|
||||||
if [ -v debug ]; then compile="$compile_debug"; fi
|
if [ -v debug ]; then compile="$compile_debug"; fi
|
||||||
if [ -v release ]; then compile="$compile_release"; fi
|
if [ -v release ]; then compile="$compile_release"; fi
|
||||||
|
if [ -v test ]; then compile="$compile_test"; fi
|
||||||
|
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
|
|
||||||
|
|||||||
@ -66,14 +66,14 @@ static Arena * CreateArenaDebug(rawptr buffer, isize length, u32 init_line_no)
|
|||||||
|
|
||||||
// ::Allocator::FreeList::Start::
|
// ::Allocator::FreeList::Start::
|
||||||
|
|
||||||
static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size)
|
static Alloc *CreateFreeListAlloc(isize init_size, isize grow_size)
|
||||||
{
|
{
|
||||||
isize size = init_size + sizeof(FreeListAlloc) + sizeof(FreeListBuffer) + sizeof(rawptr) + sizeof(FLNode);
|
isize size = init_size + sizeof(Alloc) + sizeof(FreeListBuffer) + sizeof(rawptr) + sizeof(RBNode);
|
||||||
u8 *mem = (u8 *)MemAllocZeroed(size);
|
u8 *mem = (u8 *)MemAllocZeroed(size);
|
||||||
FreeListAlloc *fl_alloc = (FreeListAlloc *)mem;
|
Alloc *fl_alloc = (Alloc *)mem;
|
||||||
|
|
||||||
u8 *pre_mem = mem;
|
u8 *pre_mem = mem;
|
||||||
mem = (u8 *)PtrAdd(mem, sizeof(FreeListAlloc));
|
mem = (u8 *)PtrAdd(mem, sizeof(Alloc));
|
||||||
isize rem_size = (size) - (pre_mem - mem);
|
isize rem_size = (size) - (pre_mem - mem);
|
||||||
|
|
||||||
fl_alloc->buf_len = 1;
|
fl_alloc->buf_len = 1;
|
||||||
@ -84,10 +84,10 @@ static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size)
|
|||||||
mem = (u8 *)PtrAdd(mem, sizeof(FreeListBuffer));
|
mem = (u8 *)PtrAdd(mem, sizeof(FreeListBuffer));
|
||||||
rem_size -= pre_mem - mem;
|
rem_size -= pre_mem - mem;
|
||||||
|
|
||||||
fl_alloc->nil = (FLNode *)mem;
|
fl_alloc->nil = (RBNode *)mem;
|
||||||
|
|
||||||
pre_mem = mem;
|
pre_mem = mem;
|
||||||
mem = (u8 *)PtrAdd(mem, sizeof(FLNode));
|
mem = (u8 *)PtrAdd(mem, sizeof(RBNode));
|
||||||
rem_size -= pre_mem - mem;
|
rem_size -= pre_mem - mem;
|
||||||
|
|
||||||
fl_alloc->buffers[0].buf = mem;
|
fl_alloc->buffers[0].buf = mem;
|
||||||
@ -97,7 +97,7 @@ static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size)
|
|||||||
return fl_alloc;
|
return fl_alloc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DeallocFreeListAlloc(FreeListAlloc *alloc)
|
static void DeallocFreeListAlloc(Alloc *alloc)
|
||||||
{
|
{
|
||||||
for (u8 i = alloc->buf_len-1; i >= 0; i--)
|
for (u8 i = alloc->buf_len-1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
@ -108,4 +108,21 @@ static void DeallocFreeListAlloc(FreeListAlloc *alloc)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static rawptr FLAlloc(Alloc *alloc, isize size)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FLFree(Alloc *alloc, rawptr ptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FreeListGrow(Alloc *alloc)
|
||||||
|
{
|
||||||
|
u8 *mem = (u8 *)MemAllocZeroed(alloc->grow_size);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// ::Allocator::FreeList::End::
|
// ::Allocator::FreeList::End::
|
||||||
|
|||||||
@ -28,24 +28,6 @@ static Arena *CreateArenaDebug(rawptr buffer, isize length, u32 init_line_no);
|
|||||||
|
|
||||||
// ::Allocator::FreeList::Header::
|
// ::Allocator::FreeList::Header::
|
||||||
|
|
||||||
typedef enum FLNodeColor_e
|
|
||||||
{
|
|
||||||
RB_RED,
|
|
||||||
RB_BLACK,
|
|
||||||
} FLNodeColor;
|
|
||||||
|
|
||||||
typedef struct FLNode_t FLNode;
|
|
||||||
|
|
||||||
typedef struct FLNode_t
|
|
||||||
{
|
|
||||||
FLNode *parent;
|
|
||||||
FLNode *left;
|
|
||||||
FLNode *right;
|
|
||||||
i32 value;
|
|
||||||
rawptr data;
|
|
||||||
FLNodeColor color;
|
|
||||||
} FLNode;
|
|
||||||
|
|
||||||
typedef struct FreeListBuffer_t
|
typedef struct FreeListBuffer_t
|
||||||
{
|
{
|
||||||
rawptr buf;
|
rawptr buf;
|
||||||
@ -53,18 +35,21 @@ typedef struct FreeListBuffer_t
|
|||||||
u32 free_size;
|
u32 free_size;
|
||||||
} FreeListBuffer;
|
} FreeListBuffer;
|
||||||
|
|
||||||
typedef struct FreeListAlloc_t
|
typedef struct Alloc_t
|
||||||
{
|
{
|
||||||
FLNode *head;
|
RBNode *head;
|
||||||
FLNode *nil;
|
RBNode *nil;
|
||||||
FreeListBuffer *buffers;
|
FreeListBuffer *buffers;
|
||||||
isize grow_size;
|
isize grow_size;
|
||||||
u8 buf_len;
|
u8 buf_len;
|
||||||
} FreeListAlloc;
|
} Alloc;
|
||||||
|
|
||||||
static FreeListAlloc *CreateFreeListAlloc(isize init_size, isize grow_size);
|
static Alloc *CreateFreeListAlloc(isize init_size, isize grow_size);
|
||||||
static void DeallocFreeListAlloc(FreeListAlloc *alloc);
|
static void DeallocFreeListAlloc(Alloc *alloc);
|
||||||
static inline b32 FLNodeInsert(FreeListAlloc *alloc, FLNode *node);
|
static void FreeListGrow(Alloc *alloc);
|
||||||
static inline void FLNodeDelete(FLNode *node);
|
static rawptr FLAlloc(Alloc *alloc, isize size);
|
||||||
static inline void FLNodeLeftRotate(FLNode *node);
|
static void FLFree(Alloc *alloc, rawptr ptr);
|
||||||
static inline void FLNodeRightRotate(FLNode *node);
|
static inline b32 FLNodeInsert(Alloc *alloc, RBNode *node);
|
||||||
|
static inline void FLNodeDelete(RBNode *node);
|
||||||
|
static inline void FLNodeLeftRotate(RBNode *node);
|
||||||
|
static inline void FLNodeRightRotate(RBNode *node);
|
||||||
|
|||||||
@ -52,3 +52,5 @@ typedef enum ModelAssetTag_e
|
|||||||
{
|
{
|
||||||
MODEL_ASSET_TAG_MAX,
|
MODEL_ASSET_TAG_MAX,
|
||||||
} ModelAssetTag;
|
} ModelAssetTag;
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
320
src/ds.c
320
src/ds.c
@ -1,2 +1,322 @@
|
|||||||
|
|
||||||
|
RBNode RB_NIL = { .color = RB_BLACK };
|
||||||
|
|
||||||
|
static void CreateRBTree(RBTree *tree)
|
||||||
|
{
|
||||||
|
Assert(tree != NULL, "RBTree is null");
|
||||||
|
RB_NIL.right = RB_NIL.left = RB_NIL.parent = &RB_NIL;
|
||||||
|
|
||||||
|
tree->root = &RB_NIL;
|
||||||
|
tree->nil = &RB_NIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RBTreeInsert(RBTree *tree, RBNode *node)
|
||||||
|
{
|
||||||
|
node->left = node->right = tree->nil;
|
||||||
|
node->color = RB_RED;
|
||||||
|
|
||||||
|
if (tree->root == tree->nil)
|
||||||
|
{
|
||||||
|
node->color = RB_BLACK;
|
||||||
|
node->parent = tree->nil;
|
||||||
|
tree->root = node;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RBNode *curr_node = tree->root;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
Assert(curr_node != tree->nil, "Current Node is NIL");
|
||||||
|
|
||||||
|
if (curr_node->value < node->value)
|
||||||
|
{
|
||||||
|
if (curr_node->right == tree->nil)
|
||||||
|
{
|
||||||
|
node->parent = curr_node;
|
||||||
|
curr_node->right = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr_node = curr_node->right;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (curr_node->left == tree->nil)
|
||||||
|
{
|
||||||
|
node->parent = curr_node;
|
||||||
|
curr_node->left = node;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
curr_node = curr_node->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->parent->color != RB_BLACK)
|
||||||
|
RBTreeCorrect(tree, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RBTreeCorrect(RBTree *tree, RBNode *node)
|
||||||
|
{
|
||||||
|
RBNode *gp = node->parent->parent;
|
||||||
|
RBNode *p = node->parent;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (node == tree->root)
|
||||||
|
{
|
||||||
|
node->color = RB_BLACK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gp == tree->nil)
|
||||||
|
{
|
||||||
|
p->color = RB_BLACK;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RBNodeDir dir = NodeDir(p);
|
||||||
|
RBNode *unc = gp->child[1 - dir];
|
||||||
|
if (unc == tree->nil || unc->color == RB_BLACK)
|
||||||
|
{
|
||||||
|
if (node == p->child[1 - dir])
|
||||||
|
{
|
||||||
|
RBTreeRotate(tree, p, dir);
|
||||||
|
node = p;
|
||||||
|
p = gp->child[dir];
|
||||||
|
}
|
||||||
|
|
||||||
|
RBTreeRotate(tree, gp, 1 - dir);
|
||||||
|
p->color = RB_BLACK;
|
||||||
|
gp->color = RB_RED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->color = RB_BLACK;
|
||||||
|
unc->color = RB_BLACK;
|
||||||
|
gp->color = RB_RED;
|
||||||
|
node = gp;
|
||||||
|
gp = node->parent->parent;
|
||||||
|
} while ((p = node->parent));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RBTreeDelete(RBTree *tree, i32 value)
|
||||||
|
{
|
||||||
|
RBNode *node = NULL;
|
||||||
|
Assert(RBTreeSearch(tree, value, &node), "Unable to find node in RBTreeDelete");
|
||||||
|
|
||||||
|
if (node == tree->root && node->left == tree->nil && node->right == tree->nil)
|
||||||
|
{
|
||||||
|
tree->root = tree->nil;
|
||||||
|
}
|
||||||
|
else if (node->left != tree->nil && node->right != tree->nil)
|
||||||
|
{
|
||||||
|
RBNode *ln = node->right;
|
||||||
|
|
||||||
|
while (ln->left != tree->nil)
|
||||||
|
ln = ln->left;
|
||||||
|
|
||||||
|
node->value = ln->value;
|
||||||
|
node->data = ln->data;
|
||||||
|
|
||||||
|
if (node->right == ln)
|
||||||
|
node->right = tree->nil;
|
||||||
|
else
|
||||||
|
ln->parent->left = tree->nil;
|
||||||
|
|
||||||
|
ln->parent = tree->nil;
|
||||||
|
}
|
||||||
|
else if (node->color == RB_BLACK && node->left != tree->nil)
|
||||||
|
{
|
||||||
|
node->value = node->left->value;
|
||||||
|
node->data = node->left->data;
|
||||||
|
node->left = tree->nil;
|
||||||
|
}
|
||||||
|
else if (node->color == RB_BLACK && node->right != tree->nil)
|
||||||
|
{
|
||||||
|
node->value = node->right->value;
|
||||||
|
node->data = node->right->data;
|
||||||
|
node->right = tree->nil;
|
||||||
|
}
|
||||||
|
else if (node->color == RB_RED && node->right == tree->nil && node->left == tree->nil)
|
||||||
|
{
|
||||||
|
RBNodeDir dir = NodeDir(node);
|
||||||
|
node->parent->child[dir] = tree->nil;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RBNode *p = node->parent;
|
||||||
|
RBNodeColor col = node->color;
|
||||||
|
RBNode *s, *cn, *dn;
|
||||||
|
|
||||||
|
RBNodeDir dir = NodeDir(node);
|
||||||
|
p->child[dir] = tree->nil;
|
||||||
|
|
||||||
|
goto start_deletion;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
dir = NodeDir(node);
|
||||||
|
start_deletion:
|
||||||
|
s = p->child[1 - dir];
|
||||||
|
dn = s->child[1 - dir];
|
||||||
|
cn = s->child[dir];
|
||||||
|
|
||||||
|
if (s->color == RB_RED)
|
||||||
|
{
|
||||||
|
RBTreeRotate(tree, p, dir);
|
||||||
|
p->color = RB_RED;
|
||||||
|
s->color = RB_BLACK;
|
||||||
|
s = cn;
|
||||||
|
|
||||||
|
dn = s->child[1 - dir];
|
||||||
|
if (dn->color == RB_RED)
|
||||||
|
goto rotate_sibling;
|
||||||
|
cn = s->child[dir];
|
||||||
|
if (cn->color == RB_RED)
|
||||||
|
goto rotate_parent;
|
||||||
|
|
||||||
|
s->color = RB_RED;
|
||||||
|
p->color = RB_BLACK;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dn->color == RB_RED)
|
||||||
|
goto rotate_parent;
|
||||||
|
|
||||||
|
if (cn->color == RB_RED)
|
||||||
|
goto rotate_sibling;
|
||||||
|
|
||||||
|
if (p->color == RB_RED)
|
||||||
|
{
|
||||||
|
s->color = RB_RED;
|
||||||
|
p->color = RB_BLACK;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p == tree->nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
s->color = RB_RED;
|
||||||
|
node = p;
|
||||||
|
} while ((p = node->parent));
|
||||||
|
|
||||||
|
rotate_sibling:
|
||||||
|
RBTreeRotate(tree, s, 1 - dir);
|
||||||
|
s->color = RB_RED;
|
||||||
|
cn->color = RB_BLACK;
|
||||||
|
dn = s;
|
||||||
|
s = cn;
|
||||||
|
|
||||||
|
rotate_parent:
|
||||||
|
RBTreeRotate(tree, p, dir);
|
||||||
|
s->color = p->color;
|
||||||
|
p->color = RB_BLACK;
|
||||||
|
dn->color = RB_BLACK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static b32 RBTreeSearch(RBTree *tree, i32 value, RBNode **out_node)
|
||||||
|
{
|
||||||
|
if (tree->root == tree->nil) return false;
|
||||||
|
|
||||||
|
b32 found = false;
|
||||||
|
RBNode *node = tree->root;
|
||||||
|
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (node->value == value)
|
||||||
|
{
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node == tree->nil)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (node->value < value)
|
||||||
|
node = node->right;
|
||||||
|
else
|
||||||
|
node = node->left;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
*out_node = node;
|
||||||
|
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void RBTreeTransplant(RBTree *tree, RBNode *node, RBNode *placed_node)
|
||||||
|
{
|
||||||
|
if (node->parent == tree->nil)
|
||||||
|
tree->root = placed_node;
|
||||||
|
else if (node == node->parent->left)
|
||||||
|
node->parent->left = placed_node;
|
||||||
|
else
|
||||||
|
node->parent->right = placed_node;
|
||||||
|
|
||||||
|
placed_node->parent = node->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RBTreeRotate(RBTree *tree, RBNode *node, RBNodeDir dir)
|
||||||
|
{
|
||||||
|
RBNode *p = node->parent;
|
||||||
|
RBNode *root = node->child[1 - dir];
|
||||||
|
RBNode *child = root->child[dir];
|
||||||
|
|
||||||
|
node->child[1 - dir] = child;
|
||||||
|
|
||||||
|
if (child != tree->nil)
|
||||||
|
child->parent = node;
|
||||||
|
|
||||||
|
root->child[dir] = node;
|
||||||
|
root->parent = p;
|
||||||
|
node->parent = root;
|
||||||
|
|
||||||
|
if (p != tree->nil)
|
||||||
|
p->child[node == p->right] = root;
|
||||||
|
else
|
||||||
|
tree->root = root;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RBTreeLeftRotate(RBTree *tree, RBNode *node)
|
||||||
|
{
|
||||||
|
RBNode *right = node->right;
|
||||||
|
if (right->left != tree->nil)
|
||||||
|
node->right = right->left;
|
||||||
|
|
||||||
|
if (node->parent == tree->nil)
|
||||||
|
tree->root = right;
|
||||||
|
else if (node->parent->left == node)
|
||||||
|
node->parent->left = right;
|
||||||
|
else
|
||||||
|
node->parent->right = right;
|
||||||
|
|
||||||
|
right->parent = node->parent;
|
||||||
|
right->left = node;
|
||||||
|
node->parent = right;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void RBTreeRightRotate(RBTree *tree, RBNode *node)
|
||||||
|
{
|
||||||
|
RBNode *left = node->left;
|
||||||
|
if (left->right != tree->nil)
|
||||||
|
node->left = left->right;
|
||||||
|
|
||||||
|
if (node->parent == tree->nil)
|
||||||
|
tree->root = left;
|
||||||
|
else if (node->parent->left == node)
|
||||||
|
node->parent->left = left;
|
||||||
|
else
|
||||||
|
node->parent->right = left;
|
||||||
|
|
||||||
|
left->parent = node->parent;
|
||||||
|
left->right = node;
|
||||||
|
node->parent = left;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
47
src/ds.h
47
src/ds.h
@ -1,3 +1,50 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum RBNodeColor_e
|
||||||
|
{
|
||||||
|
RB_RED,
|
||||||
|
RB_BLACK,
|
||||||
|
} RBNodeColor;
|
||||||
|
|
||||||
|
typedef enum RBNodeDir_e
|
||||||
|
{
|
||||||
|
RB_LEFT,
|
||||||
|
RB_RIGHT,
|
||||||
|
} RBNodeDir;
|
||||||
|
|
||||||
|
typedef struct RBNode_t RBNode;
|
||||||
|
|
||||||
|
typedef struct RBNode_t
|
||||||
|
{
|
||||||
|
RBNode *parent;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
|
RBNode *left;
|
||||||
|
RBNode *right;
|
||||||
|
};
|
||||||
|
RBNode *child[2];
|
||||||
|
};
|
||||||
|
i32 value;
|
||||||
|
rawptr data;
|
||||||
|
RBNodeColor color;
|
||||||
|
} RBNode;
|
||||||
|
|
||||||
|
typedef struct RBTree_t
|
||||||
|
{
|
||||||
|
RBNode *root;
|
||||||
|
RBNode *nil;
|
||||||
|
} RBTree;
|
||||||
|
|
||||||
|
#define NodeDir(node) (node == node->parent->left ? RB_LEFT : RB_RIGHT)
|
||||||
|
|
||||||
|
static void CreateRBTree(RBTree *tree);
|
||||||
|
static void RBTreeInsert(RBTree *tree, RBNode *node);
|
||||||
|
static b32 RBTreeSearch(RBTree *tree, i32 value, RBNode **out_node);
|
||||||
|
static void RBTreeDelete(RBTree *tree, i32 value);
|
||||||
|
static void RBTreeLeftRotate(RBTree *tree, RBNode *node);
|
||||||
|
static void RBTreeRightRotate(RBTree *tree, RBNode *node);
|
||||||
|
static void RBTreeRotate(RBTree *tree, RBNode *node, RBNodeDir dir);
|
||||||
|
static void RBTreeCorrect(RBTree *tree, RBNode *node);
|
||||||
|
static inline void RBTreeTransplant(RBTree *tree, RBNode *node, RBNode *placed_node);
|
||||||
|
|||||||
@ -12,9 +12,85 @@
|
|||||||
#include "allocators.c"
|
#include "allocators.c"
|
||||||
#include "renderer.c"
|
#include "renderer.c"
|
||||||
#include "game.c"
|
#include "game.c"
|
||||||
|
#ifdef BUILD_TEST
|
||||||
|
# include "tests.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void TraverseNode(RBTree *tree, RBNode *node, RBNodeDir *dir)
|
||||||
|
{
|
||||||
|
char *dir_str = dir == NULL ? "Root" : *dir == RB_RIGHT ? "Right" : "Left";
|
||||||
|
Printfln("Color: %s Value: %d Dir: %s", node->color == RB_RED ? "Red" : "Black", node->value, dir_str);
|
||||||
|
if (node->left != tree->nil)
|
||||||
|
{
|
||||||
|
RBNodeDir left_dir = RB_LEFT;
|
||||||
|
TraverseNode(tree, node->left, &left_dir);
|
||||||
|
}
|
||||||
|
if (node->right != tree->nil)
|
||||||
|
{
|
||||||
|
RBNodeDir right_dir = RB_RIGHT;
|
||||||
|
TraverseNode(tree, node->right, &right_dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Traverse(RBTree *tree)
|
||||||
|
{
|
||||||
|
TraverseNode(tree, tree->root, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
#ifdef BUILD_TEST
|
||||||
|
RunTests();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
RBTree tree;
|
||||||
|
CreateRBTree(&tree);
|
||||||
|
RBNode node1 = { .value = 4 };
|
||||||
|
RBNode node2 = { .value = 7 };
|
||||||
|
RBNode node3 = { .value = 33 };
|
||||||
|
RBNode node4 = { .value = 53 };
|
||||||
|
RBNode node5 = { .value = 25 };
|
||||||
|
RBNode node6 = { .value = 22 };
|
||||||
|
RBNode node7 = { .value = 6 };
|
||||||
|
RBNode node8 = { .value = 1 };
|
||||||
|
|
||||||
|
RBTreeInsert(&tree, &node1);
|
||||||
|
RBTreeInsert(&tree, &node2);
|
||||||
|
RBTreeInsert(&tree, &node3);
|
||||||
|
RBTreeInsert(&tree, &node4);
|
||||||
|
RBTreeInsert(&tree, &node5);
|
||||||
|
RBTreeInsert(&tree, &node6);
|
||||||
|
RBTreeInsert(&tree, &node7);
|
||||||
|
RBTreeInsert(&tree, &node8);
|
||||||
|
|
||||||
|
RBNode *search_node = NULL;
|
||||||
|
Assert(RBTreeSearch(&tree, 25, &search_node), "Unable to find node");
|
||||||
|
Assert(search_node->value == 25, "Node has an invalid value");
|
||||||
|
|
||||||
|
RBTreeDelete(&tree, 25);
|
||||||
|
|
||||||
|
RBNode node9 = { .value = 57 };
|
||||||
|
RBTreeInsert(&tree, &node9);
|
||||||
|
|
||||||
|
RBTreeDelete(&tree, 22);
|
||||||
|
|
||||||
|
RBNode node10 = { .value = 59 };
|
||||||
|
RBNode node11 = { .value = 60 };
|
||||||
|
RBNode node12 = { .value = 58 };
|
||||||
|
|
||||||
|
RBTreeInsert(&tree, &node10);
|
||||||
|
RBTreeInsert(&tree, &node11);
|
||||||
|
RBTreeInsert(&tree, &node12);
|
||||||
|
|
||||||
|
RBTreeDelete(&tree, 59);
|
||||||
|
RBTreeDelete(&tree, 33);
|
||||||
|
|
||||||
|
Traverse(&tree);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
u8 *mem = (u8 *)MemAllocZeroed(MB(64));
|
u8 *mem = (u8 *)MemAllocZeroed(MB(64));
|
||||||
Arena *arena = CreateArenaDebug(mem, MB(64), __LINE__);
|
Arena *arena = CreateArenaDebug(mem, MB(64), __LINE__);
|
||||||
|
|
||||||
|
|||||||
@ -21,6 +21,10 @@
|
|||||||
#include "renderer.h"
|
#include "renderer.h"
|
||||||
#include "game.h"
|
#include "game.h"
|
||||||
|
|
||||||
|
#ifdef BUILD_TEST
|
||||||
|
# include "tests.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(int argc, char **argv);
|
int main(int argc, char **argv);
|
||||||
|
|
||||||
#endif // __linux__
|
#endif // __linux__
|
||||||
|
|||||||
@ -90,7 +90,9 @@ u64 FileLength(FILE *file)
|
|||||||
u64 WriteData(void *buf, u64 pos, u64 size, FILE *file)
|
u64 WriteData(void *buf, u64 pos, u64 size, FILE *file)
|
||||||
{
|
{
|
||||||
Assert(fseek(file, pos, SEEK_SET) == 0, "WriteData fseek failure");
|
Assert(fseek(file, pos, SEEK_SET) == 0, "WriteData fseek failure");
|
||||||
return FWrite(buf, size, 1, file);
|
u64 written = (u64)FWrite(buf, size, 1, file);
|
||||||
|
fflush(file);
|
||||||
|
return written;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 ReadData(void *buf, u64 pos, u64 size, FILE *file)
|
u64 ReadData(void *buf, u64 pos, u64 size, FILE *file)
|
||||||
@ -293,15 +295,11 @@ void PackFiles(Arena *arena, FileHeader *header)
|
|||||||
WriteData(shader_assets, header->asset_offsets[SHADER_ASSET], sizeof(AssetFile)*SHADER_ASSET_MAX, file);
|
WriteData(shader_assets, header->asset_offsets[SHADER_ASSET], sizeof(AssetFile)*SHADER_ASSET_MAX, file);
|
||||||
WriteData(texture_assets, header->asset_offsets[TEXTURE_ASSET], sizeof(AssetFile)*TEXTURE_ASSET_MAX, file);
|
WriteData(texture_assets, header->asset_offsets[TEXTURE_ASSET], sizeof(AssetFile)*TEXTURE_ASSET_MAX, file);
|
||||||
|
|
||||||
FileLength(file);
|
|
||||||
|
|
||||||
ChangeDir(return_dir);
|
ChangeDir(return_dir);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintBytes(u8 *bytes, u64 len)
|
void PrintBytes(u8 *bytes, u64 len)
|
||||||
{
|
{
|
||||||
return;
|
|
||||||
|
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
while (count + 8 < len)
|
while (count + 8 < len)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -47,8 +47,6 @@ b32 InitRenderer(Arena *arena)
|
|||||||
ArenaFree(renderer.arena);
|
ArenaFree(renderer.arena);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyRenderer()
|
void DestroyRenderer()
|
||||||
|
|||||||
5
src/tests.c
Normal file
5
src/tests.c
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
|
||||||
|
void RunTests()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
3
src/tests.h
Normal file
3
src/tests.h
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
void RunTests();
|
||||||
Loading…
x
Reference in New Issue
Block a user