static value_t List_push( 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 head chunk has space remaining, push this value onto it. If the // chunk is full, we will push it onto the cold storage list and create a // new, one-element chunk for the new value, which becomes our head chunk. // This way the cold storage is a list of chunks, not a list of values. if (!chunk_can_grow( head_chunk )) { // Pushing a chunk onto cold storage is a potentially O(log n) // operation, as is popping a chunk. Therefore instead of pushing the // whole chunk, we will push only the last three elements. Our new // head chunk will include the new value and the previous head. This // way, an inexpensive pop always follows an expensive push, and vice // versa, which is how we get amortized O(1) performance. value_t pushable = chunk_pop( zone, head_chunk ); cold_storage = METHOD_1( cold_storage, sym_push, pushable ); head_chunk = chunk_alloc_1( zone, chunk_head( head_chunk ) ); } // Push the new value onto our head chunk, which may or may not have been // freshly created for the purpose. head_chunk = chunk_push( zone, head_chunk, value ); return alloc_list( zone, head_chunk, cold_storage, tail_chunk ); }
/** @brief Copy to file and save to chunk. */ static int copy_save(void *arg_, const char *data, size_t len) { s_copy_save *arg = arg_; if (arg->copy && file_write(arg->file, data, len)) return -1; if (arg->save && chunk_push(arg->save, data, len)) return -1; return 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; }
void forward_push_term( forward_t *f, uint32_t term ) { chunk_push( &f->chunk, term ); }