-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathhm.c
150 lines (116 loc) · 2.84 KB
/
hm.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
/* hm.c
A program defining a hash map in C
This program defines a simple hash table (or hash map)
in C that uses open addressing and linear probing.
*/
#include "hm.h"
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
typedef struct {
const char *key;
void *value;
} hm_entry;
struct hm {
hm_entry* entries;
size_t capacity;
size_t length;
};
#define INITIAL_CAPACITY 64;
hm *hm_create(void)
{
/* First, we allocate space for our hash map, then
allocate space for our entries
*/
hm *map = malloc(sizeof(hm));
if (map == NULL) {
return NULL;
}
map->length = 0;
map->capacity = INITIAL_CAPACITY;
map->entries = calloc(map->capacity, sizeof(hm_entry));
if (map->entries == NULL) {
free(map);
return NULL;
}
return map;
}
void *hm_destroy(hm *map) {
for (size_t i = 0; i < map->capacity; i++) {
free((void*)(map->entries[i].key));
}
free(map->entries);
free(map);
}
/* Here, we define a hash function djb2. Original code can
be found at http://www.cse.yorku.ca/~oz/hash.html and
is originally written by dan bernstein. More info can
be found at https://theartincode.stanis.me/008-djb2/
*/
unsigned long
djb2(const char *str)
{
unsigned long hash = 5381;
int c;
while (c = *str++)
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
return hash;
}
void *hm_get(hm *map, const char *key) {
// Make sure that the hash fits in the table
unsigned long hash = djb2(key);
size_t index = (size_t)(hash & (unsigned long)(map->capacity - 1));
// Begin linear probing
while (map->entries[index].key != NULL) {
if (strcmp(key, map->entries[index].key) == 0)
return map->entries[index].value;
index++;
if (index >= map->capacity)
index = 0;
}
return NULL;
}
// Function to set an entry (private scope)
static const char *
hm_set_entry(hm_entry *entries, size_t capacity,
const char *key, void *value, size_t *plength)
{
unsigned long hash = djb2(key);
size_t index = (hash & (uint64_t)(capacity - 1));
// Begin linear probing
while (entries[index].key != NULL) {
if (strcmp(key, entries[index].key) == 0) {
entries[index].value = value;
return entries[index].key;
}
index++;
if (index >= capacity)
index = 0;
}
// Key not found, insert in next null space
if (plength != NULL) {
key = strdup(key);
if (key == NULL) {
return NULL;
}
(*plength)++;
}
// Update map
entries[index].key = (char *)key;
entries[index].value = value;
return key;
}
// Setter function (public scope)
const char *
hm_set(hm *map, const char *key, void *value) {
assert(value != NULL);
if (value == NULL) {
return NULL;
}
return hm_set_entry(map->entries, map->capacity, key, value,
&map->length);
}
size_t hm_length(hm *map) {
return map->length;
}