Exemplo n.º 1
0
static value_t List_append( PREFUNC, value_t listObj, value_t value )
{
	ARGCHECK_2( listObj, value );
	value_t head_chunk = listObj->slots[LIST_HEAD_CHUNK_SLOT];
	value_t cold_storage = listObj->slots[LIST_COLD_STORAGE_SLOT];
	value_t tail_chunk = listObj->slots[LIST_TAIL_CHUNK_SLOT];

	// If our tail chunk has space remaining, append this value to it. If the
	// chunk is full, we will append it to the cold storage list, then create
	// a new, one-element chunk for our tail.
	if (!chunk_can_grow( tail_chunk)) {
		// Following the same amortization logic as our push operation, we will
		// not append the entire full chunk, but only the first three elements.
		// The current tail value will remain on the tail chunk, along with the
		// value we are about to append. This way we always follow an expensive
		// operation with a cheap one, which gives us the amortized O(1)
		// performance which is the whole point of using a finger tree.
		value_t appendable = chunk_chop( zone, tail_chunk );
		cold_storage = METHOD_1( cold_storage, sym_append, appendable );
		tail_chunk = chunk_alloc_1( zone, chunk_tail( zone, tail_chunk ) );	
	}
	tail_chunk = chunk_append( zone, tail_chunk, value );

	return alloc_list( zone, head_chunk, cold_storage, tail_chunk );
}
Exemplo n.º 2
0
unsigned read_chunk(FILE *source, Chunk *chunk, long MAX_CHUNK_SIZE) {
    int buf;
    chunk_init(chunk, ftell(source));
    while (chunk->length < MIN_CHUNK_SIZE) {
        if ((buf = fgetc(source))==EOF)
            return (chunk->length > 0);
        chunk_append(chunk, (char)buf);
    }
    while ((~(chunk_digest(chunk)) & MATCHMASK) || (chunk->length < MIN_CHUNK_SIZE)) {
        if ((buf = fgetc(source))==EOF)
            return (chunk->length > 0); //No more if this chunk has nothing
        chunk_append(chunk, (char)buf);
        if (chunk->length >= MAX_CHUNK_SIZE)
            return 1; //Chunk has data, but it's too big to take more
    }
    return 1;
}
Exemplo n.º 3
0
static value_t List_concatenate(
		PREFUNC, value_t listObj, value_t otherList )
{
	ARGCHECK_2( listObj, otherList );
	// If the list to be concatenated is also a multi-item list, we will do an
	// efficient concatenation by taking advantage of our knowledge of its
	// internal structure. Otherwise, we will hope it is a sequence and append
	// each of its items.
	if (otherList->function == (function_t)List_function) {
		value_t ourHeadChunk = listObj->slots[LIST_HEAD_CHUNK_SLOT];
		value_t ourColdStorage = listObj->slots[LIST_COLD_STORAGE_SLOT];
		value_t ourTailChunk = listObj->slots[LIST_TAIL_CHUNK_SLOT];
		value_t otherHeadChunk = otherList->slots[LIST_HEAD_CHUNK_SLOT];
		value_t otherColdStorage = otherList->slots[LIST_COLD_STORAGE_SLOT];
		value_t otherTailChunk = otherList->slots[LIST_TAIL_CHUNK_SLOT];
		// We need to put these chunks into cold storage somehow. There are
		// enough possibilities that it would be tedious to do it all with if-
		// statements. Instead, we have this matrix, which will map each of the
		// sixteen possible combinations down to one of six actions. The
		// horizontal axis represents the size of the other list's head chunk;
		// the vertical axis represents the size of our list's tail chunk.
		int actions[4][4] = {
			{0, 1, 2, 2},
			{0, 4, 4, 2},
			{3, 4, 4, 5},
			{3, 3, 5, 5}};
		int x_size = chunk_item_count(otherHeadChunk);
		int y_size = chunk_item_count(ourTailChunk);
		switch(actions[y_size][x_size]) {
			case 0: {
				// Append other chunk's head to our chunk. Append our chunk to
				// our cold storage; let the other chunk drop.
				value_t item = chunk_head( otherHeadChunk );
				ourTailChunk = chunk_append( zone, ourTailChunk, item );
				ourColdStorage = 
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
			} break;
			case 1: {
				// Push our chunk's tail onto the other chunk. Push the other
				// chunk onto its cold storage, then let ours drop.
				value_t item = chunk_tail( zone, ourTailChunk );
				otherHeadChunk = chunk_push( zone, otherHeadChunk, item );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
			} break;
			case 2: {
				// Append other chunk's head to our chunk. Append our chunk to
				// our cold storage and push the other chunk onto its.
				value_t item = chunk_head( otherHeadChunk );
				otherHeadChunk = chunk_pop( zone, otherHeadChunk );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
				ourTailChunk = chunk_append( zone, ourTailChunk, item );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
			} break;
			case 3: {
				// Push our chunk's tail onto the other chunk. Put each chunk
				// into its own cold storage.
				value_t item = chunk_tail( zone, ourTailChunk );
				ourTailChunk = chunk_chop( zone, ourTailChunk );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
				otherHeadChunk = chunk_push( zone, otherHeadChunk, item );
				otherColdStorage = 
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
			} break;
			case 4: {
				// Put each chunk into its own cold storage.
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );
			} break;
			case 5: {
				// Split one item off of each chunk to create a new middle
				// chunk. Put each original chunk onto its own list, then add
				// the middle chunk to our cold storage.
				value_t item = chunk_tail( zone, ourTailChunk );
				ourTailChunk = chunk_chop( zone, ourTailChunk );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, ourTailChunk );

				value_t midChunk = chunk_alloc_1( zone, item );
				item = chunk_head( otherHeadChunk );
				otherHeadChunk = chunk_pop( zone, otherHeadChunk );
				otherColdStorage =
					METHOD_1( otherColdStorage, sym_push, otherHeadChunk );

				midChunk = chunk_append( zone, midChunk, item );
				ourColdStorage =
					METHOD_1( ourColdStorage, sym_append, midChunk );
			} break;
		}
		// Having dealt with the active chunks, we now have a head chunk for
		// the whole list, a tail chunk for the whole list, and two cold
		// storage lists. We will recursively concatenate the cold storage
		// lists, then assemble our output list from these pieces.
		value_t combined_storage =
			METHOD_1( ourColdStorage, sym_concatenate, otherColdStorage );
		listObj = alloc_list(
				zone, ourHeadChunk, combined_storage, otherTailChunk );
	}
	else {
		value_t iter = METHOD_0( otherList, sym_iterate );
		if (IsAnException( iter )) return iter;
		while (BoolFromBoolean( zone, METHOD_0( iter, sym_is_valid ) )) {
			value_t val = METHOD_0( iter, sym_current );
			listObj = METHOD_1( listObj, sym_append, val );
			iter = METHOD_0( iter, sym_next );
		}
	}
	return listObj;
}