1 /*
2  * Copyright (c) 2008-2009, Courtney Cavin
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  - Redistributions of source code must retain the above copyright notice,
8  *  this list of conditions and the following disclaimer.
9  *
10  *  - Redistributions in binary form must reproduce the above copyright notice,
11  *  this list of conditions and the following disclaimer in the documentation
12  *  and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
18  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
24  * POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <stdlib.h>
28 #include "map.h"
29 
30 struct map_entry {
31 	struct map_item *item;
32 };
33 
34 /* Marker for deleted items */
35 static struct map_item deleted;
36 
map_destroy(struct map * map)37 void map_destroy(struct map *map)
38 {
39 	free(map->data);
40 }
41 
map_clear(struct map * map,void (* release)(struct map_item *))42 void map_clear(struct map *map, void (*release)(struct map_item *))
43 {
44 	int i;
45 
46 	for (i = 0; i < map->size; ++i){
47 		if (!map->data[i].item)
48 			continue;
49 		if (map->data[i].item != &deleted)
50 			(* release)(map->data[i].item);
51 		map->data[i].item = NULL;
52 	}
53 	map->count = 0;
54 }
55 
map_create(struct map * map)56 int map_create(struct map *map)
57 {
58 	map->size = 0;
59 	map->data = 0;
60 	map->count = 0;
61 	return 0;
62 }
63 
map_hash(struct map * map,unsigned int key)64 static int map_hash(struct map *map, unsigned int key)
65 {
66 	struct map_entry *e;
67 	int idx, i;
68 
69 	if (map->count == map->size)
70 		return -1;
71 
72 	idx = key % map->size;
73 
74 	for (i = 0; i < map->size; ++i) {
75 		e = &map->data[idx];
76 		if (!e->item || e->item == &deleted) {
77 			++map->count;
78 			return idx;
79 		}
80 		if (e->item->key == key)
81 			return idx;
82 
83 		idx = (idx + 1) % map->size;
84 	}
85 
86 	return -2;
87 }
88 
89 static int map_rehash(struct map *map);
90 
map_reput(struct map * map,unsigned int key,struct map_item * value,struct map_item ** old)91 int map_reput(struct map *map, unsigned int key, struct map_item *value,
92 		struct map_item **old)
93 {
94 	int rc;
95 
96 	while ((rc = map_hash(map, key)) < 0) {
97 		if ((rc = map_rehash(map)) < 0)
98 			return rc;
99 	}
100 
101 	if (old) {
102 		if (map->data[rc].item == &deleted)
103 			*old = NULL;
104 		else
105 			*old = map->data[rc].item;
106 	}
107 	map->data[rc].item = value;
108 	if (value)
109 		map->data[rc].item->key = key;
110 
111 	return 0;
112 }
113 
map_put(struct map * map,unsigned int key,struct map_item * value)114 int map_put(struct map *map, unsigned int key, struct map_item *value)
115 {
116 	return map_reput(map, key, value, NULL);
117 }
118 
map_rehash(struct map * map)119 static int map_rehash(struct map *map)
120 {
121 	struct map_entry *oldt, *newt;
122 	int o_size, i;
123 	int rc;
124 
125 	newt = calloc(sizeof(struct map_entry), map->size + 256);
126 	if (!newt)
127 		return -1;
128 
129 	oldt = map->data;
130 	map->data = newt;
131 
132 	o_size = map->size;
133 	map->size += 256;
134 	map->count = 0;
135 
136 	for (i = 0; i < o_size; ++i){
137 		if (!oldt[i].item || oldt[i].item == &deleted)
138 			continue;
139 		rc = map_put(map, oldt[i].item->key, oldt[i].item);
140 		if (rc < 0)
141 			return rc;
142 	}
143 
144 	free(oldt);
145 
146 	return 0;
147 }
148 
map_find(const struct map * map,unsigned int key)149 static struct map_entry *map_find(const struct map *map, unsigned int key)
150 {
151 	struct map_entry *e;
152 	int idx, i;
153 
154 	if (map->size == 0)
155 		return NULL;
156 
157 	idx = key % map->size;
158 
159 	for (i = 0; i < map->size; ++i) {
160 		e = &map->data[idx];
161 		idx = (idx + 1) % map->size;
162 
163 		if (!e->item)
164 			break;
165 		if (e->item == &deleted)
166 			continue;
167 		if (e->item->key == key)
168 			return e;
169 	}
170 	return NULL;
171 }
172 
map_contains(const struct map * map,unsigned int key)173 int map_contains(const struct map *map, unsigned int key)
174 {
175 	return (map_find(map, key) == NULL) ? 0 : 1;
176 }
177 
map_get(const struct map * map,unsigned int key)178 struct map_item *map_get(const struct map *map, unsigned int key)
179 {
180 	struct map_entry *e;
181 
182 	e = map_find(map, key);
183 	if (e == NULL)
184 		return NULL;
185 	return e->item;
186 }
187 
map_remove(struct map * map,unsigned int key)188 int map_remove(struct map *map, unsigned int key)
189 {
190 	struct map_entry *e;
191 
192 	e = map_find(map, key);
193 	if (e) {
194 		e->item = &deleted;
195 		--map->count;
196 	}
197 	return !e;
198 }
199 
map_length(struct map * map)200 unsigned int map_length(struct map *map)
201 {
202 	return map ? map->count : 0;
203 }
204 
map_iter_from(const struct map * map,unsigned int start)205 static struct map_entry *map_iter_from(const struct map *map, unsigned int start)
206 {
207 	unsigned int i = start;
208 
209 	for (; i < map->size; ++i) {
210 		if (map->data[i].item && map->data[i].item != &deleted)
211 			return &map->data[i];
212 	}
213 	return NULL;
214 }
215 
map_iter_next(const struct map * map,struct map_entry * iter)216 struct map_entry *map_iter_next(const struct map *map, struct map_entry *iter)
217 {
218 	if (iter == NULL)
219 		return NULL;
220 
221 	return map_iter_from(map, (iter - map->data) + 1);
222 }
223 
map_iter_first(const struct map * map)224 struct map_entry *map_iter_first(const struct map *map)
225 {
226 	return map_iter_from(map, 0);
227 }
228 
229 
map_iter_item(struct map_entry * iter)230 struct map_item *map_iter_item(struct map_entry *iter)
231 {
232 	return iter->item;
233 }
234