Add rbtree validation
This commit is contained in:
parent
79a77cd862
commit
431fd9aa9c
2
.gitignore
vendored
2
.gitignore
vendored
@ -9,3 +9,5 @@ docs/
|
|||||||
examples/
|
examples/
|
||||||
internal_docs
|
internal_docs
|
||||||
build.sh
|
build.sh
|
||||||
|
libctru/source/util/rbtree/test/*.o
|
||||||
|
libctru/source/util/rbtree/test/rbtree_test
|
||||||
|
@ -7,11 +7,13 @@ extern "C"
|
|||||||
|
|
||||||
#include "mem_pool.h"
|
#include "mem_pool.h"
|
||||||
#include "addrmap.h"
|
#include "addrmap.h"
|
||||||
|
#include "lock.h"
|
||||||
|
|
||||||
extern u32 __ctru_linear_heap;
|
extern u32 __ctru_linear_heap;
|
||||||
extern u32 __ctru_linear_heap_size;
|
extern u32 __ctru_linear_heap_size;
|
||||||
|
|
||||||
static MemPool sLinearPool;
|
static MemPool sLinearPool;
|
||||||
|
static LightLock sLock = 1;
|
||||||
|
|
||||||
static bool linearInit()
|
static bool linearInit()
|
||||||
{
|
{
|
||||||
@ -42,6 +44,7 @@ void* linearMemAlign(size_t size, size_t alignment)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Initialize the pool if it is not ready
|
// Initialize the pool if it is not ready
|
||||||
|
LockGuard guard(sLock);
|
||||||
if (!sLinearPool.Ready() && !linearInit())
|
if (!sLinearPool.Ready() && !linearInit())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -73,12 +76,14 @@ void* linearRealloc(void* mem, size_t size)
|
|||||||
|
|
||||||
size_t linearGetSize(void* mem)
|
size_t linearGetSize(void* mem)
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
auto node = getNode(mem);
|
auto node = getNode(mem);
|
||||||
return node ? node->chunk.size : 0;
|
return node ? node->chunk.size : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void linearFree(void* mem)
|
void linearFree(void* mem)
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
auto node = getNode(mem);
|
auto node = getNode(mem);
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
@ -91,5 +96,6 @@ void linearFree(void* mem)
|
|||||||
|
|
||||||
u32 linearSpaceFree()
|
u32 linearSpaceFree()
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
return sLinearPool.GetFreeSpace();
|
return sLinearPool.GetFreeSpace();
|
||||||
}
|
}
|
||||||
|
23
libctru/source/allocator/lock.h
Normal file
23
libctru/source/allocator/lock.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <3ds/synchronization.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
class LockGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~LockGuard()
|
||||||
|
{
|
||||||
|
LightLock_Unlock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
LockGuard(LightLock &lock) : lock(lock)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
LightLock &lock;
|
||||||
|
};
|
@ -7,8 +7,10 @@ extern "C"
|
|||||||
|
|
||||||
#include "mem_pool.h"
|
#include "mem_pool.h"
|
||||||
#include "addrmap.h"
|
#include "addrmap.h"
|
||||||
|
#include "lock.h"
|
||||||
|
|
||||||
static MemPool sMappablePool;
|
static MemPool sMappablePool;
|
||||||
|
static LightLock sLock = 1;
|
||||||
|
|
||||||
static bool mappableInit()
|
static bool mappableInit()
|
||||||
{
|
{
|
||||||
@ -25,6 +27,7 @@ static bool mappableInit()
|
|||||||
void* mappableAlloc(size_t size)
|
void* mappableAlloc(size_t size)
|
||||||
{
|
{
|
||||||
// Initialize the pool if it is not ready
|
// Initialize the pool if it is not ready
|
||||||
|
LockGuard guard(sLock);
|
||||||
if (!sMappablePool.Ready() && !mappableInit())
|
if (!sMappablePool.Ready() && !mappableInit())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -45,12 +48,14 @@ void* mappableAlloc(size_t size)
|
|||||||
|
|
||||||
size_t mappableGetSize(void* mem)
|
size_t mappableGetSize(void* mem)
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
auto node = getNode(mem);
|
auto node = getNode(mem);
|
||||||
return node ? node->chunk.size : 0;
|
return node ? node->chunk.size : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mappableFree(void* mem)
|
void mappableFree(void* mem)
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
auto node = getNode(mem);
|
auto node = getNode(mem);
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
@ -63,5 +68,6 @@ void mappableFree(void* mem)
|
|||||||
|
|
||||||
u32 mappableSpaceFree()
|
u32 mappableSpaceFree()
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
return sMappablePool.GetFreeSpace();
|
return sMappablePool.GetFreeSpace();
|
||||||
}
|
}
|
||||||
|
@ -7,8 +7,10 @@ extern "C"
|
|||||||
|
|
||||||
#include "mem_pool.h"
|
#include "mem_pool.h"
|
||||||
#include "addrmap.h"
|
#include "addrmap.h"
|
||||||
|
#include "lock.h"
|
||||||
|
|
||||||
static MemPool sVramPool;
|
static MemPool sVramPool;
|
||||||
|
static LightLock sLock = 1;
|
||||||
|
|
||||||
static bool vramInit()
|
static bool vramInit()
|
||||||
{
|
{
|
||||||
@ -39,6 +41,7 @@ void* vramMemAlign(size_t size, size_t alignment)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Initialize the pool if it is not ready
|
// Initialize the pool if it is not ready
|
||||||
|
LockGuard guard(sLock);
|
||||||
if (!sVramPool.Ready() && !vramInit())
|
if (!sVramPool.Ready() && !vramInit())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -70,12 +73,14 @@ void* vramRealloc(void* mem, size_t size)
|
|||||||
|
|
||||||
size_t vramGetSize(void* mem)
|
size_t vramGetSize(void* mem)
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
auto node = getNode(mem);
|
auto node = getNode(mem);
|
||||||
return node ? node->chunk.size : 0;
|
return node ? node->chunk.size : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vramFree(void* mem)
|
void vramFree(void* mem)
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
auto node = getNode(mem);
|
auto node = getNode(mem);
|
||||||
if (!node) return;
|
if (!node) return;
|
||||||
|
|
||||||
@ -88,5 +93,6 @@ void vramFree(void* mem)
|
|||||||
|
|
||||||
u32 vramSpaceFree()
|
u32 vramSpaceFree()
|
||||||
{
|
{
|
||||||
|
LockGuard guard(sLock);
|
||||||
return sVramPool.GetFreeSpace();
|
return sVramPool.GetFreeSpace();
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ void
|
|||||||
rbtree_clear(rbtree_t *tree,
|
rbtree_clear(rbtree_t *tree,
|
||||||
rbtree_node_destructor_t destructor)
|
rbtree_node_destructor_t destructor)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
rbtree_node_t *node = tree->root;
|
rbtree_node_t *node = tree->root;
|
||||||
|
|
||||||
while(tree->root != NULL)
|
while(tree->root != NULL)
|
||||||
@ -31,4 +33,6 @@ rbtree_clear(rbtree_t *tree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree->size = 0;
|
tree->size = 0;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#include <3ds/util/rbtree.h>
|
#include <3ds/util/rbtree.h>
|
||||||
|
#include "rbtree_internal.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
rbtree_empty(const rbtree_t *tree)
|
rbtree_empty(const rbtree_t *tree)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
return tree->root == NULL;
|
return tree->root == NULL;
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ rbtree_node_t*
|
|||||||
rbtree_find(const rbtree_t *tree,
|
rbtree_find(const rbtree_t *tree,
|
||||||
const rbtree_node_t *node)
|
const rbtree_node_t *node)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
rbtree_node_t *tmp = tree->root;
|
rbtree_node_t *tmp = tree->root;
|
||||||
rbtree_node_t *save = NULL;
|
rbtree_node_t *save = NULL;
|
||||||
|
|
||||||
@ -26,5 +28,7 @@ rbtree_find(const rbtree_t *tree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <3ds/util/rbtree.h>
|
#include <3ds/util/rbtree.h>
|
||||||
|
#include "rbtree_internal.h"
|
||||||
|
|
||||||
void
|
void
|
||||||
rbtree_init(rbtree_t *tree,
|
rbtree_init(rbtree_t *tree,
|
||||||
@ -7,4 +8,6 @@ rbtree_init(rbtree_t *tree,
|
|||||||
tree->root = NULL;
|
tree->root = NULL;
|
||||||
tree->comparator = comparator;
|
tree->comparator = comparator;
|
||||||
tree->size = 0;
|
tree->size = 0;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,8 @@ do_insert(rbtree_t *tree,
|
|||||||
rbtree_node_t *node,
|
rbtree_node_t *node,
|
||||||
int multi)
|
int multi)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
rbtree_node_t *original = node;
|
rbtree_node_t *original = node;
|
||||||
rbtree_node_t **tmp = &tree->root;
|
rbtree_node_t **tmp = &tree->root;
|
||||||
rbtree_node_t *parent = NULL;
|
rbtree_node_t *parent = NULL;
|
||||||
@ -31,6 +33,8 @@ do_insert(rbtree_t *tree,
|
|||||||
|
|
||||||
if(save != NULL)
|
if(save != NULL)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +82,8 @@ do_insert(rbtree_t *tree,
|
|||||||
|
|
||||||
tree->size += 1;
|
tree->size += 1;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
return original;
|
return original;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "3ds/util/rbtree.h"
|
||||||
|
|
||||||
#define LEFT 0
|
#define LEFT 0
|
||||||
#define RIGHT 1
|
#define RIGHT 1
|
||||||
@ -62,3 +63,9 @@ void
|
|||||||
rbtree_rotate(rbtree_t *tree,
|
rbtree_rotate(rbtree_t *tree,
|
||||||
rbtree_node_t *node,
|
rbtree_node_t *node,
|
||||||
int left);
|
int left);
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_validate(const rbtree_t *tree);
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_node_validate(const rbtree_t *tree, const rbtree_node_t *node, size_t *all, size_t *black, size_t *depth);
|
||||||
|
@ -5,6 +5,8 @@ static inline rbtree_node_t*
|
|||||||
do_minmax(const rbtree_t *tree,
|
do_minmax(const rbtree_t *tree,
|
||||||
int max)
|
int max)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
rbtree_node_t *node = tree->root;
|
rbtree_node_t *node = tree->root;
|
||||||
|
|
||||||
if(node == NULL)
|
if(node == NULL)
|
||||||
|
@ -60,6 +60,8 @@ rbtree_remove(rbtree_t *tree,
|
|||||||
rbtree_node_t *node,
|
rbtree_node_t *node,
|
||||||
rbtree_node_destructor_t destructor)
|
rbtree_node_destructor_t destructor)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
rbtree_color_t color;
|
rbtree_color_t color;
|
||||||
rbtree_node_t *child, *parent, *original = node;
|
rbtree_node_t *child, *parent, *original = node;
|
||||||
rbtree_node_t *next;
|
rbtree_node_t *next;
|
||||||
@ -136,5 +138,7 @@ rbtree_remove(rbtree_t *tree,
|
|||||||
|
|
||||||
tree->size -= 1;
|
tree->size -= 1;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,10 @@
|
|||||||
#include <3ds/util/rbtree.h>
|
#include <3ds/util/rbtree.h>
|
||||||
|
#include "rbtree_internal.h"
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
rbtree_size(const rbtree_t *tree)
|
rbtree_size(const rbtree_t *tree)
|
||||||
{
|
{
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
return tree->size;
|
return tree->size;
|
||||||
}
|
}
|
||||||
|
136
libctru/source/util/rbtree/rbtree_validate.c
Normal file
136
libctru/source/util/rbtree/rbtree_validate.c
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
#include "rbtree_internal.h"
|
||||||
|
|
||||||
|
#include <3ds/svc.h>
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define panic() do { \
|
||||||
|
svcBreak(USERBREAK_PANIC); \
|
||||||
|
abort(); \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_validate(const rbtree_t *tree)
|
||||||
|
{
|
||||||
|
if(!tree)
|
||||||
|
panic();
|
||||||
|
|
||||||
|
// root node must be black
|
||||||
|
if(!is_black(tree->root))
|
||||||
|
panic();
|
||||||
|
|
||||||
|
// root node's parent must be null
|
||||||
|
if(tree->root)
|
||||||
|
{
|
||||||
|
if(get_parent(tree->root) != NULL)
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate subtree starting at root node
|
||||||
|
size_t size = 0;
|
||||||
|
rbtree_node_validate(tree, tree->root, &size, NULL, NULL);
|
||||||
|
|
||||||
|
// make sure we are tracking the correct number of nodes
|
||||||
|
if(size != tree->size)
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_node_validate(const rbtree_t *tree, const rbtree_node_t *node, size_t *size, size_t *black, size_t *depth)
|
||||||
|
{
|
||||||
|
if(!node) // implies is_black
|
||||||
|
{
|
||||||
|
if(black)
|
||||||
|
*black += 1;
|
||||||
|
|
||||||
|
if(depth)
|
||||||
|
*depth = 1;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else // non-null
|
||||||
|
{
|
||||||
|
rbtree_node_t *parent = get_parent(node);
|
||||||
|
if(!parent)
|
||||||
|
{
|
||||||
|
// only the root node can have a null parent
|
||||||
|
if(node != tree->root)
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// make sure this node is a child of its parent
|
||||||
|
if(parent->child[LEFT] != node && parent->child[RIGHT] != node)
|
||||||
|
panic();
|
||||||
|
|
||||||
|
// if the parent is red, this node must be black
|
||||||
|
if(is_red(parent) && !is_black(node))
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(is_red(node))
|
||||||
|
{
|
||||||
|
// if this node is red, both children must be black
|
||||||
|
if(!is_black(node->child[LEFT]))
|
||||||
|
panic();
|
||||||
|
|
||||||
|
if(!is_black(node->child[RIGHT]))
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node->child[LEFT])
|
||||||
|
{
|
||||||
|
// this node must be >= left child
|
||||||
|
if((*(tree->comparator))(node, node->child[LEFT]) < 0)
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if(node->child[RIGHT])
|
||||||
|
{
|
||||||
|
// this node must be <= right child
|
||||||
|
if((*(tree->comparator))(node, node->child[RIGHT]) > 0)
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
// validate subtree at left child
|
||||||
|
size_t left_size = 0;
|
||||||
|
size_t left_black = 0;
|
||||||
|
size_t left_depth = 0;
|
||||||
|
rbtree_node_validate(tree, node->child[LEFT], &left_size, &left_black, &left_depth);
|
||||||
|
|
||||||
|
// validate subtree at right child
|
||||||
|
size_t right_size = 0;
|
||||||
|
size_t right_black = 0;
|
||||||
|
size_t right_depth = 0;
|
||||||
|
rbtree_node_validate(tree, node->child[RIGHT], &right_size, &right_black, &right_depth);
|
||||||
|
|
||||||
|
// size is left+right subtrees plus self
|
||||||
|
if(size)
|
||||||
|
*size += left_size + right_size + 1;
|
||||||
|
|
||||||
|
// all possible paths to leaf nodes must have the same number of black nodes along the path
|
||||||
|
if(left_black != right_black)
|
||||||
|
panic();
|
||||||
|
|
||||||
|
if(black)
|
||||||
|
*black += left_black + (is_black(node) ? 1 : 0);
|
||||||
|
|
||||||
|
// depth of one subtree must not exceed 2x depth of the other subtree
|
||||||
|
if(left_depth < right_depth)
|
||||||
|
{
|
||||||
|
if(right_depth - left_depth > left_depth)
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
else if(left_depth - right_depth > right_depth)
|
||||||
|
panic();
|
||||||
|
|
||||||
|
if(depth)
|
||||||
|
{
|
||||||
|
if(left_depth > right_depth)
|
||||||
|
*depth = left_depth + 1;
|
||||||
|
else
|
||||||
|
*depth = right_depth + 1;
|
||||||
|
}
|
||||||
|
}
|
23
libctru/source/util/rbtree/test/Makefile
Normal file
23
libctru/source/util/rbtree/test/Makefile
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
CFILES := $(wildcard ../*.c)
|
||||||
|
CXXFILES := $(wildcard *.cpp)
|
||||||
|
|
||||||
|
OFILES := $(patsubst ../%,%,$(CFILES:.c=.c.o))
|
||||||
|
OXXFILES := $(CXXFILES:.cpp=.cpp.o)
|
||||||
|
|
||||||
|
CPPFLAGS := -Wall -g -I../../../../include -O2
|
||||||
|
CFLAGS := $(CPPFLAGS)
|
||||||
|
CXXFLAGS := $(CPPFLAGS) -std=c++11
|
||||||
|
|
||||||
|
all: rbtree_test
|
||||||
|
|
||||||
|
rbtree_test: $(OFILES) $(OXXFILES)
|
||||||
|
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
$(OFILES): %.c.o: ../%.c
|
||||||
|
$(CC) -o $@ -c $< $(CFLAGS)
|
||||||
|
|
||||||
|
$(OXXFILES): %.cpp.o: %.cpp
|
||||||
|
$(CXX) -o $@ -c $< $(CXXFLAGS)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) rbtree_test $(OFILES) $(OXXFILES)
|
126
libctru/source/util/rbtree/test/main.cpp
Normal file
126
libctru/source/util/rbtree/test/main.cpp
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <3ds/svc.h>
|
||||||
|
#include <3ds/util/rbtree.h>
|
||||||
|
#include "../rbtree_internal.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <functional>
|
||||||
|
#include <limits>
|
||||||
|
#include <random>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct IntNode
|
||||||
|
{
|
||||||
|
IntNode(int value) : value(value)
|
||||||
|
{}
|
||||||
|
|
||||||
|
const int value;
|
||||||
|
rbtree_node_t node;
|
||||||
|
};
|
||||||
|
|
||||||
|
IntNode *getIntNode(rbtree_node_t *node)
|
||||||
|
{
|
||||||
|
return rbtree_item(node, IntNode, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
const IntNode *getIntNode(const rbtree_node_t *node)
|
||||||
|
{
|
||||||
|
return rbtree_item(node, IntNode, node);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntNodeDestructor(rbtree_node_t *node)
|
||||||
|
{
|
||||||
|
delete getIntNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
int IntNodeComparator(const rbtree_node_t *lhs, const rbtree_node_t *rhs)
|
||||||
|
{
|
||||||
|
auto left = getIntNode(lhs)->value;
|
||||||
|
auto right = getIntNode(rhs)->value;
|
||||||
|
|
||||||
|
if(left < right)
|
||||||
|
return -1;
|
||||||
|
if(right < left)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void printNode(const rbtree_node_t *node, int indent)
|
||||||
|
{
|
||||||
|
if(!node)
|
||||||
|
{
|
||||||
|
std::printf("%*s(nil) black\n", indent, "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::printf("%*s%d %s\n", indent, "", getIntNode(node)->value, is_black(node) ? "black" : "red");
|
||||||
|
|
||||||
|
printNode(node->child[LEFT], indent + 2);
|
||||||
|
printNode(node->child[RIGHT], indent + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
void printTree(const rbtree_t *tree)
|
||||||
|
{
|
||||||
|
std::printf("==========\n");
|
||||||
|
printNode(tree->root, 0);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void svcBreak(UserBreakType breakReason)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
std::default_random_engine eng;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::random_device rand;
|
||||||
|
std::random_device::result_type seedBuffer[32];
|
||||||
|
for(auto &d : seedBuffer)
|
||||||
|
d = rand();
|
||||||
|
|
||||||
|
std::seed_seq seed(std::begin(seedBuffer), std::end(seedBuffer));
|
||||||
|
eng.seed(seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto dist = std::bind(std::uniform_int_distribution<int>(std::numeric_limits<int>::min(), std::numeric_limits<int>::max()), std::ref(eng));
|
||||||
|
auto remove = std::bind(std::uniform_int_distribution<std::size_t>(0, 100), std::ref(eng));
|
||||||
|
|
||||||
|
rbtree_t tree;
|
||||||
|
rbtree_init(&tree, IntNodeComparator);
|
||||||
|
|
||||||
|
for(std::size_t chance = 0; chance <= 100; chance += 25)
|
||||||
|
{
|
||||||
|
std::printf("Chance %zu\n", chance);
|
||||||
|
|
||||||
|
std::vector<IntNode*> nodes;
|
||||||
|
for(std::size_t i = 0; i < 10000; ++i)
|
||||||
|
{
|
||||||
|
auto node = new IntNode(dist());
|
||||||
|
if(rbtree_insert(&tree, &node->node) != &node->node)
|
||||||
|
delete node;
|
||||||
|
else
|
||||||
|
nodes.emplace_back(node);
|
||||||
|
|
||||||
|
if(remove() < chance)
|
||||||
|
{
|
||||||
|
auto it = std::begin(nodes) + (eng() % nodes.size());
|
||||||
|
rbtree_remove(&tree, &(*it)->node, IntNodeDestructor);
|
||||||
|
nodes.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printTree(&tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rbtree_clear(&tree, IntNodeDestructor);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user