Beispiel #1
0
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--;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
}
Beispiel #7
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;
}
Beispiel #8
0
static Pure void* get_element(bt* tree, bt_leaf* leaf, int index) {
    return NODE_CHARDATA(leaf) + index * tree->datasize;
}
Beispiel #9
0
/**
 * 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++;
	}
}
Beispiel #10
0
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;
	}
}
Beispiel #11
0
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);
}