mirror of
https://github.com/Ed94/metadesk.git
synced 2026-07-23 16:07:51 +00:00
[map] overhaul the maps, fewer parts, fewer paths, fewer knobs; same great results
This commit is contained in:
+80
-18
@@ -311,22 +311,20 @@ main:
|
||||
//~ String-To-Node table
|
||||
|
||||
@send(Map)
|
||||
@doc("Controls the behavior of routines that write into maps when the written key was already in the map.")
|
||||
@see(MD_Map)
|
||||
@see(MD_StringMap_Insert)
|
||||
@see(MD_PtrMap_Insert)
|
||||
@enum MD_MapCollisionRule: {
|
||||
@doc("When the key written was already in the map, a new key value pair is attached to the same chain always. Leaving multiple values associated to the same key.")
|
||||
Chain,
|
||||
@doc("When the key written was already in the map, the existing value is replaced with the newly inserted value.")
|
||||
Overwrite,
|
||||
}
|
||||
@doc("An abstraction over the types of keys used in a MD_Map and the work of hashing those keys, can be constructed from an MD_String8 or an void*.")
|
||||
@struct MD_MapKey: {
|
||||
@doc("The hash of the key. The hash function used is determined from the key type.")
|
||||
hash: MD_u64,
|
||||
@doc("For a non-empty MD_String8, the size of the string data. For a void*, zero.")
|
||||
size: MD_u64,
|
||||
@doc("For a non-empty MD_String8, points to the string data of the key. For a void*, the direct pointer value.")
|
||||
ptr: *void,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
@doc("A slot containing one (key,value) pair in a MD_Map.")
|
||||
@see(MD_Map)
|
||||
@struct MD_MapSlot: {
|
||||
@doc("The next slot in the same bucket of the MD_Map")
|
||||
@doc("The next slot in the same bucket of the MD_Map.")
|
||||
next: *MD_MapSlot,
|
||||
@doc("For slots with a string key, the hash of the key.")
|
||||
hash: MD_u64,
|
||||
@@ -828,12 +826,6 @@ main:
|
||||
return: MD_f64,
|
||||
};
|
||||
|
||||
@send(Strings)
|
||||
@func MD_HashString: {
|
||||
string: MD_String8,
|
||||
return: MD_u64,
|
||||
};
|
||||
|
||||
@send(Strings)
|
||||
@func MD_CalculateCStringLength: {
|
||||
cstr: *char,
|
||||
@@ -918,9 +910,79 @@ main:
|
||||
return: MD_String32,
|
||||
};
|
||||
|
||||
////////////////////////////////
|
||||
//~ Map Table Data Structure
|
||||
|
||||
@send(Map)
|
||||
@func MD_HashString: {
|
||||
string: MD_String8,
|
||||
return: MD_u64,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
@func MD_HashPointer: {
|
||||
p: *void,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapMakeBucketCount: {
|
||||
bucket_count: MD_u64,
|
||||
return: MD_Map,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapMake: {
|
||||
return: MD_Map,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapKeyStr: {
|
||||
string: MD_String8,
|
||||
return: MD_MapKey,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapKeyPtr: {
|
||||
ptr: *void,
|
||||
return: MD_MapKey,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapLookup: {
|
||||
map: *MD_Map,
|
||||
key: MD_MapKey,
|
||||
return: *MD_MapSlot,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapScan: {
|
||||
first_slot: *MD_MapSlot,
|
||||
key: MD_MapKey,
|
||||
return: *MD_MapSlot,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapInsert: {
|
||||
map: *MD_Map,
|
||||
key: MD_MapKey,
|
||||
val: *void,
|
||||
return: *MD_MapSlot,
|
||||
};
|
||||
|
||||
@send(Map)
|
||||
MD_MapOverwrite: {
|
||||
map: *MD_Map,
|
||||
key: MD_MapKey,
|
||||
val: *void,
|
||||
return: *MD_MapSlot,
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////
|
||||
//~ String-To-Pointer Table
|
||||
|
||||
// TODO(allen): update reference for map
|
||||
|
||||
@send(Map)
|
||||
@func MD_StringMap_Lookup: {
|
||||
table: *MD_Map,
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
|
||||
static MD_Map MapFromChildren(MD_Node *node)
|
||||
{
|
||||
MD_Map result = {0};
|
||||
MD_Map result = MD_MapMake();
|
||||
for(MD_EachNodeRef(child, node->first_child))
|
||||
{
|
||||
MD_StringMap_Insert(&result, MD_MapCollisionRule_Chain, child->string, child);
|
||||
MD_MapInsert(&result, MD_MapKeyStr(child->string), child);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ OutputType_C_LHS_Namespace(FILE *file, MD_Map *user_defined_types, MD_String8 pr
|
||||
{
|
||||
MD_Node *node = type->node;
|
||||
|
||||
if(MD_StringMap_Lookup(user_defined_types, type->node->string))
|
||||
if(MD_MapLookup(user_defined_types, MD_MapKeyStr(node->string)))
|
||||
{
|
||||
fprintf(file, "%.*s", MD_StringExpand(prefix));
|
||||
}
|
||||
@@ -156,10 +156,10 @@ static void AppendConversionCode(FILE *f, MD_Map *user_defined_types, MD_Node *n
|
||||
|
||||
for(MD_EachNode(member, old_element->first_child))
|
||||
{
|
||||
MD_MapSlot *slot = MD_StringMap_Lookup(&new_element_map, member->string);
|
||||
MD_MapSlot *slot = MD_MapLookup(&new_element_map, MD_MapKeyStr(member->string));
|
||||
if(slot)
|
||||
{
|
||||
AppendConversionCode(f, user_defined_types, member, slot->value, extended_member_path);
|
||||
AppendConversionCode(f, user_defined_types, member, slot->val, extended_member_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -177,7 +177,7 @@ static void AppendConversionCode(FILE *f, MD_Map *user_defined_types, MD_Node *n
|
||||
MD_String8 extended_member_path = MD_PushStringF("%.*s.%.*s", MD_StringExpand(member_path),
|
||||
MD_StringExpand(old_element->string));
|
||||
|
||||
if(MD_StringMap_Lookup(user_defined_types, type_name))
|
||||
if(MD_MapLookup(user_defined_types, MD_MapKeyStr(type_name)))
|
||||
{
|
||||
fprintf(f, " result%.*s = %.*sFromV1(v%.*s);\n",
|
||||
MD_StringExpand(extended_member_path), MD_StringExpand(type_name),
|
||||
@@ -236,7 +236,7 @@ int main(int argument_count, char **arguments)
|
||||
|
||||
// NOTE(mal): Old types get "v1_" as a prefix
|
||||
fprintf(f, "// V1\n");
|
||||
MD_Node *v1 = MD_StringMap_Lookup(&ns_map, MD_S8Lit("v1"))->value;
|
||||
MD_Node *v1 = MD_MapLookup(&ns_map, MD_MapKeyStr(MD_S8Lit("v1")))->val;
|
||||
MD_Map v1_map = MapFromChildren(v1);
|
||||
for(MD_EachNodeRef(node, v1->first_child))
|
||||
{
|
||||
@@ -247,7 +247,7 @@ int main(int argument_count, char **arguments)
|
||||
fprintf(f, "// V2\n");
|
||||
MD_Map empty_map = {0};
|
||||
|
||||
MD_Node *v2 = MD_StringMap_Lookup(&ns_map, MD_S8Lit("v2"))->value;
|
||||
MD_Node *v2 = MD_MapLookup(&ns_map, MD_MapKeyStr(MD_S8Lit("v2")))->val;
|
||||
for(MD_EachNodeRef(node, v2->first_child))
|
||||
{
|
||||
OutputPrefixedType(f, &empty_map, MD_S8Lit(""), node, 0);
|
||||
@@ -258,8 +258,8 @@ int main(int argument_count, char **arguments)
|
||||
MD_Map v2_map = MapFromChildren(v2);
|
||||
for(MD_EachNodeRef(node, v1->first_child))
|
||||
{
|
||||
MD_MapSlot *slot = MD_StringMap_Lookup(&v2_map, node->string);
|
||||
MD_Node *v2_type = slot->value;
|
||||
MD_MapSlot *slot = MD_MapLookup(&v2_map, MD_MapKeyStr(node->string));
|
||||
MD_Node *v2_type = slot->val;
|
||||
MD_Map children_map = MapFromChildren(v2_type);
|
||||
|
||||
fprintf(f, "static %.*s %.*sFromV1(v1_%.*s v)\n{\n",
|
||||
@@ -274,10 +274,10 @@ int main(int argument_count, char **arguments)
|
||||
{
|
||||
fprintf(f, " case v1_%.*s_%.*s: ",
|
||||
MD_StringExpand(node->string), MD_StringExpand(enumerand->string));
|
||||
MD_MapSlot *slot = MD_StringMap_Lookup(&children_map, enumerand->string);
|
||||
MD_MapSlot *slot = MD_MapLookup(&children_map, MD_MapKeyStr(enumerand->string));
|
||||
if(slot)
|
||||
{
|
||||
MD_Node *v2_enumerand = slot->value;
|
||||
MD_Node *v2_enumerand = slot->val;
|
||||
fprintf(f, "result = %.*s_%.*s; break;\n",
|
||||
MD_StringExpand(node->string), MD_StringExpand(v2_enumerand->string));
|
||||
}
|
||||
@@ -305,7 +305,7 @@ int main(int argument_count, char **arguments)
|
||||
{
|
||||
fprintf(f, " if(v & v1_%.*s_%.*s) ",
|
||||
MD_StringExpand(singular_flag_type_name), MD_StringExpand(flag->string));
|
||||
MD_MapSlot *slot = MD_StringMap_Lookup(&children_map, flag->string);
|
||||
MD_MapSlot *slot = MD_MapLookup(&children_map, MD_MapKeyStr(flag->string));
|
||||
if(slot)
|
||||
{
|
||||
fprintf(f, "result |= %.*s_%.*s;\n",
|
||||
@@ -332,10 +332,10 @@ int main(int argument_count, char **arguments)
|
||||
}
|
||||
|
||||
MD_Map v1_children_map = MapFromChildren(node);
|
||||
MD_MapSlot *v1_member_slot = MD_StringMap_Lookup(&v1_children_map, authoritative_member->string);
|
||||
MD_MapSlot *v1_member_slot = MD_MapLookup(&v1_children_map, MD_MapKeyStr(authoritative_member->string));
|
||||
if(v1_member_slot)
|
||||
{
|
||||
AppendConversionCode(f, &v2_map, authoritative_member, v1_member_slot->value, MD_S8Lit(""));
|
||||
AppendConversionCode(f, &v2_map, authoritative_member, v1_member_slot->val, MD_S8Lit(""));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -348,10 +348,10 @@ int main(int argument_count, char **arguments)
|
||||
MD_Map v1_children_map = MapFromChildren(node);
|
||||
for(MD_EachNode(member, v2_type->first_child))
|
||||
{
|
||||
MD_MapSlot *v1_member_slot = MD_StringMap_Lookup(&v1_children_map, member->string);
|
||||
MD_MapSlot *v1_member_slot = MD_MapLookup(&v1_children_map, MD_MapKeyStr(member->string));
|
||||
if(v1_member_slot)
|
||||
{
|
||||
AppendConversionCode(f, &v2_map, member, v1_member_slot->value, MD_S8Lit(""));
|
||||
AppendConversionCode(f, &v2_map, member, v1_member_slot->val, MD_S8Lit(""));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -25,36 +25,6 @@
|
||||
</div>
|
||||
<div class="page_content">
|
||||
<h1 class="title">Blog</h1><input autofocus id="lister_search_0" class="lister_search" oninput="SearchInput(event, 0)" onkeydown="SearchKeyDown(event, 0)" placeholder="Filter..."></input><ul id="lister_0" class="lister">
|
||||
<a class="lister_item_link" href="blog1.html">
|
||||
<li class="lister_item">
|
||||
<div class="lister_item_text">
|
||||
<div class="lister_item_title">
|
||||
Test Blog #1
|
||||
</div>
|
||||
<div class="lister_item_date">
|
||||
30 November 2020
|
||||
</div>
|
||||
<div class="lister_item_desc">
|
||||
This is my test blog.
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
<a class="lister_item_link" href="blog2.html">
|
||||
<li class="lister_item">
|
||||
<div class="lister_item_text">
|
||||
<div class="lister_item_title">
|
||||
Hello, Again!
|
||||
</div>
|
||||
<div class="lister_item_date">
|
||||
28 November 2020
|
||||
</div>
|
||||
<div class="lister_item_desc">
|
||||
This is another test blog.
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ int main(int argument_count, char **arguments)
|
||||
{
|
||||
for(MD_EachNode(index_string, node->first_child))
|
||||
{
|
||||
MD_StringMap_Insert(&index_table, MD_MapCollisionRule_Chain, index_string->string, root);
|
||||
MD_MapInsert(&index_table, MD_MapKeyStr(index_string->string), root);
|
||||
}
|
||||
goto end_index_build;
|
||||
}
|
||||
@@ -515,14 +515,15 @@ GeneratePageContent(MD_Map *index_table, SiteInfo *site_info, PageInfo *page_inf
|
||||
MD_Node *index_string = 0;
|
||||
for(MD_u64 idx = 0; !MD_NodeIsNil(index_string = MD_ChildFromIndex(node, idx)); idx += 1)
|
||||
{
|
||||
for(MD_MapSlot *slot = MD_StringMap_Lookup(index_table, index_string->string);
|
||||
for(MD_MapSlot *slot = MD_MapLookup(index_table, MD_MapKeyStr(index_string->string));
|
||||
slot; slot = slot->next)
|
||||
{
|
||||
if(slot->value)
|
||||
if(slot->val)
|
||||
{
|
||||
PageInfo info = ParsePageInfo((MD_Node *)slot->value);
|
||||
MD_Node *node = slot->val;
|
||||
PageInfo info = ParsePageInfo(node);
|
||||
|
||||
MD_String8 filename = ((MD_Node *)slot->value)->filename;
|
||||
MD_String8 filename = node->filename;
|
||||
MD_String8 filename_no_ext = MD_ChopExtension(MD_SkipFolder(filename));
|
||||
MD_String8 link = MD_PushStringF("%.*s.html", MD_StringExpand(filename_no_ext));
|
||||
MD_String8 name = info.title->string;
|
||||
|
||||
@@ -49,7 +49,7 @@ InsertValueToNamespace(NamespaceNode *ns, MD_String8 string, Value v)
|
||||
{
|
||||
Value *v_store = malloc(sizeof(*v_store));
|
||||
*v_store = v;
|
||||
MD_StringMap_Insert(&ns->symbol_map, MD_MapCollisionRule_Overwrite, string, v_store);
|
||||
MD_MapInsert(&ns->symbol_map, MD_MapKeyStr(string), v_store);
|
||||
}
|
||||
|
||||
static Value
|
||||
@@ -58,10 +58,10 @@ ValueFromString(NamespaceNode *ns, MD_String8 string)
|
||||
Value v = {0};
|
||||
for(NamespaceNode *n = ns; n; n = n->parent)
|
||||
{
|
||||
MD_MapSlot *slot = MD_StringMap_Lookup(&n->symbol_map, string);
|
||||
if(slot && slot->value)
|
||||
MD_MapSlot *slot = MD_MapLookup(&n->symbol_map, MD_MapKeyStr(string));
|
||||
if(slot && slot->val)
|
||||
{
|
||||
v = *(Value *)slot->value;
|
||||
v = *(Value *)slot->val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+17
-30
@@ -382,20 +382,20 @@ struct MD_CodeLoc
|
||||
|
||||
//~ String-To-Ptr and Ptr-To-Ptr tables
|
||||
|
||||
typedef enum MD_MapCollisionRule
|
||||
typedef struct MD_MapKey MD_MapKey;
|
||||
struct MD_MapKey
|
||||
{
|
||||
MD_MapCollisionRule_Chain,
|
||||
MD_MapCollisionRule_Overwrite,
|
||||
}
|
||||
MD_MapCollisionRule;
|
||||
MD_u64 hash;
|
||||
MD_u64 size;
|
||||
void *ptr;
|
||||
};
|
||||
|
||||
typedef struct MD_MapSlot MD_MapSlot;
|
||||
struct MD_MapSlot
|
||||
{
|
||||
MD_MapSlot *next;
|
||||
MD_u64 hash;
|
||||
void *key;
|
||||
void *value;
|
||||
MD_MapKey key;
|
||||
void *val;
|
||||
};
|
||||
|
||||
typedef struct MD_Map MD_Map;
|
||||
@@ -627,7 +627,6 @@ MD_FUNCTION MD_String8List MD_SplitString(MD_String8 string, int split_count, MD
|
||||
MD_FUNCTION MD_String8 MD_JoinStringList(MD_String8List list, MD_String8 separator);
|
||||
MD_FUNCTION MD_i64 MD_I64FromString(MD_String8 string, MD_u32 radix);
|
||||
MD_FUNCTION MD_f64 MD_F64FromString(MD_String8 string);
|
||||
MD_FUNCTION MD_u64 MD_HashString(MD_String8 string);
|
||||
MD_FUNCTION MD_u64 MD_CalculateCStringLength(char *cstr);
|
||||
|
||||
MD_FUNCTION MD_String8 MD_StyledStringFromString(MD_String8 string, MD_WordStyle word_style, MD_String8 separator);
|
||||
@@ -646,30 +645,18 @@ MD_FUNCTION MD_String16 MD_S16FromS8(MD_String8 str);
|
||||
MD_FUNCTION MD_String8 MD_S8FromS32(MD_String32 str);
|
||||
MD_FUNCTION MD_String32 MD_S32FromS8(MD_String8 str);
|
||||
|
||||
//~ Allen's Map Proposoal
|
||||
#if 0
|
||||
MD_FUNCTION void MD_MapInit(MD_Map *map);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapLookupString(MD_Map *map, MD_String8 key);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapLookupPtr(MD_Map *map, void *key);
|
||||
MD_FUNCTION MD_b32 MD_MapInsertString(MD_Map *map, MD_String8 key, void *val);
|
||||
MD_FUNCTION MD_b32 MD_MapInsertPtr(MD_Map *map, void *key, void *val);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapNextString(MD_MapSlot *slot, MD_String8 key);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapNextPtr(MD_MapSlot *slot, void *key);
|
||||
#endif
|
||||
|
||||
|
||||
//~ Map Table Data Structure
|
||||
|
||||
MD_FUNCTION MD_u64 MD_HashString(MD_String8 string);
|
||||
MD_FUNCTION MD_u64 MD_HashPointer(void *p);
|
||||
|
||||
//- String-To-Pointer Table
|
||||
MD_FUNCTION MD_MapSlot * MD_StringMap_Lookup(MD_Map *table, MD_String8 string);
|
||||
MD_FUNCTION MD_b32 MD_StringMap_Insert(MD_Map *table, MD_MapCollisionRule collision_rule, MD_String8 string, void *value);
|
||||
MD_FUNCTION MD_MapSlot * MD_StringMap_Next(MD_MapSlot *slot, MD_String8 key);
|
||||
|
||||
//- Pointer-To-Pointer Table
|
||||
MD_FUNCTION MD_MapSlot *MD_PtrMap_Lookup(MD_Map *map, void *key);
|
||||
MD_FUNCTION MD_b32 MD_PtrMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, void *key, void *value);
|
||||
MD_FUNCTION MD_Map MD_MapMakeBucketCount(MD_u64 bucket_count);
|
||||
MD_FUNCTION MD_Map MD_MapMake(void);
|
||||
MD_FUNCTION MD_MapKey MD_MapKeyStr(MD_String8 string);
|
||||
MD_FUNCTION MD_MapKey MD_MapKeyPtr(void *ptr);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapLookup(MD_Map *map, MD_MapKey key);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapScan(MD_MapSlot *first_slot, MD_MapKey key);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapInsert(MD_Map *map, MD_MapKey key, void *val);
|
||||
MD_FUNCTION MD_MapSlot* MD_MapOverwrite(MD_Map *map, MD_MapKey key, void *val);
|
||||
|
||||
//~ Parsing
|
||||
|
||||
|
||||
+112
-176
@@ -489,17 +489,6 @@ MD_F64FromString(MD_String8 string)
|
||||
return(atof(str));
|
||||
}
|
||||
|
||||
MD_FUNCTION_IMPL MD_u64
|
||||
MD_HashString(MD_String8 string)
|
||||
{
|
||||
MD_u64 result = 5381;
|
||||
for(MD_u64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
MD_FUNCTION_IMPL MD_u64
|
||||
MD_CalculateCStringLength(char *cstr)
|
||||
{
|
||||
@@ -926,14 +915,15 @@ MD_S32FromS8(MD_String8 in)
|
||||
|
||||
//~ Map Table Data Structure
|
||||
|
||||
MD_PRIVATE_FUNCTION_IMPL void
|
||||
_MD_Map_Initialize(MD_Map *map)
|
||||
MD_FUNCTION_IMPL MD_u64
|
||||
MD_HashString(MD_String8 string)
|
||||
{
|
||||
if(map->table_size == 0)
|
||||
MD_u64 result = 5381;
|
||||
for(MD_u64 i = 0; i < string.size; i += 1)
|
||||
{
|
||||
map->table_size = 4096;
|
||||
map->table = MD_PushArray(MD_MapSlot *, map->table_size);
|
||||
result = ((result << 5) + result) + string.str[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// NOTE(mal): Generic 64-bit hash function (https://nullprogram.com/blog/2018/07/31/)
|
||||
@@ -948,169 +938,115 @@ MD_HashPointer(void *p)
|
||||
return h;
|
||||
}
|
||||
|
||||
//- String-To-Pointer Table
|
||||
|
||||
MD_FUNCTION_IMPL MD_MapSlot *
|
||||
MD_StringMap_Lookup(MD_Map *map, MD_String8 string)
|
||||
{
|
||||
_MD_Map_Initialize(map);
|
||||
MD_MapSlot *slot = 0;
|
||||
MD_u64 hash = MD_HashString(string);
|
||||
MD_u64 index = hash % map->table_size;
|
||||
for(MD_MapSlot *candidate = map->table[index]; candidate; candidate = candidate->next)
|
||||
{
|
||||
if(candidate->hash == hash && MD_StringMatch(*((MD_String8 *)candidate->key), string, 0))
|
||||
{
|
||||
slot = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return slot;
|
||||
MD_FUNCTION_IMPL MD_Map
|
||||
MD_MapMakeBucketCount(MD_u64 bucket_count){
|
||||
// TODO(allen): permanent arena? scratch arena? -- would really
|
||||
// make most sense with a parameter
|
||||
MD_Map result = {0};
|
||||
result.table_size = bucket_count;
|
||||
// TODO(allen): push array zero
|
||||
result.table = MD_PushArray(MD_MapSlot*, bucket_count);
|
||||
memset(result.table, 0, sizeof(*result.table)*bucket_count);
|
||||
return(result);
|
||||
}
|
||||
|
||||
MD_FUNCTION_IMPL MD_b32
|
||||
MD_StringMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, MD_String8 string, void *value)
|
||||
{
|
||||
_MD_Map_Initialize(map);
|
||||
|
||||
MD_MapSlot *slot = 0;
|
||||
MD_u64 hash = MD_HashString(string);
|
||||
MD_u64 index = hash % map->table_size;
|
||||
|
||||
for(MD_MapSlot *candidate = map->table[index]; candidate; candidate = candidate->next)
|
||||
{
|
||||
if(candidate->hash == hash && MD_StringMatch(*((MD_String8 *)candidate->key), string, 0))
|
||||
{
|
||||
slot = candidate;
|
||||
break;
|
||||
MD_FUNCTION_IMPL MD_Map
|
||||
MD_MapMake(void){
|
||||
MD_Map result = MD_MapMakeBucketCount(4093);
|
||||
return(result);
|
||||
}
|
||||
|
||||
MD_FUNCTION MD_MapKey
|
||||
MD_MapKeyStr(MD_String8 string){
|
||||
MD_MapKey result = {0};
|
||||
if (string.size != 0){
|
||||
result.hash = MD_HashString(string);
|
||||
result.size = string.size;
|
||||
if (string.size > 0){
|
||||
result.ptr = string.str;
|
||||
}
|
||||
}
|
||||
|
||||
if(slot == 0 || (slot != 0 && collision_rule == MD_MapCollisionRule_Chain))
|
||||
{
|
||||
slot = MD_PushArray(MD_MapSlot, 1);
|
||||
if(slot)
|
||||
{
|
||||
slot->next = 0;
|
||||
if(map->table[index])
|
||||
{
|
||||
for(MD_MapSlot *old_slot = map->table[index]; old_slot; old_slot = old_slot->next)
|
||||
{
|
||||
if(old_slot->next == 0)
|
||||
{
|
||||
old_slot->next = slot;
|
||||
return(result);
|
||||
}
|
||||
|
||||
MD_FUNCTION MD_MapKey
|
||||
MD_MapKeyPtr(void *ptr){
|
||||
MD_MapKey result = {0};
|
||||
if (ptr != 0){
|
||||
result.hash = MD_HashPointer(ptr);
|
||||
result.size = 0;
|
||||
result.ptr = ptr;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MD_FUNCTION_IMPL MD_MapSlot*
|
||||
MD_MapLookup(MD_Map *map, MD_MapKey key){
|
||||
MD_MapSlot *result = 0;
|
||||
if (map->table_size > 0){
|
||||
MD_u64 index = key.hash%map->table_size;
|
||||
result = MD_MapScan(map->table[index], key);
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
MD_FUNCTION_IMPL MD_MapSlot*
|
||||
MD_MapScan(MD_MapSlot *first_slot, MD_MapKey key){
|
||||
MD_MapSlot *result = 0;
|
||||
if (first_slot != 0){
|
||||
MD_b32 ptr_kind = (key.size == 0);
|
||||
MD_String8 key_string = MD_S8((MD_u8*)key.ptr, key.size);
|
||||
for (MD_MapSlot *slot = first_slot;
|
||||
slot != 0;
|
||||
slot = slot->next){
|
||||
if (slot->key.hash == key.hash){
|
||||
if (ptr_kind){
|
||||
if (slot->key.size == 0 && slot->key.ptr == key.ptr){
|
||||
result = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else{
|
||||
MD_String8 slot_string = MD_S8((MD_u8*)slot->key.ptr, slot->key.size);
|
||||
if (MD_StringMatch(slot_string, key_string, 0)){
|
||||
result = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
map->table[index] = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(slot)
|
||||
{
|
||||
slot->value = value;
|
||||
slot->hash = hash;
|
||||
MD_String8 *string_copy = MD_PushArray(MD_String8, 1);
|
||||
*string_copy = MD_PushStringCopy(string);
|
||||
slot->key = string_copy;
|
||||
}
|
||||
|
||||
return !!slot;
|
||||
return(result);
|
||||
}
|
||||
|
||||
MD_FUNCTION_IMPL MD_MapSlot *
|
||||
MD_StringMap_Next(MD_MapSlot *slot, MD_String8 key)
|
||||
{
|
||||
MD_MapSlot *next = 0;
|
||||
if(slot)
|
||||
{
|
||||
for(MD_MapSlot *candidate = slot->next; candidate; candidate = candidate->next)
|
||||
{
|
||||
if(MD_StringMatch(*(MD_String8 *)candidate->key, key, 0))
|
||||
{
|
||||
next = candidate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
MD_FUNCTION_IMPL MD_MapSlot*
|
||||
MD_MapInsert(MD_Map *map, MD_MapKey key, void *val){
|
||||
MD_MapSlot *result = 0;
|
||||
if (map->table_size > 0){
|
||||
MD_u64 index = key.hash%map->table_size;
|
||||
// TODO(allen): again, memory? permanent arena? scratch arena?
|
||||
// should definitely match the table's memory "object"
|
||||
MD_MapSlot *slot = MD_PushArray(MD_MapSlot, 1);
|
||||
// TODO(allen): queue push
|
||||
slot->next = map->table[index];
|
||||
map->table[index] = slot;
|
||||
slot->key = key;
|
||||
slot->val = val;
|
||||
result = slot;
|
||||
}
|
||||
return next;
|
||||
return(result);
|
||||
}
|
||||
|
||||
//- Pointer-To-Pointer Table
|
||||
|
||||
MD_FUNCTION_IMPL MD_MapSlot *
|
||||
MD_PtrMap_Lookup(MD_Map *map, void *key)
|
||||
{
|
||||
_MD_Map_Initialize(map);
|
||||
|
||||
MD_MapSlot *slot = 0;
|
||||
MD_u64 hash = MD_HashPointer(key);
|
||||
MD_u64 index = hash % map->table_size;
|
||||
for(MD_MapSlot *candidate = map->table[index]; candidate; candidate = candidate->next)
|
||||
{
|
||||
if(candidate->hash == hash)
|
||||
{
|
||||
slot = candidate;
|
||||
break;
|
||||
}
|
||||
MD_FUNCTION_IMPL MD_MapSlot*
|
||||
MD_MapOverwrite(MD_Map *map, MD_MapKey key, void *val){
|
||||
MD_MapSlot *result = MD_MapLookup(map, key);
|
||||
if (result != 0){
|
||||
result->val = val;
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
MD_FUNCTION_IMPL MD_b32
|
||||
MD_PtrMap_Insert(MD_Map *map, MD_MapCollisionRule collision_rule, void *key, void *value)
|
||||
{
|
||||
_MD_Map_Initialize(map);
|
||||
|
||||
MD_MapSlot *slot = 0;
|
||||
MD_u64 hash = MD_HashPointer(key);
|
||||
MD_u64 index = hash % map->table_size;
|
||||
|
||||
for(MD_MapSlot *candidate = map->table[index]; candidate; candidate = candidate->next)
|
||||
{
|
||||
if(candidate->hash == hash)
|
||||
{
|
||||
slot = candidate;
|
||||
break;
|
||||
}
|
||||
else{
|
||||
result = MD_MapInsert(map, key, val);
|
||||
}
|
||||
|
||||
if(slot == 0 || (slot != 0 && collision_rule == MD_MapCollisionRule_Chain))
|
||||
{
|
||||
slot = MD_PushArray(MD_MapSlot, 1);
|
||||
if(slot)
|
||||
{
|
||||
slot->next = 0;
|
||||
if(map->table[index])
|
||||
{
|
||||
for(MD_MapSlot *old_slot = map->table[index]; old_slot; old_slot = old_slot->next)
|
||||
{
|
||||
if(old_slot->next == 0)
|
||||
{
|
||||
old_slot->next = slot;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
map->table[index] = slot;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(slot)
|
||||
{
|
||||
slot->value = value;
|
||||
slot->hash = hash;
|
||||
}
|
||||
|
||||
return !!slot;
|
||||
return(result);
|
||||
}
|
||||
|
||||
//~ Parsing
|
||||
@@ -2066,16 +2002,17 @@ MD_ParseWholeString(MD_String8 filename, MD_String8 contents)
|
||||
// NOTE(allen): setup namespace structure
|
||||
MD_Node *namespaces = _MD_MakeNode_Ctx(&ctx, MD_NodeKind_List,
|
||||
MD_S8Lit(""), MD_S8Lit(""), ctx.at);
|
||||
MD_Node *default_namespace = _MD_MakeNode_Ctx(&ctx, MD_NodeKind_List,
|
||||
MD_S8Lit(""), MD_S8Lit(""), ctx.at);
|
||||
MD_PushChild(namespaces, default_namespace);
|
||||
MD_Map namespace_table = MD_MapMake();
|
||||
|
||||
MD_Map namespace_table = {0};
|
||||
MD_StringMap_Insert(&namespace_table, MD_MapCollisionRule_Overwrite, default_namespace->string, default_namespace);
|
||||
// NOTE(allen): setup default namespace
|
||||
MD_Node *default_ns = _MD_MakeNode_Ctx(&ctx, MD_NodeKind_List,
|
||||
MD_S8Lit(""), MD_S8Lit(""), ctx.at);
|
||||
MD_PushChild(namespaces, default_ns);
|
||||
MD_MapInsert(&namespace_table, MD_MapKeyStr(default_ns->string), default_ns);
|
||||
|
||||
// NOTE(allen): setup namespace
|
||||
// NOTE(allen): parse loop
|
||||
MD_NodeFlags next_child_flags = 0;
|
||||
MD_Node *selected_namespace = default_namespace;
|
||||
MD_Node *selected_namespace = default_ns;
|
||||
for(;;)
|
||||
{
|
||||
// TODO(allen): I don't get it... this can only happen once between
|
||||
@@ -2115,20 +2052,19 @@ MD_ParseWholeString(MD_String8 filename, MD_String8 contents)
|
||||
MD_Token token = MD_ZERO_STRUCT;
|
||||
if(MD_Parse_RequireKind(&ctx, MD_TokenKind_Identifier, &token))
|
||||
{
|
||||
MD_MapSlot *existing_namespace_slot = MD_StringMap_Lookup(&namespace_table, token.string);
|
||||
if(existing_namespace_slot == 0)
|
||||
{
|
||||
MD_MapKey ns_key = MD_MapKeyStr(token.string);
|
||||
MD_MapSlot *ns_slot = MD_MapLookup(&namespace_table, ns_key);
|
||||
if (ns_slot == 0){
|
||||
MD_Node *ns = _MD_MakeNode_Ctx(&ctx, MD_NodeKind_List,
|
||||
token.string, token.string, token.outer_string.str);
|
||||
MD_StringMap_Insert(&namespace_table, MD_MapCollisionRule_Overwrite, token.string, ns);
|
||||
existing_namespace_slot = MD_StringMap_Lookup(&namespace_table, token.string);
|
||||
MD_PushChild(namespaces, ns);
|
||||
ns_slot = MD_MapInsert(&namespace_table, ns_key, ns);
|
||||
}
|
||||
selected_namespace = (MD_Node *)existing_namespace_slot->value;
|
||||
selected_namespace = (MD_Node *)ns_slot->val;
|
||||
}
|
||||
else
|
||||
{
|
||||
selected_namespace = default_namespace;
|
||||
selected_namespace = default_ns;
|
||||
}
|
||||
}
|
||||
// NOTE(rjf): Not a valid hash thing
|
||||
|
||||
+18
-18
@@ -82,8 +82,8 @@ static MD_Node * NewChild(MD_Node *parent)
|
||||
|
||||
#define OPTIONAL_TAG "optional"
|
||||
|
||||
#define GET_DEPTH(depth_map, node) ((MD_u64)MD_PtrMap_Lookup(depth_map, node)->value)
|
||||
#define SET_DEPTH(depth_map, node, depth) MD_PtrMap_Insert(depth_map, MD_MapCollisionRule_Overwrite, node, (void *)(depth))
|
||||
#define GET_DEPTH(depth_map, node) ((MD_u64)MD_MapLookup(depth_map, MD_MapKeyPtr(node))->val)
|
||||
#define SET_DEPTH(depth_map, node, depth) MD_MapOverwrite(depth_map, MD_MapKeyPtr(node), (void *)(depth))
|
||||
static void PrintRule(MD_Map *depth_map, MD_Node *rule)
|
||||
{
|
||||
MD_b32 is_literal_char = rule->flags & MD_NodeFlag_CharLiteral;
|
||||
@@ -252,7 +252,7 @@ static void ExpandRule(MD_Node *rule, MD_String8List *out_strings, MD_Node *cur_
|
||||
}
|
||||
else // NOTE(mal): Non-terminal production
|
||||
{
|
||||
MD_Node * production = MD_StringMap_Lookup(globals.production_table, rule_element->string)->value;
|
||||
MD_Node * production = MD_MapLookup(globals.production_table, MD_MapKeyStr(rule_element->string))->val;
|
||||
MD_Assert(production);
|
||||
ExpandProduction(production, out_strings, cur_node, op_flags, depth_map, max_depth, depth+1);
|
||||
}
|
||||
@@ -293,13 +293,13 @@ static MD_Node * FindNonTerminalProduction(MD_Node *node, MD_Map *visited)
|
||||
MD_b32 should_visit = 1;
|
||||
if(!MD_NodeIsNil(node->first_child) && node->string.size)
|
||||
{
|
||||
if(MD_StringMap_Lookup(visited, node->string))
|
||||
if(MD_MapLookup(visited, MD_MapKeyStr(node->string)))
|
||||
{
|
||||
should_visit = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
MD_b32 inserted = MD_StringMap_Insert(visited, MD_MapCollisionRule_Overwrite, node->string, node);
|
||||
void *inserted = MD_MapOverwrite(visited, MD_MapKeyStr(node->string), node);
|
||||
MD_Assert(inserted);
|
||||
}
|
||||
}
|
||||
@@ -313,10 +313,10 @@ static MD_Node * FindNonTerminalProduction(MD_Node *node, MD_Map *visited)
|
||||
}
|
||||
else
|
||||
{
|
||||
MD_MapSlot *slot = MD_StringMap_Lookup(globals.production_table, node->string);
|
||||
MD_MapSlot *slot = MD_MapLookup(globals.production_table, MD_MapKeyStr(node->string));
|
||||
if(slot)
|
||||
{
|
||||
MD_Node *production = slot->value;
|
||||
MD_Node *production = slot->val;
|
||||
result = FindNonTerminalProduction(production, visited);
|
||||
}
|
||||
else
|
||||
@@ -431,7 +431,7 @@ static void ComputeElementDepth(MD_Map *depth_map, MD_Node *re)
|
||||
}
|
||||
else
|
||||
{
|
||||
MD_Node * production = MD_StringMap_Lookup(globals.production_table, re->string)->value;
|
||||
MD_Node * production = MD_MapLookup(globals.production_table, MD_MapKeyStr(re->string))->val;
|
||||
result = GET_DEPTH(depth_map, production)+1;
|
||||
}
|
||||
}
|
||||
@@ -576,29 +576,29 @@ int main(int argument_count, char **arguments)
|
||||
}
|
||||
|
||||
// NOTE(mal): Build production hash table
|
||||
MD_Map production_table_ = {0};
|
||||
MD_Map production_table_ = MD_MapMake();
|
||||
globals.production_table = &production_table_;
|
||||
for(MD_EachNode(production, productions->first_child))
|
||||
{
|
||||
MD_b32 inserted = MD_StringMap_Insert(globals.production_table, MD_MapCollisionRule_Overwrite,
|
||||
production->string, production);
|
||||
void *inserted = MD_MapOverwrite(globals.production_table,
|
||||
MD_MapKeyStr(production->string), production);
|
||||
MD_Assert(inserted);
|
||||
}
|
||||
|
||||
// NOTE(mal): Check for root production
|
||||
MD_Node* file_production = 0;
|
||||
{
|
||||
MD_MapSlot *file_production_slot = MD_StringMap_Lookup(globals.production_table, MD_S8Lit("file"));
|
||||
MD_MapSlot *file_production_slot = MD_MapLookup(globals.production_table, MD_MapKeyStr(MD_S8Lit("file")));
|
||||
if(!file_production_slot)
|
||||
{
|
||||
fprintf(stderr, "Error: Grammar file does not specify \"file\" production\n");
|
||||
goto error;
|
||||
}
|
||||
file_production = file_production_slot->value;
|
||||
file_production = file_production_slot->val;
|
||||
}
|
||||
|
||||
// NOTE(mal): Check that all branches lead to terminal nodes
|
||||
MD_Map visited_productions = {0};
|
||||
MD_Map visited_productions = MD_MapMake();
|
||||
|
||||
for(MD_EachNode(production, productions->first_child))
|
||||
{
|
||||
@@ -613,7 +613,7 @@ int main(int argument_count, char **arguments)
|
||||
// NOTE(mal): Check that all productions are reachable
|
||||
for(MD_EachNode(production, productions->first_child))
|
||||
{
|
||||
MD_MapSlot *slot = MD_StringMap_Lookup(&visited_productions, production->string);
|
||||
MD_MapSlot *slot = MD_MapLookup(&visited_productions, MD_MapKeyStr(production->string));
|
||||
if(!slot)
|
||||
{
|
||||
fprintf(stderr, "Warning: Unreachable production \"%.*s\"\n", MD_StringExpand(production->string));
|
||||
@@ -623,7 +623,7 @@ int main(int argument_count, char **arguments)
|
||||
// NOTE(mal): Compute depth of productions, rules, rule elements
|
||||
|
||||
// NOTE(mal): Init all MD_Node depths to 0
|
||||
MD_Map depth_map_ = {0};
|
||||
MD_Map depth_map_ = MD_MapMake();
|
||||
MD_Map *depth_map = &depth_map_;
|
||||
for(MD_EachNode(production, productions->first_child))
|
||||
{
|
||||
@@ -660,7 +660,7 @@ int main(int argument_count, char **arguments)
|
||||
MD_Assert(MD_NodeIsNil(rule_element->first_child));
|
||||
if(!(rule_element->flags & MD_NodeFlag_CharLiteral))
|
||||
{
|
||||
MD_Node * production = MD_StringMap_Lookup(globals.production_table, rule_element->string)->value;
|
||||
MD_Node * production = MD_MapLookup(globals.production_table, MD_MapKeyStr(rule_element->string))->val;
|
||||
depth = GET_DEPTH(depth_map, production);
|
||||
}
|
||||
depth += 1;
|
||||
@@ -713,7 +713,7 @@ int main(int argument_count, char **arguments)
|
||||
|
||||
RandomSeries random_series = rand_seed(0, 0); // NOTE(mal): Reproduceable
|
||||
globals.random_series = &random_series;
|
||||
MD_Node* file_production_node = MD_StringMap_Lookup(globals.production_table, MD_S8Lit("file"))->value;
|
||||
MD_Node* file_production_node = MD_MapLookup(globals.production_table, MD_MapKeyStr(MD_S8Lit("file")))->val;
|
||||
|
||||
// NOTE(mal): Generate test_count unique tests, sorted by complexity
|
||||
MD_u32 test_count = 1000;
|
||||
|
||||
+20
-37
@@ -500,53 +500,36 @@ int main(void)
|
||||
|
||||
Test("Hash maps")
|
||||
{
|
||||
MD_String8 keys[] =
|
||||
MD_String8 key_strings[] =
|
||||
{
|
||||
MD_S8Lit("\xed\x80\x73\x71\x78\xba\xff\xd6\x87\x83\xcd\x20\x28\xf7\x1c\xc1\x5f\xca\x98\x9c\x5a\xab\x0c\xae\x9a\x60\x57\x03\xeb\x1f\xde\x99"),
|
||||
MD_S8Lit("\x4c\x80\xb7\x8b\xbf\x65\x5a\x4b\xc1\x2a\xc3\x5f\xe1\x66\xfb\x0d\x72\x83\x1c\x63\xba\xb5\x97\x02\x3f\x6a\xe0\x2a\x1b\x82\x07\x76"),
|
||||
MD_S8Lit("\xd8\xfd\x11\x4b\x04\xdf\xe5\x20\x5b\xd6\x4f\x87\x00\x70\x6a\xc8\xde\xed\xc7\x79\xdb\x87\x24\x36\xa8\x7a\x31\x41\x00\x57\xbd\x8d"),
|
||||
};
|
||||
|
||||
// NOTE(mal): True for MD_HashString is djb2
|
||||
{
|
||||
TestResult(MD_HashString(keys[0]) == 1 && MD_HashString(keys[1]) == 1 && MD_HashString(keys[2]) == 3);
|
||||
MD_MapKey keys[MD_ArrayCount(key_strings)*2];
|
||||
for (MD_u64 i = 0; i < MD_ArrayCount(key_strings); i += 1){
|
||||
keys[i] = MD_MapKeyStr(key_strings[i]);
|
||||
}
|
||||
for (MD_u64 i = MD_ArrayCount(key_strings); i < MD_ArrayCount(keys); i += 1){
|
||||
keys[i] = MD_MapKeyPtr((void *)i);
|
||||
}
|
||||
|
||||
{
|
||||
MD_MapCollisionRule rules[] = { MD_MapCollisionRule_Chain, MD_MapCollisionRule_Overwrite };
|
||||
for(int i_rule = 0; i_rule < MD_ArrayCount(rules); ++i_rule)
|
||||
{
|
||||
MD_Map map = {0};
|
||||
MD_StringMap_Insert(&map, rules[i_rule], keys[0], (void *)0);
|
||||
MD_StringMap_Insert(&map, rules[i_rule], keys[1], (void *)1);
|
||||
MD_StringMap_Insert(&map, rules[i_rule], keys[2], (void *)2);
|
||||
|
||||
MD_MapSlot *slot0 = MD_StringMap_Lookup(&map, keys[0]);
|
||||
MD_MapSlot *slot1 = MD_StringMap_Lookup(&map, keys[1]);
|
||||
MD_MapSlot *slot2 = MD_StringMap_Lookup(&map, keys[2]);
|
||||
|
||||
TestResult(slot0 && slot0->value == (void *)0 &&
|
||||
slot1 && slot1->value == (void *)1 &&
|
||||
slot2 && slot2->value == (void *)2);
|
||||
MD_Map map = MD_MapMake();
|
||||
for (MD_u64 i = 0; i < MD_ArrayCount(keys); i += 1){
|
||||
MD_MapInsert(&map, keys[i], (void *)i);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
MD_MapCollisionRule rules[] = { MD_MapCollisionRule_Chain, MD_MapCollisionRule_Overwrite };
|
||||
for(int i_rule = 0; i_rule < MD_ArrayCount(rules); ++i_rule)
|
||||
{
|
||||
MD_Map map = {0};
|
||||
MD_PtrMap_Insert(&map, rules[i_rule], (void *)0, (void *)0);
|
||||
MD_PtrMap_Insert(&map, rules[i_rule], (void *)1, (void *)1);
|
||||
MD_PtrMap_Insert(&map, rules[i_rule], (void *)2, (void *)2);
|
||||
|
||||
MD_MapSlot *slot0 = MD_PtrMap_Lookup(&map, (void *)0);
|
||||
MD_MapSlot *slot1 = MD_PtrMap_Lookup(&map, (void *)1);
|
||||
MD_MapSlot *slot2 = MD_PtrMap_Lookup(&map, (void *)2);
|
||||
|
||||
TestResult(slot0 && slot0->value == (void *) 0 &&
|
||||
slot1 && slot1->value == (void *) 1 &&
|
||||
slot2 && slot2->value == (void *) 2);
|
||||
for (MD_u64 i = 0; i < MD_ArrayCount(keys); i += 1){
|
||||
MD_MapSlot *slot = MD_MapLookup(&map, keys[i]);
|
||||
TestResult(slot && slot->val == (void *)i);
|
||||
}
|
||||
for (MD_u64 i = 0; i < MD_ArrayCount(keys); i += 1){
|
||||
MD_MapOverwrite(&map, keys[i], (void *)(i + 10));
|
||||
}
|
||||
for (MD_u64 i = 0; i < MD_ArrayCount(keys); i += 1){
|
||||
MD_MapSlot *slot = MD_MapLookup(&map, keys[i]);
|
||||
TestResult(slot && slot->val == (void *)(i + 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user