@@ -84,6 +84,26 @@ def _move_delta_lbound(d, bytes):
8484
8585def delta_duplicate (src ):
8686 return DeltaChunk (src .to , src .ts , src .so , src .data )
87+
88+ def delta_chunk_apply (dc , bbuf , write ):
89+ """Apply own data to the target buffer
90+ :param bbuf: buffer providing source bytes for copy operations
91+ :param write: write method to call with data to write"""
92+ if dc .data is None :
93+ # COPY DATA FROM SOURCE
94+ write (buffer (bbuf , dc .so , dc .ts ))
95+ elif isinstance (dc .data , DeltaChunkList ):
96+ delta_list_apply (dc .data , bbuf , write , dc .so , dc .ts )
97+ else :
98+ # APPEND DATA
99+ # whats faster: if + 4 function calls or just a write with a slice ?
100+ # Considering data can be larger than 127 bytes now, it should be worth it
101+ if dc .ts < len (dc .data ):
102+ write (dc .data [:dc .ts ])
103+ else :
104+ write (dc .data )
105+ # END handle truncation
106+ # END handle chunk mode
87107
88108class DeltaChunk (object ):
89109 """Represents a piece of a delta, it can either add new data, or copy existing
@@ -136,25 +156,7 @@ def set_copy_chunklist(self, dcl):
136156 self .data = dcl
137157 self .so = 0 # allows lbound moves to be virtual
138158
139- def apply (self , bbuf , write ):
140- """Apply own data to the target buffer
141- :param bbuf: buffer providing source bytes for copy operations
142- :param write: write method to call with data to write"""
143- if self .data is None :
144- # COPY DATA FROM SOURCE
145- write (buffer (bbuf , self .so , self .ts ))
146- elif isinstance (self .data , DeltaChunkList ):
147- self .data .apply (bbuf , write , self .so , self .ts )
148- else :
149- # APPEND DATA
150- # whats faster: if + 4 function calls or just a write with a slice ?
151- # Considering data can be larger than 127 bytes now, it should be worth it
152- if self .ts < len (self .data ):
153- write (self .data [:self .ts ])
154- else :
155- write (self .data )
156- # END handle truncation
157- # END handle chunk mode
159+
158160
159161 #} END interface
160162
@@ -178,6 +180,59 @@ def _closest_index(dcl, absofs):
178180 # END for each delta absofs
179181 return len (dcl )- 1
180182
183+ def delta_list_apply (dcl , bbuf , write , lbound_offset = 0 , size = 0 ):
184+ """Apply the chain's changes and write the final result using the passed
185+ write function.
186+ :param bbuf: base buffer containing the base of all deltas contained in this
187+ list. It will only be used if the chunk in question does not have a base
188+ chain.
189+ :param lbound_offset: offset at which to start applying the delta, relative to
190+ our lbound
191+ :param size: if larger than 0, only the given amount of bytes will be applied
192+ :param write: function taking a string of bytes to write to the output"""
193+ slen = len (dcl )
194+ if slen == 0 :
195+ return
196+ # END early abort
197+ absofs = dcl .lbound () + lbound_offset
198+ if size == 0 :
199+ size = dcl .rbound () - absofs
200+ # END initialize size
201+
202+ if lbound_offset or absofs + size != dcl .rbound ():
203+ cdi = _closest_index (dcl , absofs )
204+ cd = dcl [cdi ]
205+ if cd .to != absofs :
206+ tcd = delta_duplicate (cd )
207+ _move_delta_lbound (tcd , absofs - cd .to )
208+ _set_delta_rbound (tcd , min (tcd .ts , size ))
209+ delta_chunk_apply (tcd , bbuf , write )
210+ size -= tcd .ts
211+ cdi += 1
212+ # END handle first chunk
213+
214+ # here we have to either apply full chunks, or smaller ones, but
215+ # we always start at the chunks target offset
216+ while cdi < slen and size :
217+ cd = dcl [cdi ]
218+ if cd .ts <= size :
219+ delta_chunk_apply (cd , bbuf , write )
220+ size -= cd .ts
221+ else :
222+ tcd = delta_duplicate (cd )
223+ _set_delta_rbound (tcd , size )
224+ delta_chunk_apply (tcd , bbuf , write )
225+ size -= tcd .ts
226+ break
227+ # END handle bytes to apply
228+ cdi += 1
229+ # END handle rest
230+ else :
231+ for dc in dcl :
232+ delta_chunk_apply (dc , bbuf , write )
233+ # END for each dc
234+ # END handle application values
235+
181236
182237class DeltaChunkList (list ):
183238 """List with special functionality to deal with DeltaChunks"""
@@ -211,6 +266,11 @@ def connect_with(self, bdcl):
211266 # END handle overlap
212267 # END for each dc
213268
269+ def apply (self , bbuf , write , lbound_offset = 0 , size = 0 ):
270+ """Only used by public clients, internally we only use the global routines
271+ for performance"""
272+ return delta_list_apply (self , bbuf , write , lbound_offset , size )
273+
214274 def compress (self ):
215275 """Alter the list to reduce the amount of nodes. Currently we concatenate
216276 add-chunks
@@ -255,61 +315,6 @@ def compress(self):
255315 # print "INFO: Reduced delta list len to %f %% of former size" % ((float(len(self)) / slen_orig) * 100)
256316 return self
257317
258- def apply (self , bbuf , write , lbound_offset = 0 , size = 0 ):
259- """Apply the chain's changes and write the final result using the passed
260- write function.
261- :param bbuf: base buffer containing the base of all deltas contained in this
262- list. It will only be used if the chunk in question does not have a base
263- chain.
264- :param lbound_offset: offset at which to start applying the delta, relative to
265- our lbound
266- :param size: if larger than 0, only the given amount of bytes will be applied
267- :param write: function taking a string of bytes to write to the output"""
268- slen = len (self )
269- if slen == 0 :
270- return
271- # END early abort
272- absofs = self .lbound () + lbound_offset
273- if size == 0 :
274- size = self .rbound () - absofs
275- # END initialize size
276-
277- dapply = DeltaChunk .apply
278- if lbound_offset or absofs + size != self .rbound ():
279- cdi = _closest_index (self , absofs )
280- cd = self [cdi ]
281- if cd .to != absofs :
282- tcd = delta_duplicate (cd )
283- _move_delta_lbound (tcd , absofs - cd .to )
284- _set_delta_rbound (tcd , min (tcd .ts , size ))
285- dapply (tcd , bbuf , write )
286- size -= tcd .ts
287- cdi += 1
288- # END handle first chunk
289-
290- # here we have to either apply full chunks, or smaller ones, but
291- # we always start at the chunks target offset
292- while cdi < slen and size :
293- cd = self [cdi ]
294- if cd .ts <= size :
295- dapply (cd , bbuf , write )
296- size -= cd .ts
297- else :
298- tcd = delta_duplicate (cd )
299- _set_delta_rbound (tcd , size )
300- dapply (tcd , bbuf , write )
301- size -= tcd .ts
302- break
303- # END handle bytes to apply
304- cdi += 1
305- # END handle rest
306- assert size == 0
307- else :
308- for dc in self :
309- dapply (dc , bbuf , write )
310- # END for each dc
311- # END handle application values
312-
313318 def check_integrity (self , target_size = - 1 ):
314319 """Verify the list has non-overlapping chunks only, and the total size matches
315320 target_size
@@ -380,7 +385,6 @@ def __getslice__(self, absofs, size):
380385 # END hadle size
381386 cdi += 1
382387 # END for each chunk
383- assert size == 0 , "size was %i" % size
384388
385389 # ndcl.check_integrity()
386390 return ndcl
0 commit comments