1212
1313import itertools
1414import os
15+ import shutil
1516import sys
1617import tempfile
1718import threading
2829except TypeError :
2930 DEFAULT_SIZE_OF = 16
3031
32+ try :
33+ # Python 2: basestring covers str and unicode
34+ STRING_TYPES = (basestring ,)
35+ except NameError :
36+ # Python 3: str and bytes are separate
37+ STRING_TYPES = (str , bytes )
38+
3139def _size_of (instance ):
3240 """
3341 Returns total size of a given instance / object (in bytes)
3442 """
3543
3644 retval = sys .getsizeof (instance , DEFAULT_SIZE_OF )
3745
38- if isinstance (instance , dict ):
46+ if isinstance (instance , STRING_TYPES ):
47+ return retval
48+ elif isinstance (instance , dict ):
3949 retval += sum (_size_of (_ ) for _ in itertools .chain .from_iterable (instance .items ()))
4050 elif hasattr (instance , "__iter__" ):
4151 retval += sum (_size_of (_ ) for _ in instance if _ != instance )
@@ -58,12 +68,29 @@ class BigArray(list):
5868
5969 >>> _ = BigArray(xrange(100000))
6070 >>> _[20] = 0
71+ >>> _[-1] = 999
6172 >>> _[99999]
62- 99999
73+ 999
74+ >>> _[100000]
75+ Traceback (most recent call last):
76+ ...
77+ IndexError: BigArray index out of range
6378 >>> _ += [0]
79+ >>> sum(_)
80+ 4999850980
81+ >>> _[len(_) // 2] = 17
82+ >>> sum(_)
83+ 4999800997
6484 >>> _[100000]
6585 0
66- >>> _ = _ + [1]
86+ >>> _[0] = [None]
87+ >>> _.index(0)
88+ 20
89+ >>> import pickle; __ = pickle.loads(pickle.dumps(_))
90+ >>> __.append(1)
91+ >>> len(_)
92+ 100001
93+ >>> _ = __
6794 >>> _[-1]
6895 1
6996 >>> len([_ for _ in BigArray(xrange(100000))])
@@ -134,15 +161,23 @@ def index(self, value):
134161 if self [index ] == value :
135162 return index
136163
137- return ValueError , "%s is not in list" % value
164+ raise ValueError ("%s is not in list" % value )
165+
166+ def __reduce__ (self ):
167+ return (self .__class__ , (), self .__getstate__ ())
138168
139169 def close (self ):
140- while self .filenames :
141- filename = self .filenames .pop ()
142- try :
143- self ._os_remove (filename )
144- except OSError :
145- pass
170+ with self ._lock :
171+ while self .filenames :
172+ filename = self .filenames .pop ()
173+ try :
174+ self ._os_remove (filename )
175+ except OSError :
176+ pass
177+ self .chunks = [[]]
178+ self .cache = None
179+ self .chunk_length = getattr (sys , "maxsize" , None )
180+ self ._size_counter = 0
146181
147182 def __del__ (self ):
148183 self .close ()
@@ -181,41 +216,89 @@ def _checkcache(self, index):
181216 raise SqlmapSystemException (errMsg )
182217
183218 def __getstate__ (self ):
184- return self .chunks , self .filenames
219+ if self .cache and self .cache .dirty :
220+ filename = self ._dump (self .cache .data )
221+ self .chunks [self .cache .index ] = filename
222+ self .cache .dirty = False
223+
224+ return self .chunks , self .filenames , self .chunk_length
185225
186226 def __setstate__ (self , state ):
187227 self .__init__ ()
188- self .chunks , self .filenames = state
228+ chunks , filenames , self .chunk_length = state
229+
230+ file_mapping = {}
231+ self .filenames = set ()
232+ self .chunks = []
233+
234+ for filename in filenames :
235+ if not os .path .exists (filename ):
236+ continue
237+
238+ try :
239+ handle , new_filename = tempfile .mkstemp (prefix = MKSTEMP_PREFIX .BIG_ARRAY )
240+ os .close (handle )
241+ shutil .copyfile (filename , new_filename )
242+ self .filenames .add (new_filename )
243+ file_mapping [filename ] = new_filename
244+ except (OSError , IOError ):
245+ pass
246+
247+ for chunk in chunks :
248+ if isinstance (chunk , STRING_TYPES ):
249+ if chunk in file_mapping :
250+ self .chunks .append (file_mapping [chunk ])
251+ else :
252+ errMsg = "exception occurred while restoring BigArray chunk "
253+ errMsg += "from file '%s'" % chunk
254+ raise SqlmapSystemException (errMsg )
255+ else :
256+ self .chunks .append (chunk )
189257
190258 def __getitem__ (self , y ):
191- length = len (self )
192- if length == 0 :
193- raise IndexError ("BigArray index out of range" )
259+ with self ._lock :
260+ length = len (self )
261+ if length == 0 :
262+ raise IndexError ("BigArray index out of range" )
263+
264+ if y < 0 :
265+ y += length
194266
195- while y < 0 :
196- y += length
267+ if y < 0 or y >= length :
268+ raise IndexError ( "BigArray index out of range" )
197269
198- index = y // self .chunk_length
199- offset = y % self .chunk_length
200- chunk = self .chunks [index ]
270+ index = y // self .chunk_length
271+ offset = y % self .chunk_length
272+ chunk = self .chunks [index ]
201273
202- if isinstance (chunk , list ):
203- return chunk [offset ]
204- else :
205- self ._checkcache (index )
206- return self .cache .data [offset ]
274+ if isinstance (chunk , list ):
275+ return chunk [offset ]
276+ else :
277+ self ._checkcache (index )
278+ return self .cache .data [offset ]
207279
208280 def __setitem__ (self , y , value ):
209- index = y // self .chunk_length
210- offset = y % self .chunk_length
211- chunk = self .chunks [index ]
212-
213- if isinstance (chunk , list ):
214- chunk [offset ] = value
215- else :
216- self ._checkcache (index )
217- self .cache .data [offset ] = value
218- self .cache .dirty = True
281+ with self ._lock :
282+ length = len (self )
283+ if length == 0 :
284+ raise IndexError ("BigArray index out of range" )
285+
286+ if y < 0 :
287+ y += length
288+
289+ if y < 0 or y >= length :
290+ raise IndexError ("BigArray index out of range" )
291+
292+ index = y // self .chunk_length
293+ offset = y % self .chunk_length
294+ chunk = self .chunks [index ]
295+
296+ if isinstance (chunk , list ):
297+ chunk [offset ] = value
298+ else :
299+ self ._checkcache (index )
300+ self .cache .data [offset ] = value
301+ self .cache .dirty = True
219302
220303 def __repr__ (self ):
221304 return "%s%s" % ("..." if len (self .chunks ) > 1 else "" , self .chunks [- 1 ].__repr__ ())
0 commit comments