# HG changeset patch # User David Barts # Date 1577395133 28800 # Node ID 8884b0bf779dbdae262aeef7d50f96b785e1b07f # Parent 173e86601dbc65656c23ff9dfe0b84991bf18c3e Improve the efficiency. diff -r 173e86601dbc -r 8884b0bf779d workspace.py --- a/workspace.py Thu Dec 26 12:00:03 2019 -0800 +++ b/workspace.py Thu Dec 26 13:18:53 2019 -0800 @@ -206,6 +206,7 @@ raise TypeError("offset must be an int") self.bounds = bounds self.offset = offset + self.delta = self.offset - self.bounds.start def __repr__(self): return "{0}({1!r}, {2!r})".format(self.__class__.__name__, self.bounds, self.offset) @@ -233,11 +234,10 @@ self._length = pos def _mapped(self, index): - mi = self._binsch(index) - m = None if mi is None else self._mmap[mi] - if m is None: + mmap_index = self._binsch(index) + if mmap_index is None: raise IndexError("index {0} out of range".format(index)) - return index - m.bounds.start + m.offset + return index + self._mmap[mmap_index].delta def _binsch(self, index): a = 0 @@ -260,13 +260,34 @@ # XXX - this is sorta brute-forced and could be more efficient def __getitem__(self, key): + # Trivial cases if isinstance(key, int): return self._get1(key) if not isinstance(key, slice): raise TypeError("expecting int or slice") + if key.step is not None: + raise ValueError("__getitem__ does not support steps in slices") + + # Loop up the starting segment. + mi = self._binsch(key.start) + if mi is None: + return "" + m = self._mmap[mi] + + # Horray! There's only one segment, so we can optimize. + if key.stop <= m.bounds.stop: + start = key.start + m.delta + stop = key.stop + m.delta + return self.indexable[start:stop] + + # The most involved (multi-segment) case. with io.StringIO() as buf: - for i in range(key.start, key.stop, key.step or 1): - buf.write(self._get1(i)) + for m in self._mmap[mi:]: + if m.bounds.start >= key.stop: + break + start = max(key.start, m.bounds.start) + m.delta + stop = min(key.stop, m.bounds.stop) + m.delta + buf.write(self.indexable[start:stop]) return buf.getvalue() def __len__(self):