feat: implemented dictionary type
This commit is contained in:
parent
6f2947bcab
commit
c2423f146a
100
core/src/dictionary.c
Normal file
100
core/src/dictionary.c
Normal file
|
@ -0,0 +1,100 @@
|
|||
#include "dictionary.h"
|
||||
#include "strutil.h"
|
||||
#include "string.h"
|
||||
#include "math.h"
|
||||
|
||||
typedef struct Key {
|
||||
char* key;
|
||||
uintptr_t hash;
|
||||
} Key;
|
||||
|
||||
Dictionary dictionary_new(size_t element_size) {
|
||||
return (Dictionary) {
|
||||
.element_size = element_size,
|
||||
.list = list_init(sizeof(Key) + element_size)
|
||||
};
|
||||
}
|
||||
|
||||
Key* internal_dictionary_get(Dictionary* self, uintptr_t keyhash, size_t* out_index) {
|
||||
if(self->list.len == 0) {
|
||||
*out_index = 0;
|
||||
return NULL;
|
||||
}
|
||||
Key* element;
|
||||
signed long l = 0, r = self->list.len, m;
|
||||
while(l <= r) {
|
||||
m = round((double)(l+r)/2.0);
|
||||
if(out_index != NULL) *out_index = m;
|
||||
element = list_at_unchecked(&self->list, m);
|
||||
if(keyhash < element->hash)
|
||||
r = m-1;
|
||||
else if(keyhash > element->hash)
|
||||
l = m+1;
|
||||
else
|
||||
return element;
|
||||
}
|
||||
m = m >= 0 ? (m < self->list.len ? m : self->list.len - 1) : 0;
|
||||
return list_at_as(Key, &self->list, m);
|
||||
}
|
||||
|
||||
void* dictionary_get(Dictionary* self, const char* key) {
|
||||
uintptr_t hash = strhash(key);
|
||||
Key* keyblock = internal_dictionary_get(self, hash, NULL);
|
||||
return strcmp(key, keyblock->key) != 0 ? NULL : ((char*)keyblock) + sizeof(Key);
|
||||
}
|
||||
|
||||
static inline
|
||||
int dictionary_insert_kvp(Dictionary* self, Key key, void* value, size_t index) {
|
||||
// allocate a block of memory to insert into the list
|
||||
char* insert_data = malloc(self->list.element_size);
|
||||
if(insert_data == NULL)
|
||||
return -1; // OOM
|
||||
// fill block with key and value
|
||||
memcpy(insert_data, &key, sizeof(Key));
|
||||
memcpy(insert_data + sizeof(Key), value, self->element_size);
|
||||
// decide add or insert based on current length of list
|
||||
if(self->list.len == 0)
|
||||
list_add(&self->list, insert_data);
|
||||
else
|
||||
list_insert(&self->list, insert_data, index);
|
||||
// free allocated key-value block
|
||||
free(insert_data);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dictionary_set_raw(Dictionary* self, const char* key, void* data) {
|
||||
const uintptr_t keyhash = strhash(key);
|
||||
size_t closest_index;
|
||||
Key* closest = internal_dictionary_get(self, keyhash, &closest_index);
|
||||
// get index of closest hash
|
||||
// prepare key data
|
||||
Key keydata = {
|
||||
.hash = strhash(key),
|
||||
.key = malloc(strlen(key)+1)
|
||||
};
|
||||
strcpy(keydata.key, key);
|
||||
if(closest == NULL || keyhash < closest->hash) { // insert before
|
||||
return dictionary_insert_kvp(self, keydata, data, closest_index);
|
||||
} else if(strcmp(closest->key, key) == 0) {
|
||||
memcpy(closest + 1, data, self->element_size);
|
||||
return 0;
|
||||
} else {
|
||||
return dictionary_insert_kvp(self, keydata, data, closest_index + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int dictionary_erase(Dictionary* self, const char* key) {
|
||||
const uintptr_t keyhash = strhash(key);
|
||||
size_t index;
|
||||
Key* element = internal_dictionary_get(self, keyhash, &index);
|
||||
if(element->hash != keyhash || strcmp(key, element->key) != 0)
|
||||
return -1; // not a match
|
||||
// free the key string
|
||||
free(element->key);
|
||||
list_erase(&self->list, index);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void dictionary_empty(Dictionary* self) {
|
||||
list_empty(&self->list);
|
||||
}
|
36
core/src/dictionary.h
Normal file
36
core/src/dictionary.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#ifndef _fencer_hash_map_h
|
||||
#define _fencer_hash_map_h
|
||||
|
||||
#include "list.h"
|
||||
#include "stdint.h"
|
||||
|
||||
typedef struct Dictionary {
|
||||
List list;
|
||||
size_t element_size;
|
||||
} Dictionary;
|
||||
|
||||
extern Dictionary dictionary_new(size_t element_size);
|
||||
extern void* dictionary_get(Dictionary* self, const char* key);
|
||||
extern int dictionary_set_raw(Dictionary* self, const char* key, void* data);
|
||||
extern int dictionary_erase(Dictionary* self, const char* key);
|
||||
extern void dictionary_empty(Dictionary* self);
|
||||
|
||||
static inline int dictionary_set_int(Dictionary* self, const char* key, int data) {
|
||||
return dictionary_set_raw(self, key, &data);
|
||||
}
|
||||
static inline int dictionary_set_unintptr(Dictionary* self, const char* key, uintptr_t data) {
|
||||
return dictionary_set_raw(self, key, &data);
|
||||
}
|
||||
#define dictionary_set_value(Type_, Dict_, Key_, Value_)\
|
||||
{ Type_ __value = (Type_)Value_; dictionary_set_raw(Dict_, Key_, &__value); }
|
||||
#define dictionary_check_size(Type_, Dict_)\
|
||||
(Dict_)->element_size == sizeof(Type_)
|
||||
|
||||
#define dictionary_from_type(Type_)\
|
||||
dictionary_new(sizeof(Type_))
|
||||
#define dictionary_get_as(Type_, Dict_, Key_)\
|
||||
(Type_*)dictionary_get(Dict_, Key_)
|
||||
#define dictionary_get_value(Type_, Dict_, Key_)\
|
||||
*((Type_*)dictionary_get(Dict_, Key_))
|
||||
|
||||
#endif // !_fencer_hash_map_h
|
|
@ -64,7 +64,6 @@ void list_reserve(List* self, size_t at_least) {
|
|||
self->cap = new_cap;
|
||||
}
|
||||
|
||||
static inline
|
||||
void* list_at_unchecked(List* self, size_t at) {
|
||||
union {
|
||||
uint8_t* as_byte;
|
||||
|
|
|
@ -18,6 +18,7 @@ extern void list_empty(List* list);
|
|||
|
||||
extern void list_reserve(List* self, size_t at_least);
|
||||
extern void* list_at(List* list, size_t at);
|
||||
extern void* list_at_unchecked(List* self, size_t at);
|
||||
|
||||
extern size_t list_add(List* self, void* item);
|
||||
extern void list_insert(List* self, void* item, size_t at);
|
||||
|
|
Loading…
Reference in a new issue