@@ -95,7 +95,7 @@ typedef uchar bool;
9595const ull gDVC_grow_by = 50 ;
9696
9797#ifdef DEBUG
98- #define DBG_check (vec ) DCV_dbg_check_integrity(vec)
98+ #define DBG_check (vec ) asser( DCV_dbg_check_integrity(vec) )
9999#else
100100#define DBG_check (vec )
101101#endif
@@ -165,6 +165,26 @@ ull DC_rbound(const DeltaChunk* dc)
165165 return dc -> to + dc -> ts ;
166166}
167167
168+ // Apply
169+ inline
170+ void DC_apply (const DeltaChunk * dc , const uchar * base , PyObject * writer , PyObject * tmpargs )
171+ {
172+ PyObject * buffer = 0 ;
173+ if (dc -> data ){
174+ buffer = PyBuffer_FromMemory ((void * )dc -> data , dc -> ts );
175+ } else {
176+ buffer = PyBuffer_FromMemory ((void * )(base + dc -> so ), dc -> ts );
177+ }
178+
179+ if (PyTuple_SetItem (tmpargs , 0 , buffer )){
180+ assert (0 );
181+ }
182+
183+ // tuple steals reference, and will take care about the deallocation
184+ PyObject_Call (writer , tmpargs , NULL );
185+
186+ }
187+
168188// Copy all data from src to dest, the data pointer will be copied too
169189inline
170190void DC_copy_to (const DeltaChunk * src , DeltaChunk * dest )
@@ -423,9 +443,12 @@ DeltaChunk* DCV_closest_chunk(const DeltaChunkVector* vec, ull ofs)
423443}
424444
425445// Assert the given vector has correct datachunks
426- void DCV_dbg_check_integrity (const DeltaChunkVector * vec )
446+ // return 1 on success
447+ int DCV_dbg_check_integrity (const DeltaChunkVector * vec )
427448{
428- assert (!DCV_empty (vec ));
449+ if (DCV_empty (vec )){
450+ return 0 ;
451+ }
429452 const DeltaChunk * i = vec -> mem ;
430453 const DeltaChunk * end = DCV_end (vec );
431454
@@ -434,18 +457,22 @@ void DCV_dbg_check_integrity(const DeltaChunkVector* vec)
434457 for (; i < end ; i ++ ){
435458 acc_size += i -> ts ;
436459 }
437- assert (acc_size == aparent_size );
460+ if (acc_size != aparent_size )
461+ return 0 ;
438462
439463 if (vec -> size < 2 ){
440- return ;
464+ return 1 ;
441465 }
442466
443467 const DeltaChunk * endm1 = DCV_end (vec ) - 1 ;
444468 for (i = vec -> mem ; i < endm1 ; i ++ ){
445469 const DeltaChunk * n = i + 1 ;
446- assert (DC_rbound (i ) == n -> to );
470+ if (DC_rbound (i ) != n -> to ){
471+ return 0 ;
472+ }
447473 }
448474
475+ return 1 ;
449476}
450477
451478// Write a slice as defined by its absolute offset in bytes and its size into the given
@@ -624,10 +651,41 @@ PyObject* DCL_py_rbound(DeltaChunkList* self)
624651 return PyLong_FromUnsignedLongLong (DCL_rbound (self ));
625652}
626653
654+ // Write using a write function, taking remaining bytes from a base buffer
627655static
628- PyObject * DCL_apply (PyObject * self , PyObject * args )
656+ PyObject * DCL_apply (DeltaChunkList * self , PyObject * args )
629657{
658+ PyObject * pybuf = 0 ;
659+ PyObject * writeproc = 0 ;
660+ if (!PyArg_ParseTuple (args , "OO" , & pybuf , & writeproc )){
661+ PyErr_BadArgument ();
662+ return NULL ;
663+ }
664+
665+ if (!PyObject_CheckReadBuffer (pybuf )){
666+ PyErr_SetString (PyExc_ValueError , "First argument must be a buffer-compatible object, like a string, or a memory map" );
667+ return NULL ;
668+ }
669+
670+ if (!PyCallable_Check (writeproc )){
671+ PyErr_SetString (PyExc_ValueError , "Second argument must be a writer method with signature write(buf)" );
672+ return NULL ;
673+ }
674+
675+ const DeltaChunk * i = self -> vec .mem ;
676+ const DeltaChunk * end = DCV_end (& self -> vec );
677+
678+ const uchar * data ;
679+ Py_ssize_t dlen ;
680+ PyObject_AsReadBuffer (pybuf , (const void * * )& data , & dlen );
681+
682+ PyObject * tmpargs = PyTuple_New (1 );
683+
684+ for (; i < end ; i ++ ){
685+ DC_apply (i , data , writeproc , tmpargs );
686+ }
630687
688+ Py_DECREF (tmpargs );
631689 Py_RETURN_NONE ;
632690}
633691
0 commit comments