aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deque.c404
-rw-r--r--makefile2
2 files changed, 338 insertions, 68 deletions
diff --git a/deque.c b/deque.c
index 7125764..168669e 100644
--- a/deque.c
+++ b/deque.c
@@ -1,125 +1,395 @@
1#include <assert.h>
2#include <stdbool.h>
1#include <stdio.h> 3#include <stdio.h>
2#include <stdlib.h> 4#include <stdlib.h>
3#include <stdbool.h>
4 5
5#define NELEM(x) (sizeof(x) / sizeof(x[0])) 6#define NELEM(x) (sizeof(x) / sizeof(x[0]))
6 7
7typedef int T; 8typedef int T;
8 9
9struct chunk { 10#define START_MAP_CAPACITY 4
10 int head, tail; 11#define CHUNK_CAPACITY 17
11 T array[8]; 12
13struct deque {
14 T **map;
15
16 size_t map_begin;
17 size_t map_end;
18 size_t map_capacity;
19
20 size_t offset;
21 size_t size;
12}; 22};
13 23
24void
25deque_init(struct deque *d)
26{
27 d->map_begin = 0;
28 d->map_end = 0;
29 d->offset = 0;
30 d->size = 0;
31
32 // TODO: Error handling
33 d->map = calloc(START_MAP_CAPACITY, sizeof *d->map);
34 if ( d->map != NULL ) {
35 d->map_capacity = START_MAP_CAPACITY;
36
37 for ( size_t i = 0; i != d->map_capacity; ++i ) {
38 d->map[i] = NULL;
39 }
40 }
41}
42
43void
44deque_free(struct deque *d)
45{
46 // free all chunks
47 for ( size_t i = 0; i != d->map_capacity; ++i ) {
48 free(d->map[i]);
49 }
50
51 // free the map itself
52 free(d->map);
53 d->map = NULL;
54}
55
56size_t
57deque_size(struct deque *d)
58{
59 return d->size;
60}
61
62bool
63deque_is_empty(struct deque *d)
64{
65 return d->map_begin == d->map_end;
66}
67
68static void
69grow_map(struct deque *d)
70{
71 const size_t capacity = d->map_capacity + d->map_capacity / 2;
72 T ** map = calloc(capacity, sizeof *map);
73
74 // copy elements
75 size_t i, j;
76 for ( i = 0, j = d->map_begin; i != d->map_capacity; ++i, ++j ) {
77 if ( j == d->map_capacity ) {
78 j = 0;
79 }
80 map[i] = d->map[j];
81 }
82
83 // initialize the rest (new) elements with NULL
84 for ( ; i != capacity; ++i ) {
85 map[i] = NULL;
86 }
87
88 // free old & assign new map
89 free(d->map);
90 d->map = map;
91
92 // adjust pointers
93 d->map_begin = 0;
94 d->map_end = d->map_capacity - 1;
95
96 // set new map_capacity
97 d->map_capacity = capacity;
98}
99
14static void 100static void
15chunk_init(struct chunk *c) 101map_append_chunk(struct deque *d)
16{ 102{
17 c->head = 0; 103 size_t next = (d->map_end + 1) % d->map_capacity;
18 c->tail = 0; 104
105 if ( next == d->map_begin ) { // Resize the map
106 grow_map(d);
107
108 next = d->map_end + 1;
109 }
110
111 d->map[d->map_end] = calloc(CHUNK_CAPACITY, sizeof **d->map);
112 d->map_end = next;
19} 113}
20 114
21static bool 115static void
22chunk_put(struct chunk *c, T data) 116map_prepend_chunk(struct deque *d)
23{ 117{
24 const int next = (c->head + 1) % NELEM(c->array); 118 size_t prev = (d->map_begin + d->map_capacity - 1) % d->map_capacity;
25 119
26 if ( next == c->tail ) /* full? */ 120 if ( prev == d->map_end ) {
121 grow_map(d);
122
123 prev = d->map_capacity - 1;
124 }
125
126 d->map[prev] = calloc(CHUNK_CAPACITY, sizeof **d->map);
127 d->map_begin = prev;
128}
129
130static void
131map_remove_front_chunk(struct deque *d)
132{
133 if ( d->map_begin == d->map_end ) {
134 return;
135 }
136
137 const size_t next = (d->map_begin + 1) % d->map_capacity;
138
139 free(d->map[d->map_begin]);
140 d->map[d->map_begin] = NULL;
141
142 d->map_begin = next;
143}
144
145static void
146map_remove_tail_chunk(struct deque *d)
147{
148 if ( d->map_begin == d->map_end ) {
149 return;
150 }
151
152 const size_t prev = (d->map_end + d->map_capacity - 1) % d->map_capacity;
153
154 free(d->map[prev]);
155 d->map[prev] = NULL;
156
157 d->map_end = prev;
158}
159
160bool
161deque_get_at(struct deque *d, size_t idx, T *data)
162{
163 if ( idx >= d->size ) {
27 return false; 164 return false;
165 }
166
167 const size_t pos = d->offset + idx;
168 const size_t chunk_off = pos % CHUNK_CAPACITY;
169 const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
28 170
29 c->array[c->head] = data; 171 *data = d->map[chunk_num][chunk_off];
30 c->head = next;
31 172
32 return true; 173 return true;
33} 174}
34 175
35static bool 176bool
36chunk_get(struct chunk *c, T *data) 177deque_set_at(struct deque *d, size_t idx, T data)
37{ 178{
38 if ( c->head == c->tail ) /* empty? */ 179 if ( idx >= d->size ) {
39 return false; 180 return false;
181 }
40 182
41 const int next = (c->tail + 1) % NELEM(c->array); 183 const size_t pos = d->offset + idx;
184 const size_t chunk_off = pos % CHUNK_CAPACITY;
185 const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
42 186
43 *data = c->array[c->tail]; 187 d->map[chunk_num][chunk_off] = data;
44 c->tail = next;
45 188
46 return true; 189 return true;
47} 190}
48 191
49static int 192void
50chunk_size(struct chunk *c) 193deque_push_back(struct deque *d, T data)
51{ 194{
52 return (c->head + NELEM(c->array) - c->tail) % NELEM(c->array); 195 const size_t pos = d->offset + d->size;
196 const size_t chunk_off = pos % CHUNK_CAPACITY;
197 size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
198
199 if ( chunk_num == d->map_end ) {
200 map_append_chunk(d);
201 chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
202 }
203
204 d->map[chunk_num][chunk_off] = data;
205 ++d->size;
53} 206}
54 207
55static bool 208void
56chunk_full(struct chunk *c) 209deque_push_front(struct deque *d, T data)
57{ 210{
58 return ((c->head + 1) % NELEM(c->array)) == c->tail; 211 if ( d->offset == 0 ) { // Im ersten Element ist kein Platz mehr frei!
212 map_prepend_chunk(d);
213 d->offset = CHUNK_CAPACITY;
214 }
215
216 --d->offset;
217
218 const size_t chunk_num = (d->offset / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
219
220 d->map[chunk_num][d->offset] = data;
221 ++d->size;
59} 222}
60 223
61static bool 224bool
62chunk_empty(struct chunk *c) 225deque_pop_back(struct deque *d, T *data)
63{ 226{
64 return c->head == c->tail; 227 if ( d->size == 0 ) {
228 return false;
229 }
230
231 --d->size;
232
233 const size_t pos = d->offset + d->size;
234 const size_t chunk_off = pos % CHUNK_CAPACITY;
235 const size_t chunk_num = (pos / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
236
237 *data = d->map[chunk_num][chunk_off];
238
239 if ( d->size == 0 || chunk_off == 0 ) {
240 map_remove_tail_chunk(d);
241 }
242
243 return true;
65} 244}
66 245
67static T* 246bool
68chunk_at(struct chunk *c, int idx) 247deque_pop_front(struct deque *d, T *data)
69{ 248{
70 if ( idx < 0 || idx >= chunk_size(c) ) /* invalid index? */ 249 if ( d->size == 0 ) {
71 return NULL; 250 return false;
251 }
72 252
73 return &c->array[(c->head + idx) % NELEM(c->array)]; 253 --d->size;
74}
75 254
76/* ================= */ 255 const size_t chunk_num = (d->offset / CHUNK_CAPACITY + d->map_begin) % d->map_capacity;
77 256
78struct deque { 257 *data = d->map[chunk_num][d->offset];
79 int head, tail, capacity;
80 258
81 struct chunk **chunks; 259 ++d->offset;
82}; 260
261 if ( d->size == 0 || d->offset == CHUNK_CAPACITY ) {
262 map_remove_front_chunk(d);
263 d->offset = 0;
264 }
265
266 return true;
267}
268
269static void
270deque_show(struct deque *d)
271{
272 printf("first: %zu -- last: %zu -- size: %zu -- map_capacity: %zu -- offset: %zu\n",
273 d->map_begin, d->map_end, d->size, d->map_capacity, d->offset);
274 for ( size_t i = 0; i != d->map_capacity; ++i ) {
275 printf("%zu(%p) ", i, (void *) d->map[i]);
276 }
277 putchar('\n');
278}
83 279
84void 280void
85deque_init(struct deque *d) 281test_deque(void)
86{ 282{
87 int i; 283 struct deque d[1];
88 284
89 d->head = 0; 285 deque_init(d);
90 d->tail = 0;
91 d->capacity = 1;
92 286
93 d->chunks = calloc(d->capacity, sizeof(struct chunk *)); 287 const int N = 10000000;
94 288
95 for ( i = 0; i != d->capacity; ++i ) { 289 for ( int i = 0; i != N; ++i ) {
96 d->chunks[i] = malloc(sizeof(struct chunk)); 290 deque_push_front(d, i);
97 chunk_init(d->chunks[i]);
98 } 291 }
99}
100 292
293 for ( int i = 0; i != N; ++i ) {
294 int data;
295 assert(deque_pop_back(d, &data) == true);
296 assert(data == i);
297 }
298 assert(deque_is_empty(d) == true);
299
300 deque_free(d);
301
302 deque_init(d);
303
304 for ( int i = 0; i != N; ++i ) {
305 deque_push_back(d, i);
306 }
307
308 for ( int i = 0; i != N; ++i ) {
309 int data;
310 assert(deque_pop_front(d, &data) == true);
311 assert(data == i);
312 }
313 assert(deque_is_empty(d) == true);
314
315 deque_free(d);
316
317 deque_init(d);
318
319 for ( int i = 0; i != N; ++i ) {
320 deque_push_back(d, i);
321 }
322
323 for ( int i = N - 1; i >= 0; --i ) {
324 int data;
325 assert(deque_pop_back(d, &data) == true);
326 assert(data == i);
327 }
328 assert(deque_is_empty(d) == true);
329
330 deque_free(d);
101 331
102int main(void) 332 deque_init(d);
333
334 for ( int i = 0; i != N; ++i ) {
335 if ( i & 1 ) {
336 deque_push_front(d, i);
337 }
338 else {
339 deque_push_back(d, i);
340 }
341 }
342
343 for ( int i = N - 1; i >= 0; --i ) {
344 int data;
345 if ( i & 1 ) {
346 assert(deque_pop_front(d, &data) == true);
347 }
348 else {
349 assert(deque_pop_back(d, &data) == true);
350 }
351 if ( data != i ) {
352 printf("i: %d - data: %d\n", i, data);
353 }
354 assert(data == i);
355 }
356 assert(deque_is_empty(d) == true);
357
358 deque_free(d);
359
360 deque_init(d);
361
362 for ( int i = 0; i != N; ++i ) {
363 deque_push_front(d, i);
364 }
365
366 for ( int i = N - 1; i >= 0; --i ) {
367 int data;
368 assert(deque_pop_front(d, &data) == true);
369 assert(data == i);
370 }
371 assert(deque_is_empty(d) == true);
372
373 deque_free(d);
374}
375
376int
377main(void)
103{ 378{
104 struct chunk c; 379 test_deque();
105 int data; 380
381 struct deque c;
106 382
107 chunk_init(&c); 383 deque_init(&c);
108 384
109 chunk_put(&c, '0'); 385 T data;
110 chunk_put(&c, '0'); 386 while ( deque_pop_front(&c, &data) ) {
111 chunk_get(&c, &data); 387 printf("%u, ", data);
112 chunk_get(&c, &data); 388 }
389 putchar('\n');
390 deque_show(&c);
113 391
114 chunk_put(&c, 'A'); 392 deque_free(&c);
115 chunk_put(&c, 'B');
116 chunk_put(&c, 'C');
117 chunk_put(&c, 'D');
118 chunk_put(&c, 'E');
119 chunk_put(&c, 'F');
120 chunk_put(&c, 'G');
121 393
122 printf("head: %d -- tail: %d -- size: %d\n", c.head, c.tail, chunk_size(&c));
123 return 0; 394 return 0;
124} 395}
125
diff --git a/makefile b/makefile
index 0c229d6..9748166 100644
--- a/makefile
+++ b/makefile
@@ -1,6 +1,6 @@
1.PHONY: all clean 1.PHONY: all clean
2 2
3CFLAGS=-O3 -Wall -Werror -Wno-unused-function -pedantic -std=c99 -g 3CFLAGS=-Wall -Werror -Wextra -Wno-unused-function -Wsign-conversion -pedantic -std=c99 -g
4 4
5all: list dlist stack stack2 queue ringbuff hashtab tree avl heap quicksort allocator rb deque 5all: list dlist stack stack2 queue ringbuff hashtab tree avl heap quicksort allocator rb deque
6 6