size_w sequence::insert_file(const TCHAR *filename, size_w index, bool linkto) { breakopt(); span *sptr = loadspan(filename, true); if(insert(index, (seqchar *)NULL, sptr->length)) { span *empty; span_range oldspan; span_range newspans; if((empty = spanfromindex(index, 0)) == 0) return false; oldspan.append(empty); empty->buffer = sptr->buffer; newspans.append(sptr); swap_spanrange(&oldspan, &newspans); return sptr->length; } return 0; }
bool sequence::injectsnapshot(size_w index, span_desc *desclist, size_t desclen) { span_range oldspan; span_range newspans; span *empty; if((empty = spanfromindex(index, 0)) == 0) return false; // oldspan.append(empty); // build a spanrange to insert for(size_t i = 0; i < desclen; i++) { span *sptr; if((sptr = new span(desclist[i].offset, desclist[i].length, desclist[i].buffer)) == 0) return false; newspans.append(sptr); } swap_spanrange(&oldspan, &newspans); return true; }
// // sequence::erase_worker // bool sequence::erase_worker (size_w index, size_w length, action act) { span *sptr; span_range oldspans; span_range newspans; span_range *event; size_w spanindex; size_w remoffset; size_w removelen; bool append_spanrange; debug("Erasing: idx=%d len=%d\n", index, length); // make sure we stay within the range of the sequence if(length == 0 || length > sequence_length || index > sequence_length - length) return false; // find the span that the deletion starts at if((sptr = spanfromindex(index, &spanindex)) == 0) return false; // work out the offset relative to the start of the *span* remoffset = index - spanindex; removelen = length; // // can we optimize? // // special-case 1: 'forward-delete' // erase+replace operations will pass through here // if(index == spanindex && can_optimize(act, index)) { event = stackback(undostack, act == action_replace ? 1 : 0); event->length += length; append_spanrange = true; if(frag2 != 0) { if(length < frag2->length) { frag2->length -= length; frag2->offset += length; sequence_length -= length; return true; } else { if(act == action_replace) stackback(undostack, 0)->last = frag2->next; removelen -= sptr->length; sptr = sptr->next; deletefromsequence(&frag2); } } } // // special-case 2: 'backward-delete' // only erase operations can pass through here // else if(index + length == spanindex + sptr->length && can_optimize(action_erase, index+length)) { event = undostack.back(); event->length += length; event->index -= length; append_spanrange = false; if(frag1 != 0) { if(length < frag1->length) { frag1->length -= length; frag1->offset += 0; sequence_length -= length; return true; } else { removelen -= frag1->length; deletefromsequence(&frag1); } } } else { append_spanrange = true; frag1 = frag2 = 0; if((event = initundo(index, length, act)) == 0) return false; } // // general-case 2+3 // clearstack(redostack); // does the deletion *start* mid-way through a span? if(remoffset != 0) { // split the span - keep the first "half" newspans.append(new span(sptr->offset, remoffset, sptr->buffer)); frag1 = newspans.first; // have we split a single span into two? // i.e. the deletion is completely within a single span if(remoffset + removelen < sptr->length) { // make a second span for the second half of the split newspans.append(new span( sptr->offset + remoffset + removelen, sptr->length - remoffset - removelen, sptr->buffer) ); frag2 = newspans.last; } removelen -= min(removelen, (sptr->length - remoffset)); // archive the span we are going to replace oldspans.append(sptr); sptr = sptr->next; } // we are now on a proper span boundary, so remove // any further spans that the erase-range encompasses while(removelen > 0 && sptr != tail) { // will the entire span be removed? if(removelen < sptr->length) { // split the span, keeping the last "half" newspans.append(new span( sptr->offset + removelen, sptr->length - removelen, sptr->buffer) ); frag2 = newspans.last; } removelen -= min(removelen, sptr->length); // archive the span we are replacing oldspans.append(sptr); sptr = sptr->next; } // for replace operations, update the undo-event for the // insertion so that it knows about the newly removed spans if(act == action_replace && !oldspans.boundary) stackback(undostack, 0)->last = oldspans.last->next; swap_spanrange(&oldspans, &newspans); sequence_length -= length; if(append_spanrange) event->append(&oldspans); else event->prepend(&oldspans); return true; }
// // sequence::insert_worker // bool sequence::insert_worker (size_w index, const seqchar *buf, size_w length, action act) { span * sptr; size_w spanindex; size_t modbuf_offset; span_range newspans; size_w insoffset; if(index > sequence_length) return false; // find the span that the insertion starts at if((sptr = spanfromindex(index, &spanindex)) == 0) return false; // ensure there is room in the modify buffer... // allocate a new buffer if necessary and then invalidate span cache // to prevent a span using two buffers of data if(!import_buffer(buf, length, &modbuf_offset)) return false; debug("Inserting: idx=%d len=%d %.*s\n", index, length, length, buf); clearstack(redostack); insoffset = index - spanindex; // special-case #1: inserting at the end of a prior insertion, at a span-boundary if(insoffset == 0 && can_optimize(act, index)) { // simply extend the last span's length span_range *event = undostack.back(); sptr->prev->length += length; event->length += length; } // general-case #1: inserting at a span boundary? else if(insoffset == 0) { // // Create a new undo event; because we are inserting at a span // boundary there are no spans to replace, so use a "span boundary" // span_range *oldspans = initundo(index, length, act); oldspans->spanboundary(sptr->prev, sptr); // allocate new span in the modify buffer newspans.append(new span( modbuf_offset, length, modifybuffer_id) ); // link the span into the sequence swap_spanrange(oldspans, &newspans); } // general-case #2: inserting in the middle of a span else { // // Create a new undo event and add the span // that we will be "splitting" in half // span_range *oldspans = initundo(index, length, act); oldspans->append(sptr); // span for the existing data before the insertion newspans.append(new span( sptr->offset, insoffset, sptr->buffer) ); // make a span for the inserted data newspans.append(new span( modbuf_offset, length, modifybuffer_id) ); // span for the existing data after the insertion newspans.append(new span( sptr->offset + insoffset, sptr->length - insoffset, sptr->buffer) ); swap_spanrange(oldspans, &newspans); } sequence_length += length; return true; }