Source code for genlayer.storage.array

__all__ = ('Array',)

import typing
import collections.abc

from .core import (
	_WithStorageSlotAndTD,
	TypeDesc,
	Slot,
	CopyAction,
	actions_apply_copy,
	SpecialTypeDesc,
	actions_append,
)

from ..types import SizedArray


[docs] class Array[T, S: int]( _WithStorageSlotAndTD, collections.abc.Sequence, SizedArray[T, S] ): """ Constantly sized array that can be persisted on the blockchain """ _item_desc: TypeDesc _len: int __slots__ = ('_item_desc', '_len', '_off', '_storage_slot')
[docs] def __init__(self): """ This class can't be created with ``Array()`` :raises TypeError: always """ raise TypeError('this class can not be instantiated by user')
[docs] def __len__(self) -> int: return self._len
@staticmethod def _view_at(item_desc: TypeDesc, le: int, slot: Slot, off: int) -> 'Array': slf = Array.__new__(Array) slf._item_desc = item_desc slf._len = le slf._storage_slot = slot slf._off = off return slf def _map_index(self, idx: int) -> int: le = len(self) if idx < 0: idx += le if idx < 0 or idx >= le: raise IndexError(f'index out of range {idx} not in 0..<{le}') return idx @typing.overload def __getitem__(self, idx: typing.SupportsIndex) -> T: ... @typing.overload def __getitem__(self, idx: slice) -> 'Array': ...
[docs] def __getitem__(self, idx: typing.SupportsIndex | slice) -> T | 'Array': """ Get element by index or a view over a sub-range by slice. :param idx: integer index or slice (step must be 1) :returns: single element for int index, ``Array`` view for slice :raises IndexError: when integer index is out of range :raises KeyError: when slice step is not 1 """ if not isinstance(idx, slice): idx = self._map_index(idx.__index__()) return self._item_desc.get( self._storage_slot, self._off + idx * self._item_desc.size ) else: start, stop, step = idx.indices(len(self)) if step != 1: raise KeyError('negative step is not supported') le = max(stop - start, 0) return Array._view_at( self._item_desc, le, self._storage_slot, self._off + start * self._item_desc.size, )
[docs] def __setitem__(self, idx: int, val: T) -> None: """ Set element at the given index. :param idx: integer index (supports negative indexing) :param val: value to set :raises IndexError: when index is out of range """ idx = self._map_index(idx) self._item_desc.set(self._storage_slot, self._off + idx * self._item_desc.size, val)
[docs] def __iter__(self): for i in range(len(self)): yield self[i]
class _ArrayDesc(SpecialTypeDesc): _len: int __slots__ = ('item_desc', 'view_ctor', '_len') def __init__(self, item_desc: TypeDesc, le: int): self._len = le def new_array(): ret = Array.__new__(Array) ret._len = le return ret SpecialTypeDesc.__init__(self, item_desc, new_array) cop: list[CopyAction] = [] for _i in range(le): actions_append(cop, item_desc.copy_actions) TypeDesc.__init__(self, le * item_desc.size, cop) def set(self, slot: Slot, off: int, val: Array | list) -> None: assert len(val) == self._len if isinstance(val, list): for i in range(self._len): self.item_desc.set(slot, off + i * self.item_desc.size, val[i]) else: actions_apply_copy(self.copy_actions, slot, off, val._storage_slot, val._off)