-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimple_hashmap.c
184 lines (157 loc) · 4.19 KB
/
simple_hashmap.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "simple_hashmap.h"
struct _map_entry
{
uint64_t key_hash;
void* data;
struct _map_entry* next;
};
typedef struct _map_entry map_entry;
struct _hashmap
{
map_entry** table;
size_t size;
size_t count;
};
static void* copy_content(void* content, size_t len)
{
void* copy = malloc(len);
memcpy(copy,content,len);
return copy;
}
static map_entry* generate_map_entry(void* data, size_t data_len, uint64_t key_hash)
{
map_entry* entry = malloc(sizeof(map_entry));
entry->key_hash = key_hash;
entry->data = copy_content(data, data_len);
entry->next = NULL;
return entry;
}
static void free_map_entries(map_entry* entry)
{
map_entry* next = entry->next;
free(entry->data);
free(entry);
if(next != NULL)
free_map_entries(next);
}
static int search_map_entry_in_linked_list(map_entry** entry, uint64_t key_hash, map_entry** previous)
{
int key_match = (*entry)->key_hash == key_hash;
while(!key_match && (*entry)->next != NULL)
{
*previous = *entry;
*entry = (*entry)->next;
key_match = (*entry)->key_hash == key_hash;
}
return key_match;
}
static uint64_t string_hash(char* string, size_t len)
{
uint64_t hash = 0;
unsigned char *p;
int i;
for(i = 0, p = (unsigned char *)string; i<len ; i++)
hash = 31 * hash + *(p+i);
return (hash & 0x7FFFFFFFFFFFFFFF);
}
/*=============================================================================
Public Functions
=============================================================================*/
hashmap* create_hashmap(size_t size)
{
hashmap* hm = malloc(sizeof(hashmap));
hm->table = calloc(sizeof(map_entry*), size);
hm->size = size;
hm->count = 0;
return hm;
}
void free_hashmap(hashmap* map)
{
int i;
for(i=0;i<map->size;i++)
{
map_entry* entry = map->table[i];
if(entry != NULL)
free_map_entries(entry);
}
free(map->table);
free(map);
}
int hashmap_insert(hashmap* map, char* key, size_t key_len, void* data, size_t data_len)
{
return hashmap_insert_uint64_key(map, string_hash(key, key_len), data, data_len);
}
int hashmap_insert_uint64_key(hashmap* map, uint64_t key, void* data, size_t data_len)
{
if(map->size <= map->count)
return -1;
++map->count;
size_t index = key % map->size;
if(map->table[index] == NULL)
map->table[index] = generate_map_entry(data, data_len, key);
else
{
map_entry* entry = map->table[index];
int key_match = search_map_entry_in_linked_list(&entry, key, NULL);
if(key_match)
{
free(entry->data);
entry->data = copy_content(data, data_len);
--map->count;
}
else
entry->next = generate_map_entry(data, data_len, key);
}
return 0;
}
int hashmap_remove(hashmap* map, char* key, size_t key_len)
{
return hashmap_remove_uint64_key(map, string_hash(key, key_len));
}
int hashmap_remove_uint64_key(hashmap* map, uint64_t key)
{
if(map->count == 0)
return -1;
size_t index = key % map->size;
map_entry* entry = map->table[index];
if(entry != NULL)
{
map_entry* previous = NULL;
int key_match = search_map_entry_in_linked_list(&entry, key, &previous);
if(key_match)
{
--map->count;
if(previous == NULL)
map->table[index] = entry->next;
else
previous->next = entry->next;
free(entry->data);
free(entry);
}
}
return 0;
}
void* hashmap_get(hashmap* map, char* key, size_t key_len)
{
return hashmap_get_uint64_key(map, string_hash(key, key_len));
}
void* hashmap_get_uint64_key(hashmap* map, uint64_t key)
{
if(map->count == 0)
return NULL;
map_entry* entry = map->table[key % map->size];
if(entry != NULL)
{
int key_match = search_map_entry_in_linked_list(&entry, key, NULL);
if(key_match)
return entry->data;
}
return NULL;
}
size_t hashmap_count(hashmap* map)
{
return map->count;
}