err_t _deque_reallocate_map(const ssize_t item_size, const ssize_t buf_size, deque_t* d, ssize_t nodes_to_add, char add_at_front) { const ssize_t old_num_nodes = d->finish.node - d->start.node + 1; const ssize_t new_num_nodes = old_num_nodes + nodes_to_add; deque_node_t* new_nstart; if( d->map_size > 2 * new_num_nodes ) { new_nstart = d->map + (d->map_size - new_num_nodes) / 2 + (add_at_front ? nodes_to_add : 0 ); if( new_nstart < d->start.node ) { // copy from d->start.node to d->finish.node + 1 to new_nstart _deque_map_copy_forward(d->start.node, d->finish.node + 1, new_nstart); } else { // copy backward from d->start.node to d->finish.node + 1 to new_nstart + old_num_nodes elements _deque_map_copy_backward(d->start.node, d->finish.node + 1, new_nstart + old_num_nodes); } } else { ssize_t new_map_size = d->map_size + _DEQUE_MAX(d->map_size, nodes_to_add) + 2; deque_node_t* new_map = (deque_node_t*) deque_calloc(new_map_size, sizeof(deque_node_t)); if( ! new_map ) return ENOMEM; new_nstart = new_map + (new_map_size - new_num_nodes ) / 2 + (add_at_front ? nodes_to_add : 0 ); // copy from d->start.node to d->finish.node + 1 to new_nstart _deque_map_copy_forward(d->start.node, d->finish.node + 1, new_nstart); deque_free(d->map); d->map = new_map; d->map_size = new_map_size; } _deque_set_node(item_size, buf_size, & d->start, new_nstart); _deque_set_node(item_size, buf_size, & d->finish, new_nstart + old_num_nodes - 1); return 0; }
void test_reallocate(void) { // hit the different reallocate cases. // map_size > 2* num_new_nodes // add to front, add to back { // start with copy forward/copy backward. deque_node_t nodes[4]; nodes[0].data = (void*) 0x100; nodes[1].data = (void*) 0x101; nodes[2].data = (void*) 0x102; nodes[3].data = (void*) 0x103; // test overlapping copy forward. // dstBeg should be before srcBegin _deque_map_copy_forward( &nodes[2], &nodes[4], &nodes[1]); assert(nodes[0].data == (void*) 0x100); assert(nodes[1].data == (void*) 0x102); assert(nodes[2].data == (void*) 0x103); assert(nodes[3].data == (void*) 0x103); nodes[0].data = (void*) 0x100; nodes[1].data = (void*) 0x101; nodes[2].data = (void*) 0x102; nodes[3].data = (void*) 0x103; // test overlapping copy backward. // dstEnd should be after srcEnd _deque_map_copy_backward( &nodes[0], &nodes[2], &nodes[3]); assert(nodes[0].data == (void*) 0x100); assert(nodes[1].data == (void*) 0x100); assert(nodes[2].data == (void*) 0x101); assert(nodes[3].data == (void*) 0x103); } // Now, suppose we've allocated our stuff... // let's reallocate. { deque_t d; qioerr err; ssize_t saved_size; deque_node_t saved_nodes[2*_DEQUE_INITIAL_MAP_SIZE]; deque_node_t* cur; int i; // this time, try with map_size < 2*num_new_nodes err = deque_init(16, &d, 16*_DEQUE_INITIAL_MAP_SIZE); assert(!err); // save the pointers. assert(d.map_size < 2*_DEQUE_INITIAL_MAP_SIZE);// fits in test buffer saved_size = 0; for( cur = d.start.node; cur < d.finish.node; ++cur ) { saved_nodes[saved_size++].data = cur->data; } _deque_reallocate_map(16, 512, /* first two args dont matter in this test*/ &d, 1, 0 /* not at front */); assert(d.map_size > saved_size); // make sure it grew i = 0; for( cur = d.start.node; cur < d.finish.node && i < saved_size; ++cur ) { assert(saved_nodes[i++].data == cur->data); } // don't care value of nodes[saved_size], the new slot. deque_destroy(&d); err = deque_init(16, &d, 16*_DEQUE_INITIAL_MAP_SIZE); assert(!err); assert(d.map_size < 2*_DEQUE_INITIAL_MAP_SIZE);// fits in test buffer saved_size = 0; for( cur = d.start.node; cur < d.finish.node; ++cur ) { saved_nodes[saved_size++].data = cur->data; } _deque_reallocate_map(16, 512, /* first two args dont matter in this test*/ &d, 1, 1 /* at front */); assert(d.map_size > saved_size); // make sure it grew // don't care value of nodes[0], the new slot. i = 0; for( cur = d.start.node; cur < d.finish.node && i < saved_size ; ++cur ) { assert(saved_nodes[i++].data == cur->data); } // don't care of value of nodes[saved_size+1], the previous new slot. deque_destroy(&d); // this time, try with map_size > 2*num_new_nodes err = deque_init(16, &d, 0); assert(!err); // save the pointers. assert(d.map_size < 2*_DEQUE_INITIAL_MAP_SIZE);// fits in test buffer saved_size = 0; for( cur = d.start.node; cur < d.finish.node; ++cur ) { saved_nodes[saved_size++].data = cur->data; } _deque_reallocate_map(16, 512, /* first two args dont matter in this test*/ &d, 1, 0 /* not at front */); i = 0; for( cur = d.start.node; cur < d.finish.node; ++cur ) { assert(saved_nodes[i++].data == cur->data); } assert( i == saved_size ); deque_destroy(&d); err = deque_init(16, &d, 0); assert(!err); // save the pointers. assert(d.map_size < 2*_DEQUE_INITIAL_MAP_SIZE);// fits in test buffer saved_size = 0; for( cur = d.start.node; cur < d.finish.node; ++cur ) { saved_nodes[saved_size++].data = cur->data; } _deque_reallocate_map(16, 512, /* first two args dont matter in this test*/ &d, 1, 1 /* at front */); i = 0; for( cur = d.start.node; cur < d.finish.node; ++cur ) { assert(saved_nodes[i++].data == cur->data); } assert( i == saved_size ); deque_destroy(&d); } }