static void bl_remove_from_node(bl* list, bl_node* node, bl_node* prev, int index_in_node) { // if we're removing the last element at this node, then // remove this node from the linked list. if (node->N == 1) { // if we're removing the first node... if (prev == NULL) { list->head = node->next; // if it's the first and only node... if (list->head == NULL) { list->tail = NULL; } } else { // if we're removing the last element from // the tail node... if (node == list->tail) { list->tail = prev; } prev->next = node->next; } bl_free_node(node); } else { int ncopy; // just remove this element... ncopy = node->N - index_in_node - 1; if (ncopy > 0) { memmove(NODE_CHARDATA(node) + index_in_node * list->datasize, NODE_CHARDATA(node) + (index_in_node+1) * list->datasize, ncopy * list->datasize); } node->N--; } list->N--; }
void bl_split(bl* src, bl* dest, int split) { bl_node* node; int nskipped; int ind; int ntaken = src->N - split; node = find_node(src, split, &nskipped); ind = split - nskipped; if (ind == 0) { // this whole node belongs to "dest". if (split) { // we need to get the previous node... bl_node* last = find_node(src, split-1, NULL); last->next = NULL; src->tail = last; } else { // we've removed everything from "src". src->head = NULL; src->tail = NULL; } } else { // create a new node to hold the second half of the items in "node". bl_node* newnode = bl_new_node(dest); newnode->N = (node->N - ind); newnode->next = node->next; memcpy(NODE_CHARDATA(newnode), NODE_CHARDATA(node) + (ind * src->datasize), newnode->N * src->datasize); node->N -= (node->N - ind); node->next = NULL; src->tail = node; // to make the code outside this block work... node = newnode; } // append it to "dest". if (dest->tail) { dest->tail->next = node; dest->N += ntaken; } else { dest->head = node; dest->tail = node; dest->N += ntaken; } // adjust "src". src->N -= ntaken; src->last_access = NULL; }
void bl_copy(bl* list, int start, int length, void* vdest) { bl_node* node; int nskipped; char* dest; if (length <= 0) return; node = find_node(list, start, &nskipped); // we've found the node containing "start". keep copying elements and // moving down the list until we've copied all "length" elements. dest = vdest; while (length > 0) { int take, avail; char* src; // number of elements we want to take. take = length; // number of elements available at this node. avail = node->N - (start - nskipped); if (take > avail) take = avail; src = NODE_CHARDATA(node) + (start - nskipped) * list->datasize; memcpy(dest, src, take * list->datasize); dest += take * list->datasize; start += take; length -= take; nskipped += node->N; node = node->next; } // update the last_access member... list->last_access = node; list->last_access_n = nskipped; }
void* bl_access_const(const bl* list, int n) { bl_node* node; int nskipped; node = find_node(list, n, &nskipped); // grab the element. return NODE_CHARDATA(node) + (n - nskipped) * list->datasize; }
void bl_set(bl* list, int index, const void* data) { bl_node* node; int nskipped; void* dataloc; node = find_node(list, index, &nskipped); dataloc = NODE_CHARDATA(node) + (index - nskipped) * list->datasize; memcpy(dataloc, data, list->datasize); // update the last_access member... list->last_access = node; list->last_access_n = nskipped; }
void bl_reverse(bl* list) { // reverse each block, and reverse the order of the blocks. pl* blocks; bl_node* node; bl_node* lastnode; int i; // reverse each block blocks = pl_new(256); for (node=list->head; node; node=node->next) { for (i=0; i<(node->N/2); i++) { memswap(NODE_CHARDATA(node) + i * list->datasize, NODE_CHARDATA(node) + (node->N - 1 - i) * list->datasize, list->datasize); } pl_append(blocks, node); } // reverse the blocks lastnode = NULL; for (i=pl_size(blocks)-1; i>=0; i--) { node = pl_get(blocks, i); if (lastnode) lastnode->next = node; lastnode = node; } if (lastnode) lastnode->next = NULL; pl_free(blocks); // swap head and tail node = list->head; list->head = list->tail; list->tail = node; list->last_access = NULL; list->last_access_n = 0; }
/* * Append an item to this bl node. If this node is full, then create a new * node and insert it into the list. * * Returns the location where the new item was copied. */ void* bl_node_append(bl* list, bl_node* node, const void* data) { void* dest; if (node->N == list->blocksize) { // create a new node and insert it after the current node. bl_node* newnode; newnode = bl_new_node(list); newnode->next = node->next; node->next = newnode; if (list->tail == node) list->tail = newnode; node = newnode; } // space remains at this node. add item. dest = NODE_CHARDATA(node) + node->N * list->datasize; if (data) memcpy(dest, data, list->datasize); node->N++; list->N++; return dest; }
static Pure void* get_element(bt* tree, bt_leaf* leaf, int index) { return NODE_CHARDATA(leaf) + index * tree->datasize; }
/** * Insert the element "data" into the list, such that its index is "index". * All elements that previously had indices "index" and above are moved * one position to the right. */ void bl_insert(bl* list, int index, const void* data) { bl_node* node; int nskipped; if (list->N == index) { bl_append(list, data); return; } node = find_node(list, index, &nskipped); list->last_access = node; list->last_access_n = nskipped; // if the node is full: // if we're inserting at the end of this node, then create a new node. // else, shift all but the last element, add in this element, and // add the last element to a new node. if (node->N == list->blocksize) { int localindex, nshift; bl_node* next = node->next; bl_node* destnode; localindex = index - nskipped; // if the next node exists and is not full, then insert the overflowing // element at the front. otherwise, create a new node. if (next && (next->N < list->blocksize)) { // shift the existing elements up by one position... memmove(NODE_CHARDATA(next) + list->datasize, NODE_CHARDATA(next), next->N * list->datasize); destnode = next; } else { // create and insert a new node. bl_node* newnode = bl_new_node(list); newnode->next = next; node->next = newnode; if (!newnode->next) list->tail = newnode; destnode = newnode; } if (localindex == node->N) { // the new element becomes the first element in the destination node. memcpy(NODE_CHARDATA(destnode), data, list->datasize); } else { // the last element in this node is added to the destination node. memcpy(NODE_CHARDATA(destnode), NODE_CHARDATA(node) + (node->N-1)*list->datasize, list->datasize); // shift the end portion of this node up by one... nshift = node->N - localindex - 1; memmove(NODE_CHARDATA(node) + (localindex+1) * list->datasize, NODE_CHARDATA(node) + localindex * list->datasize, nshift * list->datasize); // insert the new element... memcpy(NODE_CHARDATA(node) + localindex * list->datasize, data, list->datasize); } destnode->N++; list->N++; } else { // shift... int localindex, nshift; localindex = index - nskipped; nshift = node->N - localindex; memmove(NODE_CHARDATA(node) + (localindex+1) * list->datasize, NODE_CHARDATA(node) + localindex * list->datasize, nshift * list->datasize); // insert... memcpy(NODE_CHARDATA(node) + localindex * list->datasize, data, list->datasize); node->N++; list->N++; } }
void bl_remove_index_range(bl* list, int start, int length) { // find the node (and previous node) at which element 'start' // can be found. bl_node *node, *prev; int nskipped = 0; list->last_access = NULL; list->last_access_n = 0; for (node=list->head, prev=NULL; node; prev=node, node=node->next) { if (start < (nskipped + node->N)) break; nskipped += node->N; } // begin by removing any indices that are at the end of a block. if (start > nskipped) { // we're not removing everything at this node. int istart; int n; istart = start - nskipped; if ((istart + length) < node->N) { // we're removing a chunk of elements from the middle of this // block. move elements from the end into the removed chunk. memmove(NODE_CHARDATA(node) + istart * list->datasize, NODE_CHARDATA(node) + (istart + length) * list->datasize, (node->N - (istart + length)) * list->datasize); // we're done! node->N -= length; list->N -= length; return; } else { // we're removing everything from 'istart' to the end of this // block. just change the "N" values. n = (node->N - istart); node->N -= n; list->N -= n; length -= n; start += n; nskipped = start; prev = node; node = node->next; } } // remove complete blocks. for (;;) { int n; bl_node* todelete; if (length == 0 || length < node->N) break; // we're skipping this whole block. n = node->N; length -= n; start += n; list->N -= n; nskipped += n; todelete = node; node = node->next; bl_free_node(todelete); } if (prev) prev->next = node; else list->head = node; if (!node) list->tail = prev; // remove indices from the beginning of the last block. // note that we may have removed everything from the tail of the list, // no "node" may be null. if (node && length>0) { //printf("removing %i from end.\n", length); memmove(NODE_CHARDATA(node), NODE_CHARDATA(node) + length * list->datasize, (node->N - length) * list->datasize); node->N -= length; list->N -= length; } }
static void bl_sort_rec(bl* list, void* pivot, int (*compare)(const void* v1, const void* v2, void* userdata), void* userdata) { bl* less; bl* equal; bl* greater; int i; bl_node* node; // Empty case if (!list->head) return; // Base case: list with only one block. if (list->head == list->tail) { bl_node* node; struct funcandtoken ft; ft.compare = compare; ft.userdata = userdata; node = list->head; QSORT_R(NODE_DATA(node), node->N, list->datasize, &ft, qcompare); return; } less = bl_new(list->blocksize, list->datasize); equal = bl_new(list->blocksize, list->datasize); greater = bl_new(list->blocksize, list->datasize); for (node=list->head; node; node=node->next) { char* data = NODE_CHARDATA(node); for (i=0; i<node->N; i++) { int val = compare(data, pivot, userdata); if (val < 0) bl_append(less, data); else if (val > 0) bl_append(greater, data); else bl_append(equal, data); data += list->datasize; } } // recurse before freeing anything... bl_sort_with_userdata(less, compare, userdata); bl_sort_with_userdata(greater, compare, userdata); for (node=list->head; node;) { bl_node* next; next = node->next; bl_free_node(node); node = next; } list->head = NULL; list->tail = NULL; list->N = 0; list->last_access = NULL; list->last_access_n = 0; if (less->N) { list->head = less->head; list->tail = less->tail; list->N = less->N; } if (equal->N) { if (list->N) { list->tail->next = equal->head; list->tail = equal->tail; } else { list->head = equal->head; list->tail = equal->tail; } list->N += equal->N; } if (greater->N) { if (list->N) { list->tail->next = greater->head; list->tail = greater->tail; } else { list->head = greater->head; list->tail = greater->tail; } list->N += greater->N; } // note, these are supposed to be "free", not "bl_free"; we've stolen // the blocks, we're just freeing the headers. free(less); free(equal); free(greater); }