forked from Tib-ved/Algorithms
-
Notifications
You must be signed in to change notification settings - Fork 0
/
hashmap.c
194 lines (158 loc) · 4.19 KB
/
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
185
186
187
188
189
190
191
192
193
194
/* Generic hashmap by Andreas Pfohl (@apfohl) */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifndef HASHMAP_INITIAL_CAPACITY
#define HASHMAP_INITIAL_CAPACITY 32 ///< default hashmap init capacity
#endif
struct hashmap *clone_and_double(struct hashmap *);
/**
* Hashmap entry structure
*/
struct hashmap_entry {
char *key;
void *value;
};
/**
* Hashmap structure
*/
struct hashmap {
int capacity;
int size;
struct hashmap_entry *values;
};
/**
* @brief Dan Bernsteins DJB2 Hash Function
* @detail http://www.cse.yorku.ca/~oz/hash.html
* String must be terminated with a null-byte.
*/
unsigned long hash(char *str)
{
unsigned long hash = 5381;
int c;
while ((c = *str++)) {
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
}
return hash;
}
/**
* Allocate new hashmap.
*/
struct hashmap *hashmap_alloc(int capacity)
{
struct hashmap *new_table = malloc(sizeof(struct hashmap));
new_table->capacity = capacity;
new_table->size = 0;
new_table->values = malloc(capacity * sizeof(struct hashmap_entry));
for (int i = 0; i < new_table->capacity; i++) {
new_table->values[i].key = NULL;
}
return new_table;
}
/**
* Free hashmap.
*/
void hashmap_free(struct hashmap **table, void (*value_free)(void *ptr))
{
if (!(*table)) {
return;
}
for (int i = 0; i < (*table)->capacity; i++) {
if ((*table)->values[i].key) {
free((*table)->values[i].key);
if (value_free) {
value_free((*table)->values[i].value);
}
}
}
free((*table)->values);
free(*table);
*table = NULL;
}
/**
* Insert new element into hashmap.
*/
void *hashmap_put(struct hashmap **table, const char *key, void *value)
{
if (!key) {
return NULL;
}
if (*table == NULL) {
*table = hashmap_alloc(HASHMAP_INITIAL_CAPACITY);
} else if ((*table)->size > 0.7 * (*table)->capacity) {
struct hashmap *doubled_table = clone_and_double(*table);
hashmap_free(table, NULL);
*table = doubled_table;
}
unsigned long hashval = hash((char *)key);
unsigned long position;
unsigned char reassign = 0;
int i = 1;
do {
// Quadratic probing
position = hashval + ((int)(0.5 * i)) + ((int)(0.5 * i * i));
position %= (*table)->capacity;
i++;
} while ((*table)->values[position].key
&& !(reassign =
strcmp((*table)->values[position].key, key) == 0));
void *ret = value;
if (!reassign) {
(*table)->size++;
(*table)->values[position].key = malloc(strlen(key) + 1);
strcpy((*table)->values[position].key, key);
} else {
ret = (*table)->values[position].value;
}
(*table)->values[position].value = value;
return ret;
}
/**
* Resize hashmap.
*/
struct hashmap *clone_and_double(struct hashmap *table)
{
struct hashmap *new_table;
new_table = hashmap_alloc(2 * table->capacity);
struct hashmap_entry *entry;
for (int i = 0; i < table->capacity; i++) {
entry = table->values + i;
if (entry->key) {
hashmap_put(&new_table, entry->key, entry->value);
}
}
return new_table;
}
/**
* Get element from hashmap.
*/
void *hashmap_get(struct hashmap *const *table, const char *key)
{
void *value = NULL;
if (table && *table) {
unsigned long hashval = hash((char *)key);
unsigned long position;
int i = 1;
do {
// Quadratic probing
position =
hashval + ((int)(0.5 * i)) + ((int)(0.5 * i * i));
position %= (*table)->capacity;
i++;
} while ((*table)->values[position].key &&
strcmp((*table)->values[position].key, key) != 0);
if ((*table)->values[position].key) {
value = (*table)->values[position].value;
}
}
return value;
}
int main(int argc, char **argv)
{
struct hashmap *hashmap = NULL;
int *i = calloc(1, sizeof(int));
*i = 42;
hashmap_put(&hashmap, "sample", i);
fprintf(stdout, "%d\n", *(int *)hashmap_get(&hashmap, "sample"));
hashmap_free(&hashmap, free);
}