Compare commits
2 Commits
823223ffa7
...
b443367f46
| Author | SHA1 | Date | |
|---|---|---|---|
| b443367f46 | |||
| fd9e5dda78 |
@ -1,20 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../std.h"
|
#include "../std.h"
|
||||||
|
|
||||||
|
#define Array_construct(T, DATA, LEN) ((Array_##T){ .data = DATA, .len = LEN })
|
||||||
|
|
||||||
|
/// creates Array_##T from a const array
|
||||||
|
#define ARRAY(T, A...) Array_construct(T, ((u32[])A), ARRAY_SIZE(((u32[])A)))
|
||||||
|
|
||||||
#define Array_declare(T)\
|
#define Array_declare(T)\
|
||||||
typedef struct Array_##T {\
|
typedef struct Array_##T {\
|
||||||
T* data;\
|
T* data;\
|
||||||
u32 len;\
|
u32 len;\
|
||||||
} Array_##T;\
|
} Array_##T;\
|
||||||
\
|
\
|
||||||
static inline Array_##T Array_##T##_construct(T* data_ptr, u32 len) {\
|
|
||||||
return (Array_##T){ .data = data_ptr, .len = len };\
|
|
||||||
}\
|
|
||||||
\
|
|
||||||
static inline Array_##T Array_##T##_alloc(u32 len){\
|
static inline Array_##T Array_##T##_alloc(u32 len){\
|
||||||
return Array_##T##_construct((T*)malloc(len * sizeof(T)), len);\
|
return Array_construct(T, (T*)malloc(len * sizeof(T)), len);\
|
||||||
}\
|
}\
|
||||||
static inline void Array_##T##_realloc(Array_##T* ptr, u32 new_len){\
|
static inline void Array_##T##_realloc(Array_##T* ptr, u32 new_len){\
|
||||||
ptr->data = (T*)realloc(ptr->data, new_len * sizeof(T));\
|
ptr->data = (T*)realloc(ptr->data, new_len * sizeof(T));\
|
||||||
ptr->len = new_len;\
|
ptr->len = new_len;\
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Array_declare(u8)
|
||||||
|
Array_declare(u32)
|
||||||
|
|||||||
139
src/collections/HashMap.h
Normal file
139
src/collections/HashMap.h
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../std.h"
|
||||||
|
#include "../string/str.h"
|
||||||
|
#include "Array.h"
|
||||||
|
|
||||||
|
//TODO: sorting of bucket and binary search
|
||||||
|
//TODO: delayed deletion
|
||||||
|
|
||||||
|
#define __HashMap_HASH_FUNC str_hash32
|
||||||
|
#define __HashMapBucket_MAX_LEN 16
|
||||||
|
|
||||||
|
#define HashMap_DESTROY_VALUE_FUNC_NULL ((void (*)(void*))NULL)
|
||||||
|
|
||||||
|
/// call this in a header file
|
||||||
|
///@param T Value type
|
||||||
|
#define HashMap_declare(T)\
|
||||||
|
typedef struct KeyValue_##T {\
|
||||||
|
str key;\
|
||||||
|
T value;\
|
||||||
|
u32 hash;\
|
||||||
|
} KeyValue_##T;\
|
||||||
|
\
|
||||||
|
List_declare(KeyValue_##T);\
|
||||||
|
\
|
||||||
|
typedef struct HashMapBucket_##T {\
|
||||||
|
List_KeyValue_##T kvs;\
|
||||||
|
} HashMapBucket_##T;\
|
||||||
|
\
|
||||||
|
typedef struct HashMap_##T {\
|
||||||
|
HashMapBucket_##T* table;\
|
||||||
|
u32 height;\
|
||||||
|
u16 height_n;\
|
||||||
|
} HashMap_##T;\
|
||||||
|
\
|
||||||
|
void HashMap_##T##_alloc(HashMap_##T* ptr);\
|
||||||
|
void HashMap_##T##_free(HashMap_##T* ptr);\
|
||||||
|
NULLABLE(T*) HashMap_##T##_tryGetPtr(HashMap_##T* ptr, str key);\
|
||||||
|
bool HashMap_##T##_tryPush(HashMap_##T* ptr, str key, T value);\
|
||||||
|
bool HashMap_##T##_tryDelete(HashMap_##T* ptr, str key);\
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// call this in a source code file
|
||||||
|
///@param T Value type
|
||||||
|
///@param DESTROY_VALUE_FUNC `void foo (T*)` or HashMap_DESTROY_VALUE_FUNC_NULL
|
||||||
|
#define HashMap_define(T, DESTROY_VALUE_FUNC)\
|
||||||
|
List_define(KeyValue_##T);\
|
||||||
|
\
|
||||||
|
static const Array_u32 __HashMap_##T##_heights = ARRAY(u32, {\
|
||||||
|
17, 31, 61, 127, 257, 521, 1021, 2053, 4099, 8191, 16381, 32771,\
|
||||||
|
65521, 131071, 262147, 524287, 1048583, 2097169, 4194319,\
|
||||||
|
8388617, 16777213, 33554467, 67108859, 134217757, 268435493\
|
||||||
|
});\
|
||||||
|
\
|
||||||
|
void HashMap_##T##_alloc(HashMap_##T* ptr){\
|
||||||
|
ptr->height_n = 0;\
|
||||||
|
ptr->height = __HashMap_##T##_heights.data[0];\
|
||||||
|
ptr->table = (HashMapBucket_##T*)malloc(ptr->height * sizeof(HashMapBucket_##T));\
|
||||||
|
memset(ptr->table, 0, ptr->height * sizeof(HashMapBucket_##T));\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
void HashMap_##T##_free(HashMap_##T* ptr){\
|
||||||
|
for(u32 i = 0; i < ptr->height; i++){\
|
||||||
|
for(u32 j = 0; j < ptr->table[i].kvs.len; j++){\
|
||||||
|
KeyValue_##T* kv_ptr = &ptr->table[i].kvs.data[j];\
|
||||||
|
if(DESTROY_VALUE_FUNC){\
|
||||||
|
DESTROY_VALUE_FUNC(&kv_ptr->value);\
|
||||||
|
}\
|
||||||
|
free(kv_ptr->key.data);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
free(ptr->table[i].kvs.data);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
free(ptr->table);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
NULLABLE(T*) HashMap_##T##_tryGetPtr(HashMap_##T* ptr, str key){\
|
||||||
|
u32 hash = __HashMap_HASH_FUNC(key);\
|
||||||
|
HashMapBucket_##T* bu = &ptr->table[hash % ptr->height];\
|
||||||
|
for(u32 i = 0; i < bu->kvs.len; i++){\
|
||||||
|
if(bu->kvs.data[i].hash == hash && str_equals(bu->kvs.data[i].key, key)){\
|
||||||
|
return &bu->kvs.data[i].value;\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
return NULL;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
bool HashMap_##T##_tryPush(HashMap_##T* ptr, str key, T value){\
|
||||||
|
u32 hash = __HashMap_HASH_FUNC(key);\
|
||||||
|
HashMapBucket_##T* bu = &ptr->table[hash % ptr->height];\
|
||||||
|
for(u32 i = 0; i < bu->kvs.len; i++){\
|
||||||
|
if(bu->kvs.data[i].hash == hash && str_equals(bu->kvs.data[i].key, key)){\
|
||||||
|
return false;\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
if(bu->kvs.len >= __HashMapBucket_MAX_LEN){\
|
||||||
|
u32 height_expanded_n = ptr->height_n + 1;\
|
||||||
|
if(height_expanded_n >= __HashMap_u32_heights.len){\
|
||||||
|
printf("ERROR: HashMap_" #T " IS FULL\n");\
|
||||||
|
return false;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
u32 height_expanded = __HashMap_##T##_heights.data[height_expanded_n];\
|
||||||
|
HashMapBucket_##T* table_expanded = (HashMapBucket_##T*)malloc(height_expanded * sizeof(HashMapBucket_##T));\
|
||||||
|
memset(table_expanded, 0, height_expanded * sizeof(HashMapBucket_##T));\
|
||||||
|
for(u32 i = 0; i < height_expanded; i++){\
|
||||||
|
for(u32 j = 0; j < ptr->table[i].kvs.len; j++){\
|
||||||
|
KeyValue_##T kv = ptr->table[i].kvs.data[j];\
|
||||||
|
List_KeyValue_##T##_push(&table_expanded[kv.hash % height_expanded].kvs, kv);\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
free(ptr->table[i].kvs.data);\
|
||||||
|
}\
|
||||||
|
free(ptr->table);\
|
||||||
|
ptr->table = table_expanded;\
|
||||||
|
ptr->height = height_expanded;\
|
||||||
|
ptr->height_n = height_expanded_n;\
|
||||||
|
bu = &ptr->table[hash % ptr->height];\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
KeyValue_##T kv = { .key = str_copy(key), .value = value, .hash = hash };\
|
||||||
|
List_KeyValue_##T##_push(&bu->kvs, kv);\
|
||||||
|
return true;\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
bool HashMap_##T##_tryDelete(HashMap_##T* ptr, str key){\
|
||||||
|
u32 hash = __HashMap_HASH_FUNC(key);\
|
||||||
|
HashMapBucket_##T* bu = &ptr->table[hash % ptr->height];\
|
||||||
|
for(u32 i = 0; i < bu->kvs.len; i++){\
|
||||||
|
if(bu->kvs.data[i].hash == hash && str_equals(bu->kvs.data[i].key, key)){\
|
||||||
|
return List_KeyValue_##T##_tryRemoveAt(&bu->kvs, i);\
|
||||||
|
}\
|
||||||
|
}\
|
||||||
|
\
|
||||||
|
return false;\
|
||||||
|
}
|
||||||
@ -20,6 +20,7 @@
|
|||||||
T* List_##T##_expand(List_##T* ptr, u32 count);\
|
T* List_##T##_expand(List_##T* ptr, u32 count);\
|
||||||
void List_##T##_push(List_##T* ptr, T value);\
|
void List_##T##_push(List_##T* ptr, T value);\
|
||||||
void List_##T##_pushMany(List_##T* ptr, T* values, u32 count);\
|
void List_##T##_pushMany(List_##T* ptr, T* values, u32 count);\
|
||||||
|
bool List_##T##_tryRemoveAt(List_##T* ptr, u32 i);\
|
||||||
|
|
||||||
|
|
||||||
#define List_define(T)\
|
#define List_define(T)\
|
||||||
@ -52,6 +53,17 @@
|
|||||||
T* empty_cell_ptr = List_##T##_expand(ptr, count);\
|
T* empty_cell_ptr = List_##T##_expand(ptr, count);\
|
||||||
memcpy(empty_cell_ptr, values, count * sizeof(T));\
|
memcpy(empty_cell_ptr, values, count * sizeof(T));\
|
||||||
}\
|
}\
|
||||||
|
\
|
||||||
|
bool List_##T##_tryRemoveAt(List_##T* ptr, u32 i){\
|
||||||
|
if(ptr->len == 0 || i >= ptr->len)\
|
||||||
|
return false;\
|
||||||
|
\
|
||||||
|
ptr->len--;\
|
||||||
|
for(; i < ptr->len; i++){\
|
||||||
|
ptr->data[i] = ptr->data[i + 1];\
|
||||||
|
}\
|
||||||
|
return true;\
|
||||||
|
}\
|
||||||
|
|
||||||
|
|
||||||
List_declare(u32);
|
List_declare(u32);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ typedef u8 bool;
|
|||||||
|
|
||||||
typedef const char* cstr;
|
typedef const char* cstr;
|
||||||
|
|
||||||
#define ARRAY_SIZE(A) sizeof(A)/sizeof(A[0])
|
#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0]))
|
||||||
#define ALIGN_TO(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1))
|
#define ALIGN_TO(_SIZE,_ALIGN) (((_SIZE) + ((_ALIGN) - 1)) & ~((_ALIGN) - 1))
|
||||||
|
|
||||||
#define __count_args( \
|
#define __count_args( \
|
||||||
|
|||||||
@ -97,3 +97,12 @@ bool str_endsWith(str src, str fragment){
|
|||||||
src.len = fragment.len;
|
src.len = fragment.len;
|
||||||
return str_equals(src, fragment);
|
return str_equals(src, fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 str_hash32(str s){
|
||||||
|
u8* ubuf = (u8*)s.data;
|
||||||
|
u32 len = s.len;
|
||||||
|
u32 hash=0;
|
||||||
|
for (u32 i = 0; i < len; i++)
|
||||||
|
hash = (hash<<6) + (hash<<16) - hash + ubuf[i];
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ typedef struct str {
|
|||||||
bool isZeroTerminated;
|
bool isZeroTerminated;
|
||||||
} str;
|
} str;
|
||||||
|
|
||||||
// creates str from a string literal
|
/// creates str from a string literal
|
||||||
#define STR(LITERAL) str_construct(LITERAL, ARRAY_SIZE(LITERAL) - 1, true)
|
#define STR(LITERAL) str_construct(LITERAL, ARRAY_SIZE(LITERAL) - 1, true)
|
||||||
|
|
||||||
#define str_construct(DATA, LEN, ZERO_TERMINATED) ((str){ .data = DATA, .len = LEN, .isZeroTerminated = ZERO_TERMINATED })
|
#define str_construct(DATA, LEN, ZERO_TERMINATED) ((str){ .data = DATA, .len = LEN, .isZeroTerminated = ZERO_TERMINATED })
|
||||||
@ -32,3 +32,7 @@ i32 str_seekCharReverse(str src, char c, u32 startIndex);
|
|||||||
|
|
||||||
bool str_startsWith(str src, str fragment);
|
bool str_startsWith(str src, str fragment);
|
||||||
bool str_endsWith(str src, str fragment);
|
bool str_endsWith(str src, str fragment);
|
||||||
|
|
||||||
|
/// @brief calculates string hash using sdbm32 algorythm (something like lightweight crc32)
|
||||||
|
/// @return non-cryptografic hash of the string
|
||||||
|
u32 str_hash32(str s);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user