Source code for cocotb.types._abstract_array

# Copyright cocotb contributors
# Licensed under the Revised BSD License, see LICENSE for details.
# SPDX-License-Identifier: BSD-3-Clause
from abc import abstractmethod
from typing import Generic, Iterable, Iterator, Optional, TypeVar, Union, overload

from cocotb.types._range import Range

T_co = TypeVar("T_co", covariant=True)
T = TypeVar("T")


class AbstractArray(Generic[T_co]):
    r"""Abstract base class for non-mutating Array-like collections.

    Arrays are similar to :class:`~collections.abc.Sequence`\ s,
    but their size cannot change after creation and they support arbitrary indexing schemes.

    Abstract methods
    ^^^^^^^^^^^^^^^^

    * :attr:`range`
    * :meth:`!__getitem__`

    Mixin methods
    ^^^^^^^^^^^^^

    * :attr:`left`, :attr:`right`, and :attr:`direction`
    * :meth:`!__len__`
    * :meth:`!__iter__` and :meth:`!__reversed__`
    * :meth:`!__contains__`
    * :meth:`index` and :meth:`count`
    """

    @property
    def left(self) -> int:
        """Leftmost index of the array."""
        return self.range.left

    @property
    def direction(self) -> str:
        """``"to"`` if indexes are ascending, ``"downto"`` otherwise."""
        return self.range.direction

    @property
    def right(self) -> int:
        """Rightmost index of the array."""
        return self.range.right

    @property
    @abstractmethod
    def range(self) -> Range:
        """:class:`Range` of the indexes of the array."""

    @range.setter
    @abstractmethod
    def range(self, new_range: Range) -> None:
        """Set a new indexing scheme on the array.

        Must be the same size.
        """

    def __len__(self) -> int:
        return len(self.range)

    def __iter__(self) -> Iterator[T_co]:
        for i in self.range:
            yield self[i]

    def __reversed__(self) -> Iterator[T_co]:
        for i in reversed(self.range):
            yield self[i]

    def __contains__(self, item: object) -> bool:
        return any(v == item for v in self)

    @overload
    def __getitem__(self, item: int) -> T_co: ...

    @overload
    def __getitem__(self, item: slice) -> "AbstractArray[T_co]": ...

    @abstractmethod
    def __getitem__(
        self, item: Union[int, slice]
    ) -> Union[T_co, "AbstractArray[T_co]"]: ...

[docs] def index( self, value: object, start: Optional[int] = None, stop: Optional[int] = None, ) -> int: """Find first occurrence of value. Args: value: Value to search for. start: Index to start search at. stop: Index to stop search at. Returns: Index of first occurrence of *value*. Raises: ValueError: If the value is not present. """ if start is None: start = self.left if stop is None: stop = self.right for i in Range(start, self.direction, stop): if self[i] == value: return i raise IndexError(f"{value!r} not in array")
[docs] def count(self, value: object) -> int: """Return number of occurrences of value. Args: value: Value to search for. Returns: Number of occurrences of *value*. """ count: int = 0 for v in self: if v == value: count += 1 return count
class AbstractMutableArray(AbstractArray[T]): """Abstract base class for mutating Array-like collections. See :class:`.AbstractArray` for more details. Additional abstract methods: * :meth:`!__setitem__` """ @overload def __setitem__(self, item: int, value: T) -> None: ... @overload def __setitem__(self, item: slice, value: Iterable[T]) -> None: ... @abstractmethod def __setitem__( self, item: Union[int, slice], value: Union[T, Iterable[T]] ) -> None: ...