aboutsummaryrefslogtreecommitdiff
path: root/src/deque.c
diff options
context:
space:
mode:
authorThomas Schmucker <ts@its1.de>2022-04-09 09:43:53 +0200
committerThomas Schmucker <ts@its1.de>2022-04-09 09:43:53 +0200
commit154874afda4a8df885e51c01f7681f04fb0b8e61 (patch)
tree274817eb2793584b0e3d856de5504a614f2b4e89 /src/deque.c
parent2863f4f1d2a6a6a8704454824d6c291d2e0d4b5c (diff)
downloaddata-structures-154874afda4a8df885e51c01f7681f04fb0b8e61.tar.gz
data-structures-154874afda4a8df885e51c01f7681f04fb0b8e61.tar.bz2
data-structures-154874afda4a8df885e51c01f7681f04fb0b8e61.zip
neue Verzeichnisstruktur
Diffstat (limited to 'src/deque.c')
-rw-r--r--src/deque.c485
1 files changed, 485 insertions, 0 deletions
diff --git a/src/deque.c b/src/deque.c
new file mode 100644
index 0000000..881d1d3
--- /dev/null
+++ b/src/deque.c
@@ -0,0 +1,485 @@
1#include <assert.h>
2#include <stdbool.h>
3#include <stdio.h>
4#include <stdlib.h>
5
6#include "util.h"
7
8#define START_MAP_CAPACITY 4
9#define CHUNK_CAPACITY 17
10
11/* --8<-- deque_type */
12typedef int T;
13
14struct deque {
15 T **map;
16
17 size_t map_begin;
18 size_t map_end;
19 size_t map_capacity;
20
21 size_t offset;
22 size_t size;
23};
24/* -->8-- */
25
26/* --8<-- deque_allocate */
27static void *
28allocate(size_t n, size_t sz)
29{
30 void *ptr = calloc(n, sz);
31 if ( ptr == NULL ) {
32 ERROR("out of memory!");
33 }
34 return ptr;
35}
36/* -->8-- */
37
38/* --8<-- deque_init */
39void
40deque_init(struct deque *d)
41{
42 assert(d);
43
44 d->map_begin = 0;
45 d->map_end = 0;
46 d->offset = 0;
47 d->size = 0;
48
49 // TODO: Error handling
50 d->map = allocate(START_MAP_CAPACITY, sizeof *d->map);
51 if ( d->map ) {
52 d->map_capacity = START_MAP_CAPACITY;
53
54 for ( size_t i = 0; i != d->map_capacity; ++i ) {
55 d->map[i] = NULL;
56 }
57 }
58}
59/* -->8-- */
60
61/* --8<-- deque_free */
62void
63deque_free(struct deque *d)
64{
65 assert(d);
66
67 // free all chunks
68 for ( size_t i = 0; i != d->map_capacity; ++i ) {
69 free(d->map[i]);
70 }
71
72 // free the map itself
73 free(d->map);
74 d->map = NULL;
75}
76/* -->8-- */
77
78/* --8<-- deque_size */
79size_t
80deque_size(struct deque *d)
81{
82 assert(d);
83
84 return d->size;
85}
86/* -->8-- */
87
88/* --8<-- deque_is_empty */
89bool
90deque_is_empty(struct deque *d)
91{
92 assert(d);
93
94 return d->map_begin == d->map_end;
95}
96/* -->8-- */
97
98/* --8<-- deque_grow_map */
99static void
100grow_map(struct deque *d)
101{
102 assert(d);
103
104 const size_t capacity = d->map_capacity + d->map_capacity / 2;
105 T ** map = allocate(capacity, sizeof *map);
106
107 // copy elements
108 size_t i, j;
109 for ( i = 0, j = d->map_begin; i != d->map_capacity; ++i, ++j ) {
110 if ( j == d->map_capacity ) {
111 j = 0;
112 }
113 map[i] = d->map[j];
114 }
115
116 // initialize the rest (new) elements with NULL
117 for ( ; i != capacity; ++i ) {
118 map[i] = NULL;
119 }
120
121 // free old & assign new map
122 free(d->map);
123 d->map = map;
124
125 // adjust pointers
126 d->map_begin = 0;
127 d->map_end = d->map_capacity - 1;
128
129 // set new map_capacity
130 d->map_capacity = capacity;
131}
132/* -->8-- */
133
134/* --8<-- deque_map_append_chunk */
135static void
136map_append_chunk(struct deque *d)
137{
138 assert(d);
139
140 size_t next = (d->map_end + 1) % d->map_capacity;
141
142 if ( next == d->map_begin ) { // Resize the map
143 grow_map(d);
144
145 next = d->map_end + 1;
146 }
147
148 d->map[d->map_end] = allocate(CHUNK_CAPACITY, sizeof **d->map);
149 d->map_end = next;
150}
151/* -->8-- */
152
153/* --8<-- deque_map_prepend_chunk */
154static void
155map_prepend_chunk(struct deque *d)
156{
157 assert(d);
158
159 size_t prev = (d->map_begin + d->map_capacity - 1) % d->map_capacity;
160
161 if ( prev == d->map_end ) {
162 grow_map(d);
163
164 prev = d->map_capacity - 1;
165 }
166
167 d->map[prev] = allocate(CHUNK_CAPACITY, sizeof **d->map);
168 d->map_begin = prev;
169}
170/* -->8-- */
171
172/* --8<-- deque_map_remove_front_chunk */
173static void
174map_remove_front_chunk(struct deque *d)
175{
176 assert(d);
177
178 if ( d->map_begin == d->map_end ) {
179 return;
180 }
181
182 const size_t next = (d->map_begin + 1) % d->map_capacity;
183
184 free(d->map[d->map_begin]);
185 d->map[d->map_begin] = NULL;
186
187 d->map_begin = next;
188}
189/* -->8-- */
190
191/* --8<-- deque_remove_tail_chunk */
192static void
193map_remove_tail_chunk(struct deque *d)
194{
195 assert(d);
196
197 if ( d->map_begin == d->map_end ) {
198 return;
199 }
200
201 const size_t prev = (d->map_end + d->map_capacity - 1) % d->map_capacity;
202
203 free(d->map[prev]);
204 d->map[prev] = NULL;
205
206 d->map_end = prev;
207}
208/* -->8-- */
209
210/* --8<-- deque_get_at */
211bool
212deque_get_at(struct deque *d, size_t idx, T *data)
213{
214 assert(d);
215 assert(idx < d->size);
216 assert(data);
217
218 if ( idx >= d->size ) {
219 return false;
220 }
221
222 const size_t pos = d->offset + idx;
223 const size_t chunk_off = pos % CHUNK_CAPACITY;
224 const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
225
226 *data = d->map[chunk_num][chunk_off];
227
228 return true;
229}
230/* -->8-- */
231
232/* --8<-- deque_set_at */
233bool
234deque_set_at(struct deque *d, size_t idx, T data)
235{
236 assert(d);
237 assert(idx < d->size);
238
239 if ( idx >= d->size ) {
240 return false;
241 }
242
243 const size_t pos = d->offset + idx;
244 const size_t chunk_off = pos % CHUNK_CAPACITY;
245 const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
246
247 d->map[chunk_num][chunk_off] = data;
248
249 return true;
250}
251/* -->8-- */
252
253/* --8<-- deque_push_back */
254void
255deque_push_back(struct deque *d, T data)
256{
257 assert(d);
258
259 const size_t pos = d->offset + d->size;
260 const size_t chunk_off = pos % CHUNK_CAPACITY;
261 size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
262
263 if ( chunk_num == d->map_end ) {
264 map_append_chunk(d);
265 chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
266 }
267
268 d->map[chunk_num][chunk_off] = data;
269 ++d->size;
270}
271/* -->8-- */
272
273/* --8<-- deque_push_front */
274void
275deque_push_front(struct deque *d, T data)
276{
277 assert(d);
278
279 if ( d->offset == 0 ) { // Im ersten Element ist kein Platz mehr frei!
280 map_prepend_chunk(d);
281 d->offset = CHUNK_CAPACITY;
282 }
283
284 --d->offset;
285
286 const size_t chunk_num = (d->offset / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
287
288 d->map[chunk_num][d->offset] = data;
289 ++d->size;
290}
291/* -->8-- */
292
293/* --8<-- deque_pop_back */
294bool
295deque_pop_back(struct deque *d, T *data)
296{
297 assert(d);
298 assert(data);
299
300 if ( d->size == 0 ) {
301 return false;
302 }
303
304 --d->size;
305
306 const size_t pos = d->offset + d->size;
307 const size_t chunk_off = pos % CHUNK_CAPACITY;
308 const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
309
310 *data = d->map[chunk_num][chunk_off];
311
312 if ( d->size == 0 || chunk_off == 0 ) {
313 map_remove_tail_chunk(d);
314 }
315
316 return true;
317}
318/* -->8-- */
319
320/* --8<-- deque_pop_front */
321bool
322deque_pop_front(struct deque *d, T *data)
323{
324 assert(d);
325 assert(data);
326
327 if ( d->size == 0 ) {
328 return false;
329 }
330
331 --d->size;
332
333 const size_t chunk_num = (d->offset / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
334
335 *data = d->map[chunk_num][d->offset];
336
337 ++d->offset;
338
339 if ( d->size == 0 || d->offset == CHUNK_CAPACITY ) {
340 map_remove_front_chunk(d);
341 d->offset = 0;
342 }
343
344 return true;
345}
346/* -->8-- */
347
348static void
349deque_show(struct deque *d)
350{
351 assert(d);
352
353 printf("first: %zu -- last: %zu -- size: %zu -- map_capacity: %zu -- offset: %zu\n",
354 d->map_begin, d->map_end, d->size, d->map_capacity, d->offset);
355 for ( size_t i = 0; i != d->map_capacity; ++i ) {
356 printf("%zu(%p) ", i, (void *) d->map[i]);
357 }
358 putchar('\n');
359}
360
361void
362test_deque(void)
363{
364#ifndef NDEBUG
365 struct deque d[1];
366
367 deque_init(d);
368
369 const int N = 100000;
370
371 for ( int i = 0; i != N; ++i ) {
372 deque_push_front(d, i);
373 }
374
375 for ( int i = 0; i != N; ++i ) {
376 int data;
377 assert(deque_pop_back(d, &data) == true);
378 assert(data == i);
379 }
380 assert(deque_is_empty(d) == true);
381 assert(deque_size(d) == 0);
382
383 deque_free(d);
384
385 deque_init(d);
386
387 for ( int i = 0; i != N; ++i ) {
388 deque_push_back(d, i);
389 }
390
391 for ( int i = 0; i != N; ++i ) {
392 int data;
393 assert(deque_pop_front(d, &data) == true);
394 assert(data == i);
395 }
396 assert(deque_is_empty(d) == true);
397 assert(deque_size(d) == 0);
398
399 deque_free(d);
400
401 deque_init(d);
402
403 for ( int i = 0; i != N; ++i ) {
404 deque_push_back(d, i);
405 }
406
407 for ( int i = N - 1; i >= 0; --i ) {
408 int data;
409 assert(deque_pop_back(d, &data) == true);
410 assert(data == i);
411 }
412 assert(deque_is_empty(d) == true);
413 assert(deque_size(d) == 0);
414
415 deque_free(d);
416
417 deque_init(d);
418
419 for ( int i = 0; i != N; ++i ) {
420 if ( i & 1 ) {
421 deque_push_front(d, i);
422 }
423 else {
424 deque_push_back(d, i);
425 }
426 }
427
428 for ( int i = N - 1; i >= 0; --i ) {
429 int data;
430 if ( i & 1 ) {
431 assert(deque_pop_front(d, &data) == true);
432 }
433 else {
434 assert(deque_pop_back(d, &data) == true);
435 }
436 if ( data != i ) {
437 printf("i: %d - data: %d\n", i, data);
438 }
439 assert(data == i);
440 }
441 assert(deque_is_empty(d) == true);
442 assert(deque_size(d) == 0);
443
444 deque_free(d);
445
446 deque_init(d);
447
448 for ( int i = 0; i != N; ++i ) {
449 deque_push_front(d, i);
450 }
451
452 for ( int i = N - 1; i >= 0; --i ) {
453 int data;
454 assert(deque_pop_front(d, &data) == true);
455 assert(data == i);
456 }
457 assert(deque_is_empty(d) == true);
458 assert(deque_size(d) == 0);
459
460 deque_free(d);
461
462 puts("all tests passed.");
463#endif
464}
465
466int
467main(void)
468{
469 test_deque();
470
471 struct deque c;
472
473 deque_init(&c);
474
475 T data;
476 while ( deque_pop_front(&c, &data) ) {
477 printf("%u, ", data);
478 }
479 putchar('\n');
480 deque_show(&c);
481
482 deque_free(&c);
483
484 return 0;
485}