22#include <stdint.h>
33#include <assert.h>
44#include <stdio.h>
5+ #include <math.h>
56
67static PyObject * PackIndexFile_sha_to_index (PyObject * self , PyObject * args )
78{
@@ -87,7 +88,6 @@ static PyObject *PackIndexFile_sha_to_index(PyObject *self, PyObject *args)
8788typedef unsigned long long ull ;
8889typedef unsigned int uint ;
8990
90-
9191// DELTA CHUNK
9292////////////////
9393// Internal Delta Chunk Objects
@@ -142,13 +142,17 @@ int DCV_grow(DeltaChunkVector* vec, uint num_dc)
142142 }
143143
144144 if (vec -> mem == NULL ){
145- vec -> mem = PyMem_Malloc (grow_by_chunks * sizeof (vec -> mem ));
145+ vec -> mem = PyMem_Malloc (grow_by_chunks * sizeof (DeltaChunk ));
146146 } else {
147- vec -> mem = PyMem_Realloc (vec -> mem , (vec -> reserved_size + grow_by_chunks ) * sizeof (vec -> mem ));
147+ vec -> mem = PyMem_Realloc (vec -> mem , (vec -> reserved_size + grow_by_chunks ) * sizeof (DeltaChunk ));
148148 }
149149 assert (vec -> mem != NULL );
150150 vec -> reserved_size = vec -> reserved_size + grow_by_chunks ;
151151
152+ #ifdef DEBUG
153+ fprintf (stderr , "Allocated %i bytes at %p, to hold up to %i chunks\n" , (int )((vec -> reserved_size + grow_by_chunks ) * sizeof (DeltaChunk )), vec -> mem , (int )(vec -> reserved_size + grow_by_chunks ));
154+ #endif
155+
152156 return vec -> mem != NULL ;
153157}
154158
@@ -192,7 +196,11 @@ DeltaChunk* DCV_end(DeltaChunkVector* vec)
192196void DCV_dealloc (DeltaChunkVector * vec )
193197{
194198 if (vec -> mem ){
195- const DeltaChunk * end = DCV_end (vec );
199+ #ifdef DEBUG
200+ fprintf (stderr , "Freeing %p\n" , (void * )vec -> mem );
201+ #endif
202+
203+ const DeltaChunk * end = & vec -> mem [vec -> size ];
196204 DeltaChunk * i ;
197205 for (i = vec -> mem ; i < end ; i ++ ){
198206 DC_destroy (i );
@@ -342,6 +350,7 @@ DeltaChunkList* DCL_new_instance(void)
342350
343351 DCL_init (dcl , 0 , 0 );
344352 assert (dcl -> vec .size == 0 );
353+ assert (dcl -> vec .mem == NULL );
345354 return dcl ;
346355}
347356
@@ -377,16 +386,13 @@ static PyObject* connect_deltas(PyObject *self, PyObject *dstreams)
377386 stream_iter = dstreams ;
378387 }
379388
380- DeltaChunkList * bdcl = 0 ;
381- DeltaChunkList * tdcl = 0 ;
382- DeltaChunkList * dcl = 0 ;
389+ DeltaChunkVector bdcv ;
390+ DeltaChunkVector tdcv ;
391+ DeltaChunkVector dcv ;
392+ DCV_init (& bdcv , 0 );
393+ DCV_init (& dcv , 0 );
394+ DCV_init (& tdcv , 0 );
383395
384- dcl = tdcl = DCL_new_instance ();
385- assert (dcl != NULL );
386- if (!dcl ){
387- PyErr_SetString (PyExc_RuntimeError , "Couldn't allocate list" );
388- return NULL ;
389- }
390396
391397 unsigned int dsi ;
392398 PyObject * ds ;
@@ -408,6 +414,10 @@ static PyObject* connect_deltas(PyObject *self, PyObject *dstreams)
408414 Py_ssize_t ofs = 0 ;
409415 const ull base_size = msb_size (data , dlen , 0 , & ofs );
410416 const ull target_size = msb_size (data , dlen , ofs , & ofs );
417+
418+ // estimate number of ops - assume one third adds, half two byte (size+offset) copies
419+ const uint approx_num_cmds = (dlen / 3 ) + (((dlen / 3 ) * 2 ) / (2 + 2 + 1 ));
420+ DCV_grow (& dcv , approx_num_cmds );
411421
412422 // parse command stream
413423 const char * dend = data + dlen ;
@@ -431,7 +441,7 @@ static PyObject* connect_deltas(PyObject *self, PyObject *dstreams)
431441 const unsigned long rbound = cp_off + cp_size ;
432442 if (rbound < cp_size ||
433443 rbound > base_size ){
434- goto loop_end ;
444+ break ;
435445 }
436446
437447 // TODO: Add node
@@ -446,8 +456,19 @@ static PyObject* connect_deltas(PyObject *self, PyObject *dstreams)
446456 goto loop_end ;
447457 }
448458 }// END handle command opcodes
449-
450459 assert (tbw == target_size );
460+
461+ // swap the vector
462+ // Skip the first vector, as it is also used as top chunk vector
463+ if (bdcv .mem != tdcv .mem ){
464+ DCV_dealloc (& bdcv );
465+ }
466+ bdcv = dcv ;
467+ if (dsi == 0 ){
468+ tdcv = dcv ;
469+ }
470+ DCV_init (& dcv , 0 );
471+
451472
452473loop_end :
453474 // perform cleanup
@@ -467,11 +488,31 @@ static PyObject* connect_deltas(PyObject *self, PyObject *dstreams)
467488 Py_DECREF (stream_iter );
468489 }
469490
491+ DCV_dealloc (& bdcv );
492+ if (dsi > 1 ){
493+ // otherwise dcv equals tcl
494+ DCV_dealloc (& dcv );
495+ }
496+
497+ // Return the actual python object - its just a container
498+ DeltaChunkList * dcl = DCL_new_instance ();
499+ if (!dcl ){
500+ PyErr_SetString (PyExc_RuntimeError , "Couldn't allocate list" );
501+ // Otherwise tdcv would be deallocated by the chunk list
502+ DCV_dealloc (& tdcv );
503+ error = 1 ;
504+ } else {
505+ // Plain copy, don't deallocate
506+ dcl -> vec = tdcv ;
507+ }
508+
470509 if (error ){
510+ // Will dealloc tdcv
511+ Py_XDECREF (dcl );
471512 return NULL ;
472513 }
473514
474- return (PyObject * )tdcl ;
515+ return (PyObject * )dcl ;
475516}
476517
477518static PyMethodDef py_fun [] = {
0 commit comments