diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/container.h | 144 | ||||
-rw-r--r-- | include/hashset.h | 0 |
2 files changed, 113 insertions, 31 deletions
diff --git a/include/container.h b/include/container.h index 3370be3..78090af 100644 --- a/include/container.h +++ b/include/container.h @@ -41,7 +41,6 @@ typedef unsigned char byte; /// define TODO macro #define TODO (void)(*(volatile char*)0) - /// typedefs for array qsort typedef int(*qsort_cmp_t)(const void*, const void*); #define get_qsort_cmp(type) __qsort_cmps[sizeof(type)] @@ -225,7 +224,12 @@ void ll_remove_back(struct linked_list* list); /// Removes element at index i. if there is no such index, does nothing. /// O(n) char ll_remove_at(struct linked_list *list, size_t i); +/// removes first occurrence of element `elem` from list. +void ll_remove_elem(struct linked_list* list, const void* elem, qsort_cmp_t cmp); /// Removes ALL occurrences of element "elem" in a list +/// WARNING: SOMETHING IS WRONG WITH THIS FUNCTION AND IT SHOULD NOT BE USED EVER +/// UNLESS I FIX IT +/// FOR NOW I WILL ADD TODO MARK THERE /// O(n) void ll_remove_all(struct linked_list* list, const void* elem, qsort_cmp_t cmp); /// splits a linked list into two, the second one starting from element at index `i`. @@ -273,10 +277,14 @@ struct linked_list ll_deep_copy(const struct linked_list* list, memcpy_t cpy); /* ------------------------HASH MAP HEADER-------------------------- */ /* ----------------------------------------------------------------- */ -#define HMAP_BUCKET_MAX_SIZE 8 -#define HMAP_DEFAULT_BUCKETS 32 -/// should return `0` only if first argument is not equal to second, -/// otherwise should return `1` or any other positive integer +#ifndef HMAP_MAX_BUCKET_SIZE + #define HMAP_MAX_BUCKET_SIZE 8 +#endif +#ifndef HMAP_INIT_SIZE + #define HMAP_INIT_SIZE 32 +#endif +/// should return `0` only if first argument is equal to second, +/// otherwise should return `1` or any other integer /// OPERATES ON `struct hmap_pair*` !!!!!!!!!! NOT ON KEYS! typedef int(*hmap_equal_fn)(const void*, const void*); typedef size_t(*hmap_hash_fn)(const void*); @@ -295,24 +303,34 @@ enum hmapi_cmp_res { hmap_lt = -1, hmap_eq = 0, hmap_gt = 1, - hmap_no = 0x80000000, + hmap_no = 0xB19A55, }; struct hash_map_iter { const struct hash_map* map; size_t bucket_pos; struct linked_list_node* current_node; }; +typedef struct hash_map_iter hmap_iter; struct hash_map hmap_create(const size_t key_size, const size_t val_size, hmap_equal_fn eq, hmap_hash_fn hash); -struct hash_map hmap_create_from_buffer(size_t key_size, size_t val_size, hmap_equal_fn eq, hmap_hash_fn hash, struct hmap_pair* buf, size_t buf_len); +/// copies data from pointers +struct hash_map hmap_create_from_buffer(size_t key_size, size_t val_size, hmap_equal_fn eq, hmap_hash_fn hash, const struct hmap_pair* buf, size_t buf_len); void hmap_free(struct hash_map* map); -void hmap_insert(struct hash_map* map, struct hmap_pair element); +/// copy the contents of the pair into hash map (using `memcpy`). +/// The element is left unchanged, the memory pointed to by `element` may be anything, from stack to FFI allocator +void hmap_insert_copy(struct hash_map* map, const struct hmap_pair element); +/// returns 1 if an object was inserted, 0 if it was not. This is done to be able to free uninserted pointer. +char hmap_insert_mallocated(struct hash_map* map, struct hmap_pair element); /// pair is a pointer #define hmap_insert_pair(map, pair) hmap_insert_range(map, pair, 1); -void hmap_insert_range(struct hash_map* map, struct hmap_pair* elements, size_t elements_len); +/// copies data from pointers +void hmap_insert_range(struct hash_map* map, const struct hmap_pair* elements, size_t elements_len); void* hmap_get(struct hash_map* map, void* key); +/// returns 1 if value was updates successfully, otherwise 0 (if key does not exist) +char hmap_update(struct hash_map* map, void* key, void* new_val); void hmap_remove(struct hash_map* map, void* key); /// double the size of a hash map void hmap_rehash(struct hash_map* map); +void hmap_rehash_to_size(struct hash_map* map, size_t new_size); /// initialize iterator `iter`. void hmapi_begin(const struct hash_map* map, struct hash_map_iter* iter); @@ -369,7 +387,7 @@ void *_insert_to_index_dynarray(void *const dynarray, const void *const element, // uncomment in dev mode so that LSP highlights the code -#define CONTAINER_IMPLEMENTATION +/*#define CONTAINER_IMPLEMENTATION*/ #ifdef CONTAINER_IMPLEMENTATION /* ----------------------------------------------------------------- */ @@ -647,7 +665,8 @@ void ll_truncate(struct linked_list* list, const size_t i) { struct linked_list_node *start = ll_at(list, i-1); if (start == NULL) return; struct linked_list freeable = { - .meta = {list->meta.element_size, list->meta.assumed_size - i}, + .meta = {list->meta.element_size, list->meta.assumed_size - i, .free_function = list->meta.free_function, +}, .first = start->next, }; ll_free(&freeable); @@ -786,8 +805,33 @@ char ll_remove_at(struct linked_list *list, size_t i) { --list->meta.assumed_size; return 1; } +void ll_remove_elem(struct linked_list* list, const void* elem, qsort_cmp_t cmp) { + if (list->first == NULL) return; + if (cmp(list->first->data, elem) == 0) { + ll_remove_front(list); + return; + } + struct linked_list_node *fst = list->first, + *snd = fst->next; + while (snd != NULL) { + if (cmp(snd->data, elem) == 0) { + fst->next = ll_free_node(list, snd); + return; + } + } + if (cmp(fst->data, elem) == 0) ll_remove_back(list); +} void ll_remove_all(struct linked_list* list, const void* elem, qsort_cmp_t cmp) { - while (cmp(list->first->data, elem) == 0) ll_remove_front(list); + printf("DON'T USE THIS FUNCTION!!!!!\n"); + TODO; + __builtin_unreachable(); + + if (list->first == NULL) return; + while (1) { + if (list->first == NULL) return; + if (cmp(list->first->data, elem) == 0) ll_remove_front(list); + else break; + } struct linked_list_node *prev = list->first, *current; for (current = prev->next; current != NULL; current = prev->next) { @@ -903,11 +947,11 @@ void __hmap_ll_custom_free(void* data) { struct hmap_pair *pair = data; free(pair->key); free(pair->val); - free(pair); + free(data); } struct hash_map hmap_create(const size_t key_size, const size_t val_size, hmap_equal_fn eq, hmap_hash_fn hash) { struct hash_map ret = { - .buckets = array_new(struct linked_list, HMAP_DEFAULT_BUCKETS), + .buckets = array_new(struct linked_list, HMAP_INIT_SIZE), .key_size = key_size, .val_size = val_size, .eq = eq, @@ -915,19 +959,20 @@ struct hash_map hmap_create(const size_t key_size, const size_t val_size, hmap_e }; const struct linked_list def = { .meta = { - .element_size = key_size+val_size, + .element_size = sizeof(struct hmap_pair), .assumed_size = 0, .free_function = __hmap_ll_custom_free, }, .first = NULL, .last = NULL, }; - for (size_t i = 0; i < HMAP_DEFAULT_BUCKETS; ++i) ret.buckets[i] = def; + for (size_t i = 0; i < HMAP_INIT_SIZE; ++i) ret.buckets[i] = def; return ret; } -struct hash_map hmap_create_from_buffer(size_t key_size, size_t val_size, hmap_equal_fn eq, hmap_hash_fn hash, struct hmap_pair* buf, size_t buf_len) { +struct hash_map hmap_create_from_buffer(size_t key_size, size_t val_size, hmap_equal_fn eq, hmap_hash_fn hash, const struct hmap_pair* buf, size_t buf_len) { struct hash_map ret = hmap_create(key_size, val_size, eq, hash); - for (size_t i = 0; i < buf_len; ++i) ll_append(ret.buckets + (ret.hash(buf[i].key) % array_size(ret.buckets)), buf + i); + hmap_rehash_to_size(&ret, buf_len / HMAP_MAX_BUCKET_SIZE); + for (size_t i = 0; i < buf_len; ++i) hmap_insert_copy(&ret, buf[i]); return ret; } void hmap_free(struct hash_map* map) { @@ -935,42 +980,79 @@ void hmap_free(struct hash_map* map) { array_free(map->buckets); memset(map, 0, sizeof(*map)); } -void hmap_insert(struct hash_map* map, struct hmap_pair element) { +void hmap_insert_copy(struct hash_map* map, const struct hmap_pair element) { size_t index = map->hash(element.key) % array_size(map->buckets); + if (ll_search(map->buckets + index, &element, map->eq)) { + struct hmap_pair* target = ll_find(map->buckets + index, &element, map->eq)->data; + memcpy(target->val, element.val, map->val_size); + return; + } + struct hmap_pair copy = {malloc(map->key_size), malloc(map->val_size)}; + memcpy(copy.key, element.key, map->key_size); + memcpy(copy.val, element.val, map->val_size); + ll_append(map->buckets + index, ©); + if (map->buckets[index].meta.assumed_size > HMAP_MAX_BUCKET_SIZE) hmap_rehash(map); +} +char hmap_insert_mallocated(struct hash_map* map, struct hmap_pair element) { + size_t index = map->hash(element.key) % array_size(map->buckets); + if (ll_search(map->buckets + index, &element, map->eq)) { + struct hmap_pair* target = ll_find(map->buckets + index, &element, map->eq)->data; + free(target->val); + target->val = element.val; + free(element.key); + return 0; + } ll_append(map->buckets + index, &element); - if (map->buckets[index].meta.assumed_size > HMAP_BUCKET_MAX_SIZE) hmap_rehash(map); + if (map->buckets[index].meta.assumed_size > HMAP_MAX_BUCKET_SIZE) hmap_rehash(map); + return 1; } -/// pair is a pointer -void hmap_insert_range(struct hash_map* map, struct hmap_pair* elements, size_t elements_len) { - for (size_t i = 0; i < elements_len; ++i) hmap_insert(map, elements[i]); +void hmap_insert_range(struct hash_map* map, const struct hmap_pair* elements, size_t elements_len) { + for (size_t i = 0; i < elements_len; ++i) hmap_insert_copy(map, elements[i]); } void* hmap_get(struct hash_map* map, void* key) { size_t index = map->hash(key) % array_size(map->buckets); struct linked_list* target_list = map->buckets + index; - struct linked_list_node* node = ll_find(target_list, key, map->eq); - if (node == NULL) { return NULL; } + struct hmap_pair pr = {.key = key, .val = NULL }; + struct linked_list_node* node = ll_find(target_list, &pr, map->eq); + if (node == NULL) return NULL; struct hmap_pair *pair = node->data; return pair->val; } +char hmap_update(struct hash_map* map, void* key, void* new_val) { + size_t index = map->hash(key) % array_size(map->buckets); + struct linked_list* target_list = map->buckets + index; + struct hmap_pair pr = {.key = key, .val = NULL }; + struct linked_list_node* node = ll_find(target_list, &pr, map->eq); + if (node == NULL) return 0; + memcpy(((struct hmap_pair*)node->data)->val, new_val, map->val_size); + return 1; +} void hmap_remove(struct hash_map* map, void* key) { size_t index = map->hash(key) % array_size(map->buckets); struct linked_list* target_list = map->buckets + index; struct hmap_pair tmppr = {.key = key, .val = NULL}; - ll_remove_all(target_list, &tmppr, map->eq); + ll_remove_elem(target_list, &tmppr, map->eq); } -/// double the size of a hash map void hmap_rehash(struct hash_map* map) { - size_t new_size = array_size(map->buckets) * 2; + hmap_rehash_to_size(map, array_size(map->buckets) << 1); +} +/// double the size of a hash map +void hmap_rehash_to_size(struct hash_map* map, size_t new_size) { struct linked_list* new_buckets = array_new(struct linked_list, new_size); - for (size_t i = 0; i < new_size; ++i) - new_buckets[i] = ll_create( /* I know this is ugly */ map->buckets[0].meta.element_size); - + for (size_t i = 0; i < new_size; ++i) { + new_buckets[i] = ll_create(sizeof(struct hmap_pair)); + new_buckets[i].meta.free_function = __hmap_ll_custom_free; + } struct hash_map_iter iter; for (hmapi_begin(map, &iter); !hmapi_end(&iter); hmapi_next(&iter)) { size_t hash_pos = map->hash(hmapi_get_key(&iter)) % new_size; struct hmap_pair hash_data = hmapi_get_data(&iter); ll_append(new_buckets + hash_pos, &hash_data); } + for (size_t i = 0; i < array_size(map->buckets); ++i) { + map->buckets[i].meta.free_function = free; + ll_free(map->buckets + i); + } array_free(map->buckets); map->buckets = new_buckets; } diff --git a/include/hashset.h b/include/hashset.h deleted file mode 100644 index e69de29..0000000 --- a/include/hashset.h +++ /dev/null |