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 ); }
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; }
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; }