Compare commits
4 Commits
master
...
allocator-
Author | SHA1 | Date | |
---|---|---|---|
![]() |
dca3e9919d | ||
![]() |
6298be6420 | ||
![]() |
888569bba1 | ||
![]() |
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
|
||||||
|
@ -4,6 +4,12 @@
|
|||||||
*/
|
*/
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef _3DS
|
||||||
|
#include <3ds/synchronization.h>
|
||||||
|
#else
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
@ -21,16 +27,23 @@ typedef int (*rbtree_node_comparator_t)(const rbtree_node_t *lhs,
|
|||||||
/// An rbtree node.
|
/// An rbtree node.
|
||||||
struct rbtree_node
|
struct rbtree_node
|
||||||
{
|
{
|
||||||
|
uint32_t prefix[32]; ///< Guard prefix.
|
||||||
|
char nodeTag[4]; ///< Node tag.
|
||||||
uintptr_t parent_color; ///< Parent color.
|
uintptr_t parent_color; ///< Parent color.
|
||||||
rbtree_node_t *child[2]; ///< Node children.
|
rbtree_node_t *child[2]; ///< Node children.
|
||||||
|
rbtree_t *tree; ///< Owning tree.
|
||||||
|
uint32_t *suffix[32]; ///< Guard suffix.
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An rbtree.
|
/// An rbtree.
|
||||||
struct rbtree
|
struct rbtree
|
||||||
{
|
{
|
||||||
|
char treeTag[4]; ///< Tree tag.
|
||||||
rbtree_node_t *root; ///< Root node.
|
rbtree_node_t *root; ///< Root node.
|
||||||
rbtree_node_comparator_t comparator; ///< Node comparator.
|
rbtree_node_comparator_t comparator; ///< Node comparator.
|
||||||
size_t size; ///< Size.
|
size_t size; ///< Size.
|
||||||
|
LightLock lock; ///< Tree mutex.
|
||||||
|
bool busy; ///< Busy flag.
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
@ -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;
|
||||||
|
|
||||||
@ -56,7 +59,9 @@ void* linearMemAlign(size_t size, size_t alignment)
|
|||||||
sLinearPool.Deallocate(chunk);
|
sLinearPool.Deallocate(chunk);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
if (rbtree_insert(&sAddrMap, &node->node));
|
if (rbtree_insert(&sAddrMap, &node->node) != &node->node)
|
||||||
|
svcBreak(USERBREAK_PANIC);
|
||||||
|
|
||||||
return chunk.addr;
|
return chunk.addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,12 +78,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 +98,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();
|
||||||
}
|
}
|
||||||
|
81
libctru/source/crc32c.c
Normal file
81
libctru/source/crc32c.c
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "crc32c.h"
|
||||||
|
|
||||||
|
static const uint32_t crc32cTable[] =
|
||||||
|
{
|
||||||
|
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
|
||||||
|
0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
|
||||||
|
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
|
||||||
|
0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
|
||||||
|
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
|
||||||
|
0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
|
||||||
|
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
|
||||||
|
0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
|
||||||
|
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
|
||||||
|
0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
|
||||||
|
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
|
||||||
|
0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
|
||||||
|
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
|
||||||
|
0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
|
||||||
|
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
|
||||||
|
0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
|
||||||
|
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
|
||||||
|
0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
|
||||||
|
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
|
||||||
|
0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
|
||||||
|
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
|
||||||
|
0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
|
||||||
|
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
|
||||||
|
0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
|
||||||
|
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
|
||||||
|
0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
|
||||||
|
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
|
||||||
|
0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
|
||||||
|
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
|
||||||
|
0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
|
||||||
|
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
|
||||||
|
0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
|
||||||
|
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
|
||||||
|
0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
|
||||||
|
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
|
||||||
|
0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
|
||||||
|
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
|
||||||
|
0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
|
||||||
|
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
|
||||||
|
0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
|
||||||
|
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
|
||||||
|
0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
|
||||||
|
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
|
||||||
|
0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
|
||||||
|
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
|
||||||
|
0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
|
||||||
|
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
|
||||||
|
0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
|
||||||
|
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
|
||||||
|
0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
|
||||||
|
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
|
||||||
|
0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
|
||||||
|
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
|
||||||
|
0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
|
||||||
|
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
|
||||||
|
0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
|
||||||
|
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
|
||||||
|
0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
|
||||||
|
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
|
||||||
|
0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
|
||||||
|
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
|
||||||
|
0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
|
||||||
|
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
|
||||||
|
0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32_t crc32c(const void *buffer, size_t size, uint32_t crc)
|
||||||
|
{
|
||||||
|
const uint8_t *ptr = (const uint8_t*)buffer;
|
||||||
|
|
||||||
|
crc ^= ~(uint32_t)0;
|
||||||
|
|
||||||
|
for(size_t i = 0; i < size; ++i)
|
||||||
|
crc = crc32cTable[(crc ^ ptr[i]) & 0xFF] ^ (crc >> 8);
|
||||||
|
|
||||||
|
return ~crc;
|
||||||
|
}
|
6
libctru/source/crc32c.h
Normal file
6
libctru/source/crc32c.h
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint32_t crc32c(const void *buffer, size_t size, uint32_t crc);
|
@ -5,25 +5,28 @@ void
|
|||||||
rbtree_clear(rbtree_t *tree,
|
rbtree_clear(rbtree_t *tree,
|
||||||
rbtree_node_destructor_t destructor)
|
rbtree_node_destructor_t destructor)
|
||||||
{
|
{
|
||||||
|
rbtree_set_busy(tree);
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
rbtree_node_t *node = tree->root;
|
rbtree_node_t *node = tree->root;
|
||||||
|
|
||||||
while(tree->root != NULL)
|
while(tree->root)
|
||||||
{
|
{
|
||||||
while(node->child[LEFT] != NULL)
|
while(node->child[LEFT])
|
||||||
node = node->child[LEFT];
|
node = node->child[LEFT];
|
||||||
|
|
||||||
if(node->child[RIGHT] != NULL)
|
if(node->child[RIGHT])
|
||||||
node = node->child[RIGHT];
|
node = node->child[RIGHT];
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rbtree_node_t *parent = get_parent(node);
|
rbtree_node_t *parent = get_parent(node);
|
||||||
|
|
||||||
if(parent == NULL)
|
if(!parent)
|
||||||
tree->root = NULL;
|
tree->root = NULL;
|
||||||
else
|
else
|
||||||
parent->child[node != parent->child[LEFT]] = NULL;
|
parent->child[node != parent->child[LEFT]] = NULL;
|
||||||
|
|
||||||
if(destructor != NULL)
|
if(destructor)
|
||||||
(*destructor)(node);
|
(*destructor)(node);
|
||||||
|
|
||||||
node = parent;
|
node = parent;
|
||||||
@ -31,4 +34,7 @@ rbtree_clear(rbtree_t *tree,
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree->size = 0;
|
tree->size = 0;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
rbtree_clear_busy(tree);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
#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)
|
||||||
{
|
{
|
||||||
return tree->root == NULL;
|
rbtree_set_busy((rbtree_t*)tree);
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
|
bool empty = !tree->root;
|
||||||
|
|
||||||
|
rbtree_clear_busy((rbtree_t*)tree);
|
||||||
|
return empty;
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,13 @@ 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_set_busy((rbtree_t*)tree);
|
||||||
|
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;
|
||||||
|
|
||||||
while(tmp != NULL)
|
while(tmp)
|
||||||
{
|
{
|
||||||
int rc = (*tree->comparator)(node, tmp);
|
int rc = (*tree->comparator)(node, tmp);
|
||||||
if(rc < 0)
|
if(rc < 0)
|
||||||
@ -26,5 +29,8 @@ rbtree_find(const rbtree_t *tree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
rbtree_clear_busy((rbtree_t*)tree);
|
||||||
|
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,19 @@
|
|||||||
#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,
|
||||||
rbtree_node_comparator_t comparator)
|
rbtree_node_comparator_t comparator)
|
||||||
{
|
{
|
||||||
|
tree->treeTag[3] = 'T';
|
||||||
|
tree->treeTag[2] = 'R';
|
||||||
|
tree->treeTag[1] = 'E';
|
||||||
|
tree->treeTag[0] = 'E';
|
||||||
tree->root = NULL;
|
tree->root = NULL;
|
||||||
tree->comparator = comparator;
|
tree->comparator = comparator;
|
||||||
tree->size = 0;
|
tree->size = 0;
|
||||||
|
tree->busy = false;
|
||||||
|
LightLock_Init(&tree->lock);
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
}
|
}
|
||||||
|
@ -6,12 +6,30 @@ do_insert(rbtree_t *tree,
|
|||||||
rbtree_node_t *node,
|
rbtree_node_t *node,
|
||||||
int multi)
|
int multi)
|
||||||
{
|
{
|
||||||
|
rbtree_set_busy(tree);
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < 32; ++i)
|
||||||
|
{
|
||||||
|
node->prefix[i] = 0;
|
||||||
|
node->suffix[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node->nodeTag[3] = 'N';
|
||||||
|
node->nodeTag[2] = 'O';
|
||||||
|
node->nodeTag[1] = 'D';
|
||||||
|
node->nodeTag[0] = 'E';
|
||||||
|
node->parent_color = 0;
|
||||||
|
node->child[LEFT] = NULL;
|
||||||
|
node->child[RIGHT] = NULL;
|
||||||
|
node->tree = 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;
|
||||||
rbtree_node_t *save = NULL;
|
rbtree_node_t *save = NULL;
|
||||||
|
|
||||||
while(*tmp != NULL)
|
while(*tmp)
|
||||||
{
|
{
|
||||||
int cmp = (*(tree->comparator))(node, *tmp);
|
int cmp = (*(tree->comparator))(node, *tmp);
|
||||||
parent = *tmp;
|
parent = *tmp;
|
||||||
@ -29,8 +47,20 @@ do_insert(rbtree_t *tree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(save != NULL)
|
if(save)
|
||||||
{
|
{
|
||||||
|
node->nodeTag[3] = 'D';
|
||||||
|
node->nodeTag[2] = 'O';
|
||||||
|
node->nodeTag[1] = 'N';
|
||||||
|
node->nodeTag[0] = 'E';
|
||||||
|
node->parent_color = 0;
|
||||||
|
node->child[LEFT] = NULL;
|
||||||
|
node->child[RIGHT] = NULL;
|
||||||
|
node->tree = NULL;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
rbtree_clear_busy(tree);
|
||||||
|
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -78,6 +108,9 @@ do_insert(rbtree_t *tree,
|
|||||||
|
|
||||||
tree->size += 1;
|
tree->size += 1;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
rbtree_clear_busy(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
|
||||||
@ -28,7 +29,7 @@ set_red(rbtree_node_t *node)
|
|||||||
static inline rbtree_color_t
|
static inline rbtree_color_t
|
||||||
get_color(const rbtree_node_t *node)
|
get_color(const rbtree_node_t *node)
|
||||||
{
|
{
|
||||||
if(node == NULL)
|
if(!node)
|
||||||
return BLACK;
|
return BLACK;
|
||||||
return (rbtree_color_t)(node->parent_color & COLOR_MASK);
|
return (rbtree_color_t)(node->parent_color & COLOR_MASK);
|
||||||
}
|
}
|
||||||
@ -58,7 +59,19 @@ set_parent(rbtree_node_t *node,
|
|||||||
node->parent_color = (get_color(node)) | ((uintptr_t)parent);
|
node->parent_color = (get_color(node)) | ((uintptr_t)parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_set_busy(rbtree_t *tree);
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_clear_busy(rbtree_t *tree);
|
||||||
|
|
||||||
void
|
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);
|
||||||
|
@ -7,16 +7,16 @@ do_iterate(const rbtree_node_t *node,
|
|||||||
{
|
{
|
||||||
rbtree_node_t *it = (rbtree_node_t*)node;
|
rbtree_node_t *it = (rbtree_node_t*)node;
|
||||||
|
|
||||||
if(it->child[next] != NULL)
|
if(it->child[next])
|
||||||
{
|
{
|
||||||
it = it->child[next];
|
it = it->child[next];
|
||||||
while(it->child[!next] != NULL)
|
while(it->child[!next])
|
||||||
it = it->child[!next];
|
it = it->child[!next];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
rbtree_node_t *parent = get_parent(node);
|
rbtree_node_t *parent = get_parent(node);
|
||||||
while(parent != NULL && it == parent->child[next])
|
while(parent && it == parent->child[next])
|
||||||
{
|
{
|
||||||
it = parent;
|
it = parent;
|
||||||
parent = get_parent(it);
|
parent = get_parent(it);
|
||||||
|
@ -5,33 +5,32 @@ static inline rbtree_node_t*
|
|||||||
do_minmax(const rbtree_t *tree,
|
do_minmax(const rbtree_t *tree,
|
||||||
int max)
|
int max)
|
||||||
{
|
{
|
||||||
|
rbtree_set_busy((rbtree_t*)tree);
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
rbtree_node_t *node = tree->root;
|
rbtree_node_t *node = tree->root;
|
||||||
|
|
||||||
if(node == NULL)
|
if(!node)
|
||||||
|
{
|
||||||
|
rbtree_clear_busy((rbtree_t*)tree);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
while(node->child[max] != NULL)
|
while(node->child[max])
|
||||||
node = node->child[max];
|
node = node->child[max];
|
||||||
|
|
||||||
|
rbtree_clear_busy((rbtree_t*)tree);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
rbtree_node_t*
|
rbtree_node_t*
|
||||||
rbtree_min(const rbtree_t *tree)
|
rbtree_min(const rbtree_t *tree)
|
||||||
{
|
{
|
||||||
rbtree_node_t *node;
|
return do_minmax(tree, LEFT);
|
||||||
|
|
||||||
node = do_minmax(tree, LEFT);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rbtree_node_t*
|
rbtree_node_t*
|
||||||
rbtree_max(const rbtree_t *tree)
|
rbtree_max(const rbtree_t *tree)
|
||||||
{
|
{
|
||||||
rbtree_node_t *node;
|
return do_minmax(tree, RIGHT);
|
||||||
|
|
||||||
node = do_minmax(tree, RIGHT);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <3ds/util/rbtree.h>
|
#include <3ds/util/rbtree.h>
|
||||||
|
#include <3ds/svc.h>
|
||||||
#include "rbtree_internal.h"
|
#include "rbtree_internal.h"
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -51,31 +52,55 @@ recolor(rbtree_t *tree,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(node != NULL)
|
if(node)
|
||||||
set_black(node);
|
set_black(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
in_tree(const rbtree_t *tree,
|
||||||
|
const rbtree_node_t *node)
|
||||||
|
{
|
||||||
|
if(tree->root == node)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const rbtree_node_t *parent = get_parent(node);
|
||||||
|
while(parent)
|
||||||
|
{
|
||||||
|
if(tree->root == parent)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
parent = get_parent(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
rbtree_node_t*
|
rbtree_node_t*
|
||||||
rbtree_remove(rbtree_t *tree,
|
rbtree_remove(rbtree_t *tree,
|
||||||
rbtree_node_t *node,
|
rbtree_node_t *node,
|
||||||
rbtree_node_destructor_t destructor)
|
rbtree_node_destructor_t destructor)
|
||||||
{
|
{
|
||||||
|
rbtree_set_busy(tree);
|
||||||
|
if(!in_tree(tree, node))
|
||||||
|
svcBreak(USERBREAK_PANIC);
|
||||||
|
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;
|
||||||
|
|
||||||
next = rbtree_node_next(node);
|
next = rbtree_node_next(node);
|
||||||
|
|
||||||
if(node->child[LEFT] != NULL && node->child[RIGHT] != NULL)
|
if(node->child[LEFT] && node->child[RIGHT])
|
||||||
{
|
{
|
||||||
rbtree_node_t *old = node;
|
rbtree_node_t *old = node;
|
||||||
|
|
||||||
node = node->child[RIGHT];
|
node = node->child[RIGHT];
|
||||||
while(node->child[LEFT] != NULL)
|
while(node->child[LEFT])
|
||||||
node = node->child[LEFT];
|
node = node->child[LEFT];
|
||||||
|
|
||||||
parent = get_parent(old);
|
parent = get_parent(old);
|
||||||
if(parent != NULL)
|
if(parent)
|
||||||
{
|
{
|
||||||
if(parent->child[LEFT] == old)
|
if(parent->child[LEFT] == old)
|
||||||
parent->child[LEFT] = node;
|
parent->child[LEFT] = node;
|
||||||
@ -93,7 +118,7 @@ rbtree_remove(rbtree_t *tree,
|
|||||||
parent = node;
|
parent = node;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(child != NULL)
|
if(child)
|
||||||
set_parent(child, parent);
|
set_parent(child, parent);
|
||||||
parent->child[LEFT] = child;
|
parent->child[LEFT] = child;
|
||||||
|
|
||||||
@ -107,7 +132,7 @@ rbtree_remove(rbtree_t *tree,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if(node->child[LEFT] == NULL)
|
if(!node->child[LEFT])
|
||||||
child = node->child[RIGHT];
|
child = node->child[RIGHT];
|
||||||
else
|
else
|
||||||
child = node->child[LEFT];
|
child = node->child[LEFT];
|
||||||
@ -115,9 +140,9 @@ rbtree_remove(rbtree_t *tree,
|
|||||||
parent = get_parent(node);
|
parent = get_parent(node);
|
||||||
color = get_color(node);
|
color = get_color(node);
|
||||||
|
|
||||||
if(child != NULL)
|
if(child)
|
||||||
set_parent(child, parent);
|
set_parent(child, parent);
|
||||||
if(parent != NULL)
|
if(parent)
|
||||||
{
|
{
|
||||||
if(parent->child[LEFT] == node)
|
if(parent->child[LEFT] == node)
|
||||||
parent->child[LEFT] = child;
|
parent->child[LEFT] = child;
|
||||||
@ -131,10 +156,22 @@ rbtree_remove(rbtree_t *tree,
|
|||||||
if(color == BLACK)
|
if(color == BLACK)
|
||||||
recolor(tree, parent, child);
|
recolor(tree, parent, child);
|
||||||
|
|
||||||
if(destructor != NULL)
|
original->nodeTag[3] = 'D';
|
||||||
|
original->nodeTag[2] = 'O';
|
||||||
|
original->nodeTag[1] = 'N';
|
||||||
|
original->nodeTag[0] = 'E';
|
||||||
|
original->parent_color = 0;
|
||||||
|
original->child[LEFT] = NULL;
|
||||||
|
original->child[RIGHT] = NULL;
|
||||||
|
original->tree = NULL;
|
||||||
|
|
||||||
|
if(destructor)
|
||||||
(*destructor)(original);
|
(*destructor)(original);
|
||||||
|
|
||||||
tree->size -= 1;
|
tree->size -= 1;
|
||||||
|
|
||||||
|
rbtree_validate(tree);
|
||||||
|
rbtree_clear_busy(tree);
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
@ -10,12 +10,12 @@ rbtree_rotate(rbtree_t *tree,
|
|||||||
rbtree_node_t *parent = get_parent(node);
|
rbtree_node_t *parent = get_parent(node);
|
||||||
|
|
||||||
node->child[left] = tmp->child[!left];
|
node->child[left] = tmp->child[!left];
|
||||||
if(tmp->child[!left] != NULL)
|
if(tmp->child[!left])
|
||||||
set_parent(tmp->child[!left], node);
|
set_parent(tmp->child[!left], node);
|
||||||
|
|
||||||
tmp->child[!left] = node;
|
tmp->child[!left] = node;
|
||||||
set_parent(tmp, parent);
|
set_parent(tmp, parent);
|
||||||
if(parent != NULL)
|
if(parent)
|
||||||
{
|
{
|
||||||
if(node == parent->child[!left])
|
if(node == parent->child[!left])
|
||||||
parent->child[!left] = tmp;
|
parent->child[!left] = tmp;
|
||||||
|
@ -1,7 +1,14 @@
|
|||||||
#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)
|
||||||
{
|
{
|
||||||
return tree->size;
|
rbtree_set_busy((rbtree_t*)tree);
|
||||||
|
rbtree_validate(tree);
|
||||||
|
|
||||||
|
size_t size = tree->size;
|
||||||
|
|
||||||
|
rbtree_clear_busy((rbtree_t*)tree);
|
||||||
|
return size;
|
||||||
}
|
}
|
||||||
|
164
libctru/source/util/rbtree/rbtree_validate.c
Normal file
164
libctru/source/util/rbtree/rbtree_validate.c
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
#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))
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < 32; ++i)
|
||||||
|
{
|
||||||
|
if(node->prefix[i])
|
||||||
|
panic();
|
||||||
|
|
||||||
|
if(node->suffix[i])
|
||||||
|
panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_set_busy(rbtree_t *tree)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&tree->lock);
|
||||||
|
if(tree->busy)
|
||||||
|
panic();
|
||||||
|
|
||||||
|
tree->busy = true;
|
||||||
|
LightLock_Unlock(&tree->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rbtree_clear_busy(rbtree_t *tree)
|
||||||
|
{
|
||||||
|
LightLock_Lock(&tree->lock);
|
||||||
|
if(!tree->busy)
|
||||||
|
panic();
|
||||||
|
|
||||||
|
tree->busy = false;
|
||||||
|
LightLock_Unlock(&tree->lock);
|
||||||
|
}
|
28
libctru/source/util/rbtree/test/Makefile
Normal file
28
libctru/source/util/rbtree/test/Makefile
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
CFILES := $(wildcard ../*.c)
|
||||||
|
CXXFILES := $(wildcard *.cpp)
|
||||||
|
|
||||||
|
OFILES := $(patsubst ../%,%,$(CFILES:.c=.c.o))
|
||||||
|
OXXFILES := $(CXXFILES:.cpp=.cpp.o)
|
||||||
|
|
||||||
|
CPPFLAGS := -Wall -g -I../../../../include -O2 \
|
||||||
|
-D"LightLock=pthread_mutex_t" \
|
||||||
|
-D"LightLock_Init(x)=pthread_mutex_init(x, NULL)" \
|
||||||
|
-D"LightLock_Lock(x)=pthread_mutex_lock(x)" \
|
||||||
|
-D"LightLock_Unlock(x)=pthread_mutex_unlock(x)"
|
||||||
|
|
||||||
|
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)
|
130
libctru/source/util/rbtree/test/main.cpp
Normal file
130
libctru/source/util/rbtree/test/main.cpp
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
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)
|
||||||
|
{
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
// remove random node
|
||||||
|
if(remove() <= chance)
|
||||||
|
{
|
||||||
|
auto it = std::begin(nodes) + (eng() % nodes.size());
|
||||||
|
rbtree_remove(&tree, &(*it)->node, IntNodeDestructor);
|
||||||
|
nodes.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// printTree(&tree);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::printf("Ended with %zu nodes in tree\n", rbtree_size(&tree));
|
||||||
|
|
||||||
|
rbtree_clear(&tree, IntNodeDestructor);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user