from BTrees.IOBTree import IOBTree
[docs]class LargeList(IOBTree):
"""Large List."""
LENGTH_KEY = -1
def __init__(self, items=None):
items = items if items is not None else []
self.extend(items)
def append(self, item, unique=False):
if unique and item in self:
return
new_index = len(self)
self._set_length(len(self) + 1)
self[new_index] = item
def __eq__(self, other):
if len(self) != len(other):
return False
return all(mine == their for mine, their in zip(self, other))
def __len__(self):
return IOBTree.get(self, self.LENGTH_KEY, self.LENGTH_KEY + 1)
def __add__(self, other):
return LargeList(list(self) + other)
def _set_length(self, length):
IOBTree.__setitem__(self, self.LENGTH_KEY, length)
def extend(self, items, unique=False):
for _item in items:
self.append(_item, unique)
[docs] def insert(self, indice, element):
self._set_length(len(self) + 1)
for i in range(len(self) - 1, indice, -1):
self[i] = self[i - 1]
self[indice] = element
def remove(self, item, all=False):
found = False
for key, value in self.items():
if key == self.LENGTH_KEY:
continue
if item != value:
continue
found = True
del self[key]
if not all:
return
if not all or not found:
raise ValueError(f"{item} not in {self}")
[docs] def pop(self):
length = len(self)
self._set_length(length - 1)
return super().pop(length - 1)
def __iter__(self):
_values = IOBTree.itervalues(self)
try:
next(_values)
return _values
except StopIteration:
return iter({})
def __contains__(self, item):
return item in iter(self)
def __getitem__(self, item):
if isinstance(item, slice):
_slice = self._reslice(item)
return (
IOBTree.__getitem__(self, index)
for index in range(
_slice.start, min(len(self), _slice.stop), _slice.step
)
)
elif isinstance(item, int):
if item >= len(self):
raise IndexError
try:
if not item:
return IOBTree.__getitem__(self, 0)
return IOBTree.__getitem__(self, item > 0 and item or len(self) + item)
except KeyError as ex:
raise IndexError(ex)
else:
raise TypeError(
f"Invalid LargeList key '{item}'. It must be an integer or a slice."
)
def __setitem__(self, key, value):
if not isinstance(key, slice) and key >= len(self):
raise IndexError
return super().__setitem__(key, value)
def __delitem__(self, key):
IOBTree.__delitem__(self, key)
for i in range(key + 1, len(self)):
item = IOBTree.__getitem__(self, i)
IOBTree.__setitem__(self, i - 1, item)
IOBTree.__delitem__(self, i)
self._set_length(len(self) - 1)
def _reslice(self, item):
if item.step is None or item.step > 0:
return slice(self._start(item), self._stop(item), self._step(item))
else:
return slice(self._start_down(item), self._stop_down(item), item.step)
def _start(self, item):
if item.start is None:
return 0
elif item.start < 0:
return len(self) + item.start
else:
return item.start
def _stop(self, item):
if item.stop is None:
return len(self)
elif item.stop < 0:
return len(self) + item.stop
else:
return item.stop
def _step(self, item):
return item.step or 1
def _start_down(self, item):
if item.start is None:
return len(self) - 1
elif item.start < 0:
return len(self) + item.start
else:
return item.start
def _stop_down(self, item):
if item.stop is None:
return -1
elif item.stop < 0:
return len(self) + item.stop
else:
return item.stop