comparison workspace.py @ 2:8884b0bf779d

Improve the efficiency.
author David Barts <n5jrn@me.com>
date Thu, 26 Dec 2019 13:18:53 -0800
parents 173e86601dbc
children 091c03f1b2e8
comparison
equal deleted inserted replaced
1:173e86601dbc 2:8884b0bf779d
204 raise TypeError("bounds must be a Bounds object") 204 raise TypeError("bounds must be a Bounds object")
205 if not isinstance(offset, int): 205 if not isinstance(offset, int):
206 raise TypeError("offset must be an int") 206 raise TypeError("offset must be an int")
207 self.bounds = bounds 207 self.bounds = bounds
208 self.offset = offset 208 self.offset = offset
209 self.delta = self.offset - self.bounds.start
209 210
210 def __repr__(self): 211 def __repr__(self):
211 return "{0}({1!r}, {2!r})".format(self.__class__.__name__, self.bounds, self.offset) 212 return "{0}({1!r}, {2!r})".format(self.__class__.__name__, self.bounds, self.offset)
212 213
213 class SegmentedView(object): 214 class SegmentedView(object):
231 pos += r.stop - r.start 232 pos += r.stop - r.start
232 self._mmap.append(Mapping(Bounds(opos, pos), r.start)) 233 self._mmap.append(Mapping(Bounds(opos, pos), r.start))
233 self._length = pos 234 self._length = pos
234 235
235 def _mapped(self, index): 236 def _mapped(self, index):
236 mi = self._binsch(index) 237 mmap_index = self._binsch(index)
237 m = None if mi is None else self._mmap[mi] 238 if mmap_index is None:
238 if m is None:
239 raise IndexError("index {0} out of range".format(index)) 239 raise IndexError("index {0} out of range".format(index))
240 return index - m.bounds.start + m.offset 240 return index + self._mmap[mmap_index].delta
241 241
242 def _binsch(self, index): 242 def _binsch(self, index):
243 a = 0 243 a = 0
244 z = len(self._mmap) - 1 244 z = len(self._mmap) - 1
245 while a <= z: 245 while a <= z:
258 raise TypeError("__setitem__ only supports integers") 258 raise TypeError("__setitem__ only supports integers")
259 self.indexable[self._mapped(key)] = value 259 self.indexable[self._mapped(key)] = value
260 260
261 # XXX - this is sorta brute-forced and could be more efficient 261 # XXX - this is sorta brute-forced and could be more efficient
262 def __getitem__(self, key): 262 def __getitem__(self, key):
263 # Trivial cases
263 if isinstance(key, int): 264 if isinstance(key, int):
264 return self._get1(key) 265 return self._get1(key)
265 if not isinstance(key, slice): 266 if not isinstance(key, slice):
266 raise TypeError("expecting int or slice") 267 raise TypeError("expecting int or slice")
268 if key.step is not None:
269 raise ValueError("__getitem__ does not support steps in slices")
270
271 # Loop up the starting segment.
272 mi = self._binsch(key.start)
273 if mi is None:
274 return ""
275 m = self._mmap[mi]
276
277 # Horray! There's only one segment, so we can optimize.
278 if key.stop <= m.bounds.stop:
279 start = key.start + m.delta
280 stop = key.stop + m.delta
281 return self.indexable[start:stop]
282
283 # The most involved (multi-segment) case.
267 with io.StringIO() as buf: 284 with io.StringIO() as buf:
268 for i in range(key.start, key.stop, key.step or 1): 285 for m in self._mmap[mi:]:
269 buf.write(self._get1(i)) 286 if m.bounds.start >= key.stop:
287 break
288 start = max(key.start, m.bounds.start) + m.delta
289 stop = min(key.stop, m.bounds.stop) + m.delta
290 buf.write(self.indexable[start:stop])
270 return buf.getvalue() 291 return buf.getvalue()
271 292
272 def __len__(self): 293 def __len__(self):
273 return self._length 294 return self._length
274 295