@@ -91,6 +91,9 @@ typedef unsigned int uint;
9191typedef unsigned char uchar ;
9292typedef uchar bool ;
9393
94+ // Constants
95+ const ull gDVC_grow_by = 50 ;
96+
9497// DELTA CHUNK
9598////////////////
9699// Internal Delta Chunk Objects
@@ -277,10 +280,17 @@ DeltaChunk* DCV_get(DeltaChunkVector* vec, Py_ssize_t i)
277280 return & vec -> mem [i ];
278281}
279282
283+ // Return last item
284+ inline
285+ DeltaChunk * DCV_last (DeltaChunkVector * vec )
286+ {
287+ return DCV_get (vec , vec -> size - 1 );
288+ }
289+
280290inline
281291ull DCV_rbound (DeltaChunkVector * vec )
282292{
283- return DC_rbound (DCV_get (vec , vec -> size - 1 ));
293+ return DC_rbound (DCV_last (vec ));
284294}
285295
286296inline
@@ -371,14 +381,41 @@ static inline
371381DeltaChunk * DCV_append (DeltaChunkVector * vec )
372382{
373383 if (vec -> size + 1 > vec -> reserved_size ){
374- DCV_grow_by (vec , 1 );
384+ DCV_grow_by (vec , gDVC_grow_by );
375385 }
376386
377387 DeltaChunk * next = vec -> mem + vec -> size ;
378388 vec -> size += 1 ;
379389 return next ;
380390}
381391
392+ // Return delta chunk being closest to the given absolute offset
393+ inline
394+ DeltaChunk * DCV_closest_chunk (DeltaChunkVector * vec , ull ofs )
395+ {
396+ assert (vec -> mem );
397+
398+ ull lo = 0 ;
399+ ull hi = vec -> size ;
400+ ull mid ;
401+ DeltaChunk * dc ;
402+
403+ while (lo < hi )
404+ {
405+ mid = (lo + hi ) / 2 ;
406+ dc = vec -> mem + mid ;
407+ if (dc -> to > ofs ){
408+ hi = mid ;
409+ } else if ((DC_rbound (dc ) > ofs ) | (dc -> to == ofs )) {
410+ return dc ;
411+ } else {
412+ lo = mid + 1 ;
413+ }
414+ }
415+
416+ return DCV_last (vec );
417+ }
418+
382419// Write a slice as defined by its absolute offset in bytes and its size into the given
383420// destination. The individual chunks written will be a deep copy of the source
384421// data chunks
@@ -387,14 +424,67 @@ DeltaChunk* DCV_append(DeltaChunkVector* vec)
387424inline
388425void DCV_copy_slice_to (DeltaChunkVector * src , DeltaChunkVector * dest , ull ofs , ull size )
389426{
427+ assert (DCV_lbound (src ) <= ofs );
428+ assert (DCV_rbound (src ) <= ofs + size );
390429
430+ DeltaChunk * cdc = DCV_closest_chunk (src , ofs );
431+
432+ // partial overlap
433+ if (cdc -> to != ofs ) {
434+ DeltaChunk * destc = DCV_append (dest );
435+ const ull relofs = ofs - cdc -> to ;
436+ DC_offset_copy_to (cdc , destc , relofs , cdc -> ts - relofs < size ? cdc -> ts - relofs : size );
437+ cdc += 1 ;
438+ size -= destc -> ts ;
439+
440+ if (size == 0 ){
441+ return ;
442+ }
443+ }
444+
445+ DeltaChunk * vecend = DCV_end (src );
446+ for ( ;(cdc < vecend ) && size ; ++ cdc )
447+ {
448+ if (cdc -> ts < size ) {
449+ DC_copy_to (cdc , DCV_append (dest ));
450+ size -= cdc -> ts ;
451+ } else {
452+ DC_offset_copy_to (cdc , DCV_append (dest ), 0 , size );
453+ size = 0 ;
454+ break ;
455+ }
456+ }
457+
458+ assert (size == 0 );
391459}
392460
393461
462+ // Insert all chunks in 'from' to 'to', starting at the delta chunk named 'at' which
463+ // originates in to
464+ // 'at' will be replaced by the items to insert ( special purpose )
465+ // 'at' will be properly destroyed, but all items will just be copied bytewise
466+ // using memcpy. Hence from must just forget about them !
467+ inline
468+ void DCV_replace_one_by_many (DeltaChunkVector * from , DeltaChunkVector * to , DeltaChunk * at )
469+ {
470+ assert (from -> size > 1 );
471+
472+ DCV_reserve_memory (to , to -> size + from -> size - 1 ); // -1 because we replace at
473+ DC_destroy (at );
474+ to -> size -= 1 + from -> size ;
475+
476+ // If we are somewhere in the middle, we have to make some space
477+ if (DCV_last (to ) != at ) {
478+ memmove ((void * )at + from -> size , (void * )(at + 1 ), (size_t )(DCV_end (to ) - (at + 1 )));
479+ }
480+
481+ // Finally copy all the items in
482+ memcpy ((void * ) at , (void * )from -> mem , from -> size * sizeof (DeltaChunk ));
483+ }
484+
394485// Take slices of bdcv into the corresponding area of the tdcv, which is the topmost
395486// delta to apply. tmpl is used as temporary space and must be initialzed and destroyed by the
396487// caller
397- static
398488void DCV_connect_with_base (DeltaChunkVector * tdcv , DeltaChunkVector * bdcv , DeltaChunkVector * tmpl )
399489{
400490 DeltaChunk * dc = tdcv -> mem ;
@@ -413,18 +503,20 @@ void DCV_connect_with_base(DeltaChunkVector* tdcv, DeltaChunkVector* bdcv, Delta
413503 // assert(tmpl->size);
414504
415505 // move target bounds
416- DeltaChunk * cdc = tmpl -> mem ;
417- DeltaChunk * cdcend = tmpl -> mem + tmpl -> size ;
506+ DeltaChunk * tdc = tmpl -> mem ;
507+ DeltaChunk * tdcend = tmpl -> mem + tmpl -> size ;
418508 const ull ofs = dc -> to - dc -> so ;
419- for (;cdc < cdcend ; cdc ++ ){
420- cdc -> to += ofs ;
509+ for (;tdc < tdcend ; tdc ++ ){
510+ tdc -> to += ofs ;
421511 }
422512
423- // insert slice into our list, replacing our current chunk
513+ // insert slice into our list
424514 if (tmpl -> size == 1 ){
515+ // Its not data, so destroy is not really required, anyhow ...
516+ DC_destroy (dc );
425517 * dc = * DCV_get (tmpl , 0 );
426518 } else {
427-
519+ DCV_replace_one_by_many ( tmpl , tdcv , dc );
428520 }
429521
430522 // make sure the members will not be deallocated by the list
0 commit comments