mirror of
https://github.com/krgamestudios/Toy.git
synced 2026-04-15 23:04:08 +10:00
Wrote tests for Toy_Table
I hope that's it, I don't wanna do that again XD
This commit is contained in:
18
.notes/hash_generator_1.c
Normal file
18
.notes/hash_generator_1.c
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
https://www.programiz.com/c-programming/online-compiler/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static unsigned int hashUInt(unsigned int x) {
|
||||||
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
|
x = (x >> 16) ^ x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
//print the index/hash pairs
|
||||||
|
for (unsigned int i = 0; i < 100; i++) {
|
||||||
|
printf("{%u:%u}\n", i, hashUInt(i) % 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
23
.notes/hash_generator_2.c
Normal file
23
.notes/hash_generator_2.c
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
https://www.programiz.com/c-programming/online-compiler/
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
static unsigned int hashUInt(unsigned int x) {
|
||||||
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
|
x = ((x >> 16) ^ x) * 0x45d9f3b;
|
||||||
|
x = (x >> 16) ^ x;
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
//find the first number with a specific hash, then print the c-code
|
||||||
|
for (unsigned int h = 0; h < 20; h++) {
|
||||||
|
for (unsigned int i = 0; i < 100; i++) {
|
||||||
|
if (hashUInt(i) % 32 == h) {
|
||||||
|
printf("Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(%d), TOY_VALUE_TO_INTEGER(42)); //hash: %d\n", i, h);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -10,7 +10,7 @@
|
|||||||
#include "toy_stack.h"
|
#include "toy_stack.h"
|
||||||
#include "toy_bucket.h"
|
#include "toy_bucket.h"
|
||||||
#include "toy_string.h"
|
#include "toy_string.h"
|
||||||
//TODO: hashtable
|
#include "toy_table.h"
|
||||||
|
|
||||||
//IR structures and other components
|
//IR structures and other components
|
||||||
#include "toy_ast.h"
|
#include "toy_ast.h"
|
||||||
|
|||||||
@@ -9,59 +9,24 @@
|
|||||||
#define MIN_CAPACITY 16
|
#define MIN_CAPACITY 16
|
||||||
|
|
||||||
//utils
|
//utils
|
||||||
static Toy_Table* adjustTableCapacity(Toy_Table* oldTable, unsigned int newCapacity) {
|
static void probeAndInsert(Toy_Table** table, Toy_Value key, Toy_Value value) {
|
||||||
//allocate and zero a new table in memory
|
//make the entry
|
||||||
Toy_Table* newTable = malloc(newCapacity * sizeof(Toy_TableEntry) + sizeof(Toy_Table));
|
|
||||||
|
|
||||||
newTable->capacity = newCapacity;
|
|
||||||
newTable->count = 0;
|
|
||||||
newTable->minPsl = 0;
|
|
||||||
newTable->maxPsl = 0;
|
|
||||||
|
|
||||||
//unlike other structures, the empty space in a table needs to be null
|
|
||||||
memset(newTable + 1, 0, newTable->capacity * sizeof(Toy_TableEntry));
|
|
||||||
|
|
||||||
if (oldTable == NULL) { //for initial allocations
|
|
||||||
return newTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//for each entry in the old table, copy it into the new table
|
|
||||||
for (int i = 0; i < oldTable->capacity; i++) {
|
|
||||||
Toy_insertTable(&newTable, oldTable->data[i].key, oldTable->data[i].value);
|
|
||||||
}
|
|
||||||
|
|
||||||
//clean up and return
|
|
||||||
free(oldTable);
|
|
||||||
return newTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
//exposed functions
|
|
||||||
Toy_Table* Toy_allocateTable() {
|
|
||||||
return adjustTableCapacity(NULL, MIN_CAPACITY);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_freeTable(Toy_Table* table) {
|
|
||||||
//TODO: slip in a call to free the complex values here
|
|
||||||
|
|
||||||
free(table);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value) {
|
|
||||||
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
|
||||||
exit(-1); //TODO: #127
|
|
||||||
}
|
|
||||||
|
|
||||||
//expand the capacity
|
|
||||||
if ((*table)->capacity < (*table)->count * (1 / 0.75f)) {
|
|
||||||
(*table) = adjustTableCapacity(*table, (*table)->capacity * 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
//insert
|
|
||||||
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
||||||
Toy_TableEntry entry = (Toy_TableEntry){ .key = key, .value = value, .psl = 0 };
|
Toy_TableEntry entry = (Toy_TableEntry){ .key = key, .value = value, .psl = 0 };
|
||||||
|
|
||||||
|
//probe
|
||||||
while (true) {
|
while (true) {
|
||||||
|
//if we're overriding an existing value
|
||||||
|
if (TOY_VALUE_IS_EQUAL((*table)->data[probe].key, key)) {
|
||||||
|
(*table)->data[probe] = entry;
|
||||||
|
|
||||||
|
//TODO: benchmark the psl optimisation
|
||||||
|
(*table)->minPsl = entry.psl < (*table)->minPsl ? entry.psl : (*table)->minPsl;
|
||||||
|
(*table)->maxPsl = entry.psl > (*table)->maxPsl ? entry.psl : (*table)->maxPsl;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//if this spot is free, insert and return
|
//if this spot is free, insert and return
|
||||||
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
||||||
(*table)->data[probe] = entry;
|
(*table)->data[probe] = entry;
|
||||||
@@ -88,7 +53,65 @@ void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Toy_Value Toy_lookupTableValue(Toy_Table** table, Toy_Value key) {
|
static Toy_Table* adjustTableCapacity(Toy_Table* oldTable, unsigned int newCapacity) {
|
||||||
|
//allocate and zero a new table in memory
|
||||||
|
Toy_Table* newTable = malloc(newCapacity * sizeof(Toy_TableEntry) + sizeof(Toy_Table));
|
||||||
|
|
||||||
|
if (newTable == NULL) {
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a 'Toy_Table' of %u capacity\n" TOY_CC_RESET, newCapacity);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
newTable->capacity = newCapacity;
|
||||||
|
newTable->count = 0;
|
||||||
|
newTable->minPsl = 0;
|
||||||
|
newTable->maxPsl = 0;
|
||||||
|
|
||||||
|
//unlike other structures, the empty space in a table needs to be null
|
||||||
|
memset(newTable + 1, 0, newTable->capacity * sizeof(Toy_TableEntry));
|
||||||
|
|
||||||
|
if (oldTable == NULL) { //for initial allocations
|
||||||
|
return newTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
//for each entry in the old table, copy it into the new table
|
||||||
|
for (int i = 0; i < oldTable->capacity; i++) {
|
||||||
|
if (!TOY_VALUE_IS_NULL(oldTable->data[i].key)) {
|
||||||
|
probeAndInsert(&newTable, oldTable->data[i].key, oldTable->data[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//clean up and return
|
||||||
|
free(oldTable);
|
||||||
|
return newTable;
|
||||||
|
}
|
||||||
|
|
||||||
|
//exposed functions
|
||||||
|
Toy_Table* Toy_allocateTable() {
|
||||||
|
return adjustTableCapacity(NULL, MIN_CAPACITY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_freeTable(Toy_Table* table) {
|
||||||
|
//TODO: slip in a call to free the complex values here
|
||||||
|
|
||||||
|
free(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value) {
|
||||||
|
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||||
|
exit(-1); //TODO: #127
|
||||||
|
}
|
||||||
|
|
||||||
|
//expand the capacity
|
||||||
|
if ((*table)->count > (*table)->capacity * 0.8) {
|
||||||
|
(*table) = adjustTableCapacity(*table, (*table)->capacity * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
probeAndInsert(table, key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Value Toy_lookupTable(Toy_Table** table, Toy_Value key) {
|
||||||
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||||
exit(-1); //TODO: #127
|
exit(-1); //TODO: #127
|
||||||
@@ -96,7 +119,6 @@ Toy_Value Toy_lookupTableValue(Toy_Table** table, Toy_Value key) {
|
|||||||
|
|
||||||
//lookup
|
//lookup
|
||||||
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
||||||
unsigned int counter = 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
//found the entry
|
//found the entry
|
||||||
@@ -104,18 +126,17 @@ Toy_Value Toy_lookupTableValue(Toy_Table** table, Toy_Value key) {
|
|||||||
return (*table)->data[probe].value;
|
return (*table)->data[probe].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if the psl is too big, or empty slot
|
//if its an empty slot
|
||||||
if ((*table)->data[probe].psl > counter || TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
||||||
return TOY_VALUE_TO_NULL();
|
return TOY_VALUE_TO_NULL();
|
||||||
}
|
}
|
||||||
|
|
||||||
//adjust and continue
|
//adjust and continue
|
||||||
probe = (probe + 1) % (*table)->capacity;
|
probe = (probe + 1) % (*table)->capacity;
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Toy_removeTableEntry(Toy_Table** table, Toy_Value key) {
|
void Toy_removeTable(Toy_Table** table, Toy_Value key) {
|
||||||
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
if (TOY_VALUE_IS_NULL(key) || TOY_VALUE_IS_BOOLEAN(key)) { //TODO: disallow functions and opaques
|
||||||
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad table key\n" TOY_CC_RESET);
|
||||||
exit(-1); //TODO: #127
|
exit(-1); //TODO: #127
|
||||||
@@ -123,7 +144,6 @@ void Toy_removeTableEntry(Toy_Table** table, Toy_Value key) {
|
|||||||
|
|
||||||
//lookup
|
//lookup
|
||||||
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
unsigned int probe = Toy_hashValue(key) % (*table)->capacity;
|
||||||
unsigned int counter = 0;
|
|
||||||
unsigned int wipe = probe; //wiped at the end
|
unsigned int wipe = probe; //wiped at the end
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
@@ -132,31 +152,31 @@ void Toy_removeTableEntry(Toy_Table** table, Toy_Value key) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if the psl is too big, or empty slot
|
//if its an empty slot
|
||||||
if ((*table)->data[probe].psl > counter || TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
if (TOY_VALUE_IS_NULL((*table)->data[probe].key)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//adjust and continue
|
//adjust and continue
|
||||||
probe = (probe + 1) % (*table)->capacity;
|
probe = (probe + 1) % (*table)->capacity;
|
||||||
counter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//shift down the later entries (past the probing point)
|
//shift along the later entries
|
||||||
for (unsigned int i = (*table)->minPsl; i < (*table)->maxPsl; i++) {
|
for (unsigned int i = (*table)->minPsl; i < (*table)->maxPsl; i++) {
|
||||||
unsigned int p = (probe + i + 0) % (*table)->capacity; //prev
|
unsigned int p = (probe + i + 0) % (*table)->capacity; //prev
|
||||||
unsigned int u = (probe + i + 1) % (*table)->capacity; //current
|
unsigned int u = (probe + i + 1) % (*table)->capacity; //current
|
||||||
|
|
||||||
//if the psl is too big, or an empty slot, stop
|
|
||||||
if ((*table)->data[u].psl > (counter + i) || TOY_VALUE_IS_NULL((*table)->data[u].key)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*table)->data[p] = (*table)->data[u];
|
(*table)->data[p] = (*table)->data[u];
|
||||||
(*table)->data[p].psl--;
|
(*table)->data[p].psl--;
|
||||||
wipe = wipe % (*table)->capacity;
|
|
||||||
|
//if you hit something where it should be, or nothing at all, stop
|
||||||
|
if (TOY_VALUE_IS_NULL((*table)->data[u].key) || (*table)->data[p].psl == 0) {
|
||||||
|
wipe = u;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//finally, wipe the removed entry
|
//finally, wipe the removed entry
|
||||||
(*table)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 };
|
(*table)->data[wipe] = (Toy_TableEntry){ .key = TOY_VALUE_TO_NULL(), .value = TOY_VALUE_TO_NULL(), .psl = 0 };
|
||||||
|
(*table)->count--;
|
||||||
}
|
}
|
||||||
@@ -23,5 +23,5 @@ typedef struct Toy_Table { //32 | 64 BITNESS
|
|||||||
TOY_API Toy_Table* Toy_allocateTable();
|
TOY_API Toy_Table* Toy_allocateTable();
|
||||||
TOY_API void Toy_freeTable(Toy_Table* table);
|
TOY_API void Toy_freeTable(Toy_Table* table);
|
||||||
TOY_API void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value);
|
TOY_API void Toy_insertTable(Toy_Table** table, Toy_Value key, Toy_Value value);
|
||||||
TOY_API Toy_Value Toy_lookupTableValue(Toy_Table** table, Toy_Value key);
|
TOY_API Toy_Value Toy_lookupTable(Toy_Table** table, Toy_Value key);
|
||||||
TOY_API void Toy_removeTableEntry(Toy_Table** table, Toy_Value key);
|
TOY_API void Toy_removeTable(Toy_Table** table, Toy_Value key);
|
||||||
|
|||||||
@@ -4,17 +4,610 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
int test_table_allocation() {
|
int test_table_allocation() {
|
||||||
|
//allocate and free a table
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//check
|
||||||
|
if (table == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to allocate a table\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_table_simple_insert_lookup_and_remove() {
|
||||||
|
//simple insert
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
Toy_Value key = TOY_VALUE_TO_INTEGER(1);
|
||||||
|
Toy_Value value = TOY_VALUE_TO_INTEGER(42);
|
||||||
|
|
||||||
|
//insert
|
||||||
|
Toy_insertTable(&table, key, value);
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 1)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to insert into a table\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//lookup
|
||||||
|
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_TO_INTEGER(1));
|
||||||
|
|
||||||
|
//check lookup
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 1 ||
|
||||||
|
TOY_VALUE_AS_INTEGER(result) != 42)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to lookup from a table\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove
|
||||||
|
Toy_removeTable(&table, TOY_VALUE_TO_INTEGER(1));
|
||||||
|
|
||||||
|
//check remove
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 0)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to remove from a table\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//macros are a godsend
|
||||||
|
#define TEST_ENTRY_STATE(i, k, v, p) \
|
||||||
|
TOY_VALUE_IS_INTEGER(table->data[i].key) != true || \
|
||||||
|
TOY_VALUE_AS_INTEGER(table->data[i].key) != k || \
|
||||||
|
TOY_VALUE_IS_INTEGER(table->data[i].value) != true || \
|
||||||
|
TOY_VALUE_AS_INTEGER(table->data[i].value) != v || \
|
||||||
|
table->data[i].psl != p
|
||||||
|
|
||||||
|
int test_table_contents_no_expansion() {
|
||||||
|
//single insert
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//insert a key and value
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(1), TOY_VALUE_TO_INTEGER(42));
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 1 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(7, 1, 42, 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, single insert {1:42}\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiple inserts, no collisions
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(1), TOY_VALUE_TO_INTEGER(42)); //hash: 7
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(2), TOY_VALUE_TO_INTEGER(69)); //hash: 8
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(3), TOY_VALUE_TO_INTEGER(420)); //hash: 5
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 3 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(7, 1, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(8, 2, 69, 0) ||
|
||||||
|
TEST_ENTRY_STATE(5, 3, 420, 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, multiple inserts, no collisions {1:42},{2:69},{3:420}\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiple inserts, with collisions
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(1), TOY_VALUE_TO_INTEGER(42)); //hash: 7
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(14), TOY_VALUE_TO_INTEGER(69)); //hash: 7
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(76), TOY_VALUE_TO_INTEGER(420)); //hash: 7
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(80), TOY_VALUE_TO_INTEGER(8891)); //hash: 7
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 4 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(7, 1, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(8, 14, 69, 1) ||
|
||||||
|
TEST_ENTRY_STATE(9, 76, 420, 2) ||
|
||||||
|
TEST_ENTRY_STATE(10, 80, 8891, 3)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions {1:42},{14:69},{76:420},{80:8891}\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiple inserts, with collisions, modulo wrap
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(17), TOY_VALUE_TO_INTEGER(42)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(33), TOY_VALUE_TO_INTEGER(69)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(70), TOY_VALUE_TO_INTEGER(420)); //hash: 15
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 3 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(15, 17, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(0, 33, 69, 1) ||
|
||||||
|
TEST_ENTRY_STATE(1, 70, 420, 2)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions, modulo wrap {17:42},{33:69},{70:420}\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//lookup, with collisions, modulo wrap
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(17), TOY_VALUE_TO_INTEGER(42)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(33), TOY_VALUE_TO_INTEGER(69)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(70), TOY_VALUE_TO_INTEGER(420)); //hash: 15
|
||||||
|
|
||||||
|
//lookup
|
||||||
|
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_TO_INTEGER(33));
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 3 ||
|
||||||
|
|
||||||
|
TOY_VALUE_IS_INTEGER(result) != true ||
|
||||||
|
TOY_VALUE_AS_INTEGER(result) != 69
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad result from table lookup with collisions and modulo wrap\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiple inserts, with collisions, modulo wrap, psl overlap
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(17), TOY_VALUE_TO_INTEGER(42)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(33), TOY_VALUE_TO_INTEGER(69)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(70), TOY_VALUE_TO_INTEGER(420)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(35), TOY_VALUE_TO_INTEGER(8891)); //hash: 1
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 4 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(15, 17, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(0, 33, 69, 1) ||
|
||||||
|
TEST_ENTRY_STATE(1, 70, 420, 2) ||
|
||||||
|
TEST_ENTRY_STATE(2, 35, 8891, 1)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions, modulo wrap, psl overlap {17:42},{33:69},{70:420},{35:8891}\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiple inserts, with collisions, modulo wrap, psl overlap, psl shift
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(17), TOY_VALUE_TO_INTEGER(42)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(33), TOY_VALUE_TO_INTEGER(69)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(70), TOY_VALUE_TO_INTEGER(420)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(35), TOY_VALUE_TO_INTEGER(8891)); //hash: 1
|
||||||
|
|
||||||
|
//remove
|
||||||
|
Toy_removeTable(&table, TOY_VALUE_TO_INTEGER(33));
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 16 ||
|
||||||
|
table->count != 3 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(15, 17, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(0, 70, 420, 1) ||
|
||||||
|
TEST_ENTRY_STATE(1, 35, 8891, 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data, muiltiple inserts, with collisions, modulo wrap, psl overlap, psl shift {17:42},{*33:69},{70:420},{35:8891}\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_table_contents_with_expansions() {
|
||||||
|
//simple expansion
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//insert a key and value
|
||||||
|
for (int i = 0; i < 20; i++) {
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(i), TOY_VALUE_TO_INTEGER(42));
|
||||||
|
}
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 32 ||
|
||||||
|
table->count != 20
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Failed to expand table capacity\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//expansion, multiple inserts, no collisions
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(0), TOY_VALUE_TO_INTEGER(42)); //hash: 0
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(35), TOY_VALUE_TO_INTEGER(42)); //hash: 1
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(19), TOY_VALUE_TO_INTEGER(42)); //hash: 2
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(8), TOY_VALUE_TO_INTEGER(42)); //hash: 3
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(10), TOY_VALUE_TO_INTEGER(42)); //hash: 4
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(3), TOY_VALUE_TO_INTEGER(42)); //hash: 5
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(28), TOY_VALUE_TO_INTEGER(42)); //hash: 6
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(1), TOY_VALUE_TO_INTEGER(42)); //hash: 7
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(6), TOY_VALUE_TO_INTEGER(42)); //hash: 8
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(93), TOY_VALUE_TO_INTEGER(42)); //hash: 9
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(85), TOY_VALUE_TO_INTEGER(42)); //hash: 10
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(9), TOY_VALUE_TO_INTEGER(42)); //hash: 11
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(11), TOY_VALUE_TO_INTEGER(42)); //hash: 12
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(22), TOY_VALUE_TO_INTEGER(42)); //hash: 13
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(13), TOY_VALUE_TO_INTEGER(42)); //hash: 14
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(17), TOY_VALUE_TO_INTEGER(42)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(43), TOY_VALUE_TO_INTEGER(42)); //hash: 16
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(4), TOY_VALUE_TO_INTEGER(42)); //hash: 17
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(5), TOY_VALUE_TO_INTEGER(42)); //hash: 18
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(7), TOY_VALUE_TO_INTEGER(42)); //hash: 19
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 32 ||
|
||||||
|
table->count != 20 ||
|
||||||
|
|
||||||
|
//effectively, check that each key was placed in the correct position after the expansion
|
||||||
|
TEST_ENTRY_STATE(0, 0, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(1, 35, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(2, 19, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(3, 8, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(4, 10, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(5, 3, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(6, 28, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(7, 1, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(8, 6, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(9, 93, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(10, 85, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(11, 9, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(12, 11, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(13, 22, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(14, 13, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(15, 17, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(16, 43, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(17, 4, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(18, 5, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(19, 7, 42, 0)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data after expansion, multiple inserts, no collisions\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiple inserts, with collisions
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(0), TOY_VALUE_TO_INTEGER(42)); //hash: 0
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(35), TOY_VALUE_TO_INTEGER(42)); //hash: 1
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(19), TOY_VALUE_TO_INTEGER(42)); //hash: 2
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(8), TOY_VALUE_TO_INTEGER(42)); //hash: 3
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(10), TOY_VALUE_TO_INTEGER(42)); //hash: 4
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(3), TOY_VALUE_TO_INTEGER(42)); //hash: 5
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(28), TOY_VALUE_TO_INTEGER(42)); //hash: 6
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(1), TOY_VALUE_TO_INTEGER(42)); //hash: 7
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(6), TOY_VALUE_TO_INTEGER(42)); //hash: 8
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(93), TOY_VALUE_TO_INTEGER(42)); //hash: 9
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(85), TOY_VALUE_TO_INTEGER(42)); //hash: 10
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(9), TOY_VALUE_TO_INTEGER(42)); //hash: 11
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(11), TOY_VALUE_TO_INTEGER(42)); //hash: 12
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(22), TOY_VALUE_TO_INTEGER(42)); //hash: 13
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(13), TOY_VALUE_TO_INTEGER(42)); //hash: 14
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(17), TOY_VALUE_TO_INTEGER(42)); //hash: 15
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(43), TOY_VALUE_TO_INTEGER(42)); //hash: 16
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(4), TOY_VALUE_TO_INTEGER(42)); //hash: 17
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(5), TOY_VALUE_TO_INTEGER(42)); //hash: 18
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(7), TOY_VALUE_TO_INTEGER(42)); //hash: 19
|
||||||
|
|
||||||
|
//insert one more
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(70), TOY_VALUE_TO_INTEGER(42)); //hash: 15
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 32 ||
|
||||||
|
table->count != 21 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(0, 0, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(1, 35, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(2, 19, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(3, 8, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(4, 10, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(5, 3, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(6, 28, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(7, 1, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(8, 6, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(9, 93, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(10, 85, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(11, 9, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(12, 11, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(13, 22, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(14, 13, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(15, 17, 42, 0) ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(16, 70, 42, 1) || //the collision
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(17, 43, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(18, 4, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(19, 5, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(20, 7, 42, 1)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data after expansion, muiltiple inserts, with collisions\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//multiple inserts, with collisions, modulo wrap
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(123), TOY_VALUE_TO_INTEGER(42)); //hash: 20
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(42), TOY_VALUE_TO_INTEGER(42)); //hash: 21
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(132), TOY_VALUE_TO_INTEGER(42)); //hash: 22
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(34), TOY_VALUE_TO_INTEGER(42)); //hash: 23
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(2), TOY_VALUE_TO_INTEGER(42)); //hash: 24
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(32), TOY_VALUE_TO_INTEGER(42)); //hash: 25
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(21), TOY_VALUE_TO_INTEGER(42)); //hash: 26
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(44), TOY_VALUE_TO_INTEGER(42)); //hash: 27
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(104), TOY_VALUE_TO_INTEGER(42)); //hash: 28
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(15), TOY_VALUE_TO_INTEGER(42)); //hash: 29
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(57), TOY_VALUE_TO_INTEGER(42)); //hash: 30
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(33), TOY_VALUE_TO_INTEGER(42)); //hash: 31
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(0), TOY_VALUE_TO_INTEGER(42)); //hash: 32
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(35), TOY_VALUE_TO_INTEGER(42)); //hash: 33
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(19), TOY_VALUE_TO_INTEGER(42)); //hash: 34
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(8), TOY_VALUE_TO_INTEGER(42)); //hash: 35
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(10), TOY_VALUE_TO_INTEGER(42)); //hash: 36
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(3), TOY_VALUE_TO_INTEGER(42)); //hash: 37
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(28), TOY_VALUE_TO_INTEGER(42)); //hash: 38
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(1), TOY_VALUE_TO_INTEGER(42)); //hash: 39
|
||||||
|
|
||||||
|
//insert one more
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(79), TOY_VALUE_TO_INTEGER(42)); //hash: 23
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 32 ||
|
||||||
|
table->count != 21 ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(20, 123, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(21, 42, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(22, 132, 42, 0) ||
|
||||||
|
TEST_ENTRY_STATE(23, 34, 42, 0) ||
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(24, 79, 42, 1) || //the collision
|
||||||
|
|
||||||
|
TEST_ENTRY_STATE(25, 2, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(26, 32, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(27, 21, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(28, 44, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(29, 104, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(30, 15, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(31, 57, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(0, 33, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(1, 0, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(2, 35, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(3, 19, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(4, 8, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(5, 10, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(6, 3, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(7, 28, 42, 1) ||
|
||||||
|
TEST_ENTRY_STATE(8, 1, 42, 1)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Unrecognized state from table data after expansion, muiltiple inserts, with collisions, modulo wrap\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//lookup, with collisions, modulo wrap
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
//inserts
|
||||||
|
for (int i = 0; i < 20; i++) { //enough to expand
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(i), TOY_VALUE_TO_INTEGER(100 - i));
|
||||||
|
}
|
||||||
|
|
||||||
|
//lookup
|
||||||
|
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_TO_INTEGER(15));
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 32 ||
|
||||||
|
table->count != 20 ||
|
||||||
|
|
||||||
|
TOY_VALUE_IS_INTEGER(result) != true ||
|
||||||
|
TOY_VALUE_AS_INTEGER(result) != 85
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Bad result from table lookup after expansion, with collisions and modulo wrap\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Skipped: multiple inserts, with collisions, modulo wrap, psl overlap
|
||||||
|
//Skipped: multiple inserts, with collisions, modulo wrap, psl overlap, psl shift
|
||||||
|
|
||||||
|
//Note: since psl overlap and psl shift both work without expansion, I'm leaving these tests unimplemented due to exhaustion.
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_table_expansions_under_stress() {
|
||||||
|
//multiple expansions, find one value
|
||||||
|
{
|
||||||
|
//setup
|
||||||
|
Toy_Table* table = Toy_allocateTable();
|
||||||
|
|
||||||
|
int top = 300;
|
||||||
|
|
||||||
|
//insert keys and values
|
||||||
|
for (int i = 0; i < 300; i++) {
|
||||||
|
Toy_insertTable(&table, TOY_VALUE_TO_INTEGER(i), TOY_VALUE_TO_INTEGER(top - i));
|
||||||
|
}
|
||||||
|
|
||||||
|
Toy_Value result = Toy_lookupTable(&table, TOY_VALUE_TO_INTEGER(265));
|
||||||
|
|
||||||
|
//check the state
|
||||||
|
if (table == NULL ||
|
||||||
|
table->capacity != 512 ||
|
||||||
|
table->count != 300 ||
|
||||||
|
|
||||||
|
TOY_VALUE_IS_INTEGER(result) != true ||
|
||||||
|
TOY_VALUE_AS_INTEGER(result) != 35
|
||||||
|
)
|
||||||
|
{
|
||||||
|
fprintf(stderr, TOY_CC_ERROR "ERROR: Table expansions under stress failed\n" TOY_CC_RESET);
|
||||||
|
Toy_freeTable(table);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//free
|
||||||
|
Toy_freeTable(table);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
//not finished yet
|
|
||||||
fprintf(stderr, TOY_CC_WARN "'Toy_Table' is not yet tested\n" TOY_CC_RESET);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
//run each test set, returning the total errors given
|
//run each test set, returning the total errors given
|
||||||
int total = 0, res = 0;
|
int total = 0, res = 0;
|
||||||
|
|
||||||
|
//Note: there's some utility c programs in .notes called "hash_generator" that can help
|
||||||
|
|
||||||
{
|
{
|
||||||
res = test_table_allocation();
|
res = test_table_allocation();
|
||||||
if (res == 0) {
|
if (res == 0) {
|
||||||
@@ -23,5 +616,37 @@ int main() {
|
|||||||
total += res;
|
total += res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = test_table_simple_insert_lookup_and_remove();
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = test_table_contents_no_expansion();
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = test_table_contents_with_expansions();
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
res = test_table_expansions_under_stress();
|
||||||
|
if (res == 0) {
|
||||||
|
printf(TOY_CC_NOTICE "All good\n" TOY_CC_RESET);
|
||||||
|
}
|
||||||
|
total += res;
|
||||||
|
}
|
||||||
|
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user