Add table tests
This commit is contained in:
10
array.hpp
10
array.hpp
@@ -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);
|
||||||
|
|||||||
@@ -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
2
core.h
@@ -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"
|
||||||
|
|||||||
28
table.hpp
28
table.hpp
@@ -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;
|
|
||||||
};
|
};
|
||||||
@@ -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
43
test/test_table.cpp
Normal 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;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user