Skip to content

Commit d470d94

Browse files
authored
Optimize deque outer array (#124)
Optimize the array which holds mappings to blocks in deque by shifting whenever it runs out of memory on one side rather than always allocating new memory.
1 parent eff1e3e commit d470d94

2 files changed

Lines changed: 99 additions & 30 deletions

File tree

src/deque.c

Lines changed: 56 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -293,24 +293,39 @@ static size_t deque_get_new_block_count(deque me)
293293
bk_err deque_push_front(deque me, void *const data)
294294
{
295295
if (me->start_index == 0) {
296-
const size_t new_block_count = deque_get_new_block_count(me);
297-
size_t added_blocks;
298-
char **temp;
299-
if (new_block_count == 0) {
300-
return -BK_ERANGE;
301-
}
302-
added_blocks = new_block_count - me->block_count;
303-
temp = realloc(me->data, new_block_count * sizeof(char *));
304-
if (!temp) {
305-
return -BK_ENOMEM;
296+
const size_t available_end = me->block_count - me->alloc_block_end - 1;
297+
if (available_end > BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT) {
298+
const size_t shift_end = available_end / 2;
299+
const size_t allocated_blocks =
300+
me->alloc_block_end - me->alloc_block_start + 1;
301+
memmove(me->data + me->alloc_block_start + shift_end,
302+
me->data + me->alloc_block_start,
303+
allocated_blocks * sizeof(char *));
304+
me->start_index += shift_end * me->block_size;
305+
me->end_index += shift_end * me->block_size;
306+
me->alloc_block_start += shift_end;
307+
me->alloc_block_end += shift_end;
308+
} else {
309+
const size_t new_block_count = deque_get_new_block_count(me);
310+
size_t added_blocks;
311+
char **temp;
312+
if (new_block_count == 0) {
313+
return -BK_ERANGE;
314+
}
315+
added_blocks = new_block_count - me->block_count;
316+
temp = realloc(me->data, new_block_count * sizeof(char *));
317+
if (!temp) {
318+
return -BK_ENOMEM;
319+
}
320+
memmove(temp + added_blocks, temp,
321+
me->block_count * sizeof(char *));
322+
me->data = temp;
323+
me->block_count = new_block_count;
324+
me->start_index += added_blocks * me->block_size;
325+
me->end_index += added_blocks * me->block_size;
326+
me->alloc_block_start += added_blocks;
327+
me->alloc_block_end += added_blocks;
306328
}
307-
memmove(temp + added_blocks, temp, me->block_count * sizeof(char *));
308-
me->data = temp;
309-
me->block_count = new_block_count;
310-
me->start_index += added_blocks * me->block_size;
311-
me->end_index += added_blocks * me->block_size;
312-
me->alloc_block_start += added_blocks;
313-
me->alloc_block_end += added_blocks;
314329
}
315330
if (me->start_index % me->block_size == 0) {
316331
const size_t add_block_index = me->start_index / me->block_size - 1;
@@ -357,17 +372,31 @@ bk_err deque_push_front(deque me, void *const data)
357372
bk_err deque_push_back(deque me, void *const data)
358373
{
359374
if (me->end_index == me->block_count * me->block_size) {
360-
const size_t new_block_count = deque_get_new_block_count(me);
361-
char **temp;
362-
if (new_block_count == 0) {
363-
return -BK_ERANGE;
364-
}
365-
temp = realloc(me->data, new_block_count * sizeof(char *));
366-
if (!temp) {
367-
return -BK_ENOMEM;
375+
const size_t available_start = me->alloc_block_start;
376+
if (available_start > BKTHOMPS_DEQUE_INITIAL_BLOCK_COUNT) {
377+
const size_t shift_start = available_start - available_start / 2;
378+
const size_t allocated_blocks =
379+
me->alloc_block_end - me->alloc_block_start + 1;
380+
memmove(me->data + me->alloc_block_start / 2,
381+
me->data + me->alloc_block_start,
382+
allocated_blocks * sizeof(char *));
383+
me->start_index -= shift_start * me->block_size;
384+
me->end_index -= shift_start * me->block_size;
385+
me->alloc_block_start -= shift_start;
386+
me->alloc_block_end -= shift_start;
387+
} else {
388+
const size_t new_block_count = deque_get_new_block_count(me);
389+
char **temp;
390+
if (new_block_count == 0) {
391+
return -BK_ERANGE;
392+
}
393+
temp = realloc(me->data, new_block_count * sizeof(char *));
394+
if (!temp) {
395+
return -BK_ENOMEM;
396+
}
397+
me->data = temp;
398+
me->block_count = new_block_count;
368399
}
369-
me->data = temp;
370-
me->block_count = new_block_count;
371400
}
372401
if (me->end_index % me->block_size == 0) {
373402
const size_t add_block_index = me->end_index / me->block_size;

tst/test_deque.c

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ struct pair {
388388
int cur_cost;
389389
};
390390

391-
static int test_puzzle(int start_node, int dest_node)
391+
static int test_puzzle_forwards(int start_node, int dest_node)
392392
{
393393
deque q = deque_init(sizeof(struct pair));
394394
struct pair cur;
@@ -424,6 +424,42 @@ static int test_puzzle(int start_node, int dest_node)
424424
return -1;
425425
}
426426

427+
static int test_puzzle_backwards(int start_node, int dest_node)
428+
{
429+
deque q = deque_init(sizeof(struct pair));
430+
struct pair cur;
431+
cur.cur_node = start_node;
432+
cur.cur_cost = 0;
433+
assert(deque_is_empty(q));
434+
deque_push_back(q, &cur);
435+
assert(deque_size(q) == 1);
436+
while (!deque_is_empty(q)) {
437+
int node;
438+
int cost;
439+
deque_pop_back(&cur, q);
440+
node = cur.cur_node;
441+
cost = cur.cur_cost;
442+
if (node > 2 * dest_node || node < 1) {
443+
continue;
444+
}
445+
if (node == dest_node) {
446+
deque_destroy(q);
447+
return cost;
448+
}
449+
cur.cur_cost = cost + 1;
450+
cur.cur_node = node - 1;
451+
deque_push_front(q, &cur);
452+
assert(cur.cur_cost == cost + 1);
453+
assert(cur.cur_node == node - 1);
454+
cur.cur_node = 2 * node;
455+
deque_push_front(q, &cur);
456+
assert(cur.cur_cost == cost + 1);
457+
assert(cur.cur_node == 2 * node);
458+
}
459+
deque_destroy(q);
460+
return -1;
461+
}
462+
427463
struct big_object {
428464
int n;
429465
double d;
@@ -624,8 +660,12 @@ void test_deque(void)
624660
test_clear_out_of_memory();
625661
#endif
626662
test_single_full_block();
627-
assert(test_puzzle(2, 5) == 4);
628-
assert(test_puzzle(2, 10) == 5);
663+
assert(test_puzzle_forwards(2, 5) == 4);
664+
assert(test_puzzle_forwards(2, 10) == 5);
665+
assert(test_puzzle_forwards(100, 1000) == 42);
666+
assert(test_puzzle_backwards(2, 5) == 4);
667+
assert(test_puzzle_backwards(2, 10) == 5);
668+
assert(test_puzzle_backwards(100, 1000) == 42);
629669
test_big_object();
630670
for (i = 1; i < 6000; i++) {
631671
test_add_all(i);

0 commit comments

Comments
 (0)