Add table tests

This commit is contained in:
Krzosa Karol
2023-12-31 16:41:02 +01:00
parent b3f5ce3772
commit 0a81270278
6 changed files with 87 additions and 19 deletions

View File

@@ -62,10 +62,6 @@ struct Array {
ARRAY_ASSERT(index >= 0 && index < len); ARRAY_ASSERT(index >= 0 && index < len);
return data[index]; return data[index];
} }
T &operator[](long long index) {
ARRAY_ASSERT(index >= 0 && index < len);
return data[index];
}
bool is_first(T &item) { return &item == first(); } bool is_first(T &item) { return &item == first(); }
bool is_last(T &item) { return &item == last(); } bool is_last(T &item) { return &item == last(); }
@@ -81,7 +77,7 @@ struct Array {
return (int)offset; return (int)offset;
} }
void add(T item) { void add(const T &item) {
try_growing(); try_growing();
data[len++] = item; data[len++] = item;
} }
@@ -222,7 +218,7 @@ struct Array {
len = cap = 0; len = cap = 0;
} }
Array<T> exact_copy(ARRAY_Allocator allocator) { Array<T> copy(ARRAY_Allocator allocator) {
Array result = {}; Array result = {};
result.allocator = allocator; result.allocator = allocator;
result.reserve(cap); result.reserve(cap);
@@ -234,7 +230,7 @@ struct Array {
Array<T> tight_copy(ARRAY_Allocator allocator) { Array<T> tight_copy(ARRAY_Allocator allocator) {
Array result = {}; Array result = {};
ARRAY_ALLOCATOR_CODE(result.allocator = allocator;) result.allocator = allocator;
result.reserve(len); result.reserve(len);
ARRAY_MemoryMove(result.data, data, sizeof(T) * len); ARRAY_MemoryMove(result.data, data, sizeof(T) * len);

View File

@@ -14,6 +14,13 @@ set RELEASE_LINE=%RELEASE% %WRN% %COMMON% -link -incremental:no %LINK_RELEASE%
mkdir build mkdir build
cd build cd build
cl.exe -Fe:test_table.exe ../test/test_table.cpp %DEBUG_LINE%
if %errorlevel% neq 0 exit /b %errorlevel%
test_table.exe
if %errorlevel% neq 0 exit /b %errorlevel%
cl.exe -Fe:test_array.exe ../test/test_array.cpp %DEBUG_LINE% cl.exe -Fe:test_array.exe ../test/test_array.cpp %DEBUG_LINE%
if %errorlevel% neq 0 exit /b %errorlevel% if %errorlevel% neq 0 exit /b %errorlevel%
test_array.exe test_array.exe

2
core.h
View File

@@ -16,6 +16,8 @@
#include "defer.hpp" #include "defer.hpp"
#define TABLE_ASSERT IO_Assert #define TABLE_ASSERT IO_Assert
#define TABLE_ALLOCATOR_TYPE M_Allocator #define TABLE_ALLOCATOR_TYPE M_Allocator
#define TABLE_ALLOCATE(allocator, size) M_Alloc(allocator, size)
#define TABLE_DEALLOCATE(allocator, p) M_Dealloc(allocator, p)
#define TABLE_SET_DEFAULT_ALLOCATOR \ #define TABLE_SET_DEFAULT_ALLOCATOR \
if (!allocator.p) allocator = M_GetSystemAllocator(); if (!allocator.p) allocator = M_GetSystemAllocator();
#include "table.hpp" #include "table.hpp"

View File

@@ -57,6 +57,7 @@ TABLE_PRIVATE_FUNCTION uint64_t TABLE__HashBytes(void *data, unsigned size) {
#endif #endif
#define TABLE__WRAP_AROUND_POWER_OF_2(x, pow2) (((x) & ((pow2)-1llu))) #define TABLE__WRAP_AROUND_POWER_OF_2(x, pow2) (((x) & ((pow2)-1llu)))
#define TABLE__IS_POW2(x) (((x) & ((x)-1)) == 0)
TABLE_PRIVATE_FUNCTION int TABLE_CStringLen(char *str) { TABLE_PRIVATE_FUNCTION int TABLE_CStringLen(char *str) {
int i = 0; int i = 0;
@@ -79,11 +80,24 @@ struct Table {
size_t len, cap; size_t len, cap;
Entry *values; Entry *values;
static const size_t max_load_factor = 80;
static const size_t min_load_factor = 50;
static const size_t significant_distance = 8;
// load factor calculation was rearranged
// to get rid of division:
//> 100 * len / cap = load_factor
//> len * 100 = load_factor * cap
inline bool reached_load_factor(size_t lfactor) {
return (len + 1) * 100 >= lfactor * cap;
}
inline bool is_empty(Entry *entry) { return entry->hash == 0; } inline bool is_empty(Entry *entry) { return entry->hash == 0; }
inline bool is_occupied(Entry *entry) { return entry->hash != 0; } inline bool is_occupied(Entry *entry) { return entry->hash != 0; }
void reserve(size_t size) { void reserve(size_t size) {
TABLE_ASSERT(size > cap && "New size is smaller then original size"); TABLE_ASSERT(size > cap && "New size is smaller then original size");
TABLE_ASSERT(TABLE__IS_POW2(size));
TABLE_SET_DEFAULT_ALLOCATOR; TABLE_SET_DEFAULT_ALLOCATOR;
Entry *old_values = values; Entry *old_values = values;
@@ -132,14 +146,6 @@ struct Table {
TABLE_ASSERT(!"Invalid codepath"); TABLE_ASSERT(!"Invalid codepath");
} }
// load factor calculation was rearranged
// to get rid of division:
//> 100 * len / cap = load_factor
//> len * 100 = load_factor * cap
inline bool reached_load_factor(size_t lfactor) {
return (len + 1) * 100 >= lfactor * cap;
}
void insert(uint64_t key, const Value &value) { void insert(uint64_t key, const Value &value) {
if (reached_load_factor(max_load_factor)) { if (reached_load_factor(max_load_factor)) {
if (cap == 0) cap = 16; // 32 cause cap*2 if (cap == 0) cap = 16; // 32 cause cap*2
@@ -189,6 +195,7 @@ struct Table {
Entry *entry = get_table_entry(key); Entry *entry = get_table_entry(key);
entry->hash = 0; entry->hash = 0;
entry->distance = 0; entry->distance = 0;
len -= 1;
} }
Value *get(uint64_t key) { Value *get(uint64_t key) {
@@ -218,12 +225,9 @@ struct Table {
} }
void dealloc() { void dealloc() {
COR_DEALLOCATE(allocator, values); TABLE_DEALLOCATE(allocator, values);
len = 0; len = 0;
cap = 0; cap = 0;
values = 0; values = 0;
} }
static const size_t max_load_factor = 80;
static const size_t min_load_factor = 50;
static const size_t significant_distance = 8;
}; };

View File

@@ -112,11 +112,27 @@ void TestReverseLoop() {
array.dealloc(); array.dealloc();
} }
void TestCopy() {
MA_Scratch scratch;
auto a = GenArray();
auto b = a.tight_copy(scratch);
auto c = a.copy(scratch);
int i = 0;
For(b) IO_Assert(it == i++);
i = 0;
For(c) IO_Assert(it == i++);
IO_Assert(b.cap == b.len && b.len == a.len);
IO_Assert(a.len == c.len && a.cap == c.cap);
}
int main() { int main() {
TestExclusiveArenaBackedArray(); TestExclusiveArenaBackedArray();
TestRemoveForLoop(); TestRemoveForLoop();
TestBasic(); TestBasic();
TestReverseLoop(); TestReverseLoop();
TestCopy();
return 0; return 0;
} }

43
test/test_table.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include "../core.c"
void TestSimpleInsertAndIntegrity() {
MA_Scratch scratch;
Table<uint64_t> table = {scratch};
table.reserve(64);
for (uint64_t i = 0; i < 10000; i += 1) {
table.insert(i, i);
}
for (uint64_t i = 0; i < 10000; i += 1) {
uint64_t *v = table.get(i);
IO_Assert(*v == i);
}
IO_Assert(table.len == 10000);
IO_Assert(table.cap > table.len);
IO_Assert(MA_IS_POW2(table.cap));
table.remove(32);
table.reset();
table.dealloc();
}
void TestStrings() {
struct Data {
int a[32];
int i;
};
Table<Data> table = {};
table.puts("1", Data{{}, 1});
table.puts("2", Data{{}, 2});
table.puts("3", Data{{}, 3});
IO_Assert(table.gets("1")->i == 1);
IO_Assert(table.gets("2")->i == 2);
IO_Assert(table.gets("3")->i == 3);
}
int main() {
TestSimpleInsertAndIntegrity();
TestStrings();
return 0;
}