[ Web Proxy ]
URL:
Viewing: https://raw.githubusercontent.com/ZeroIntensity/pointers.py/master/src/pointers/malloc.py [Back]  [Original]

from __future__ import annotations

import sys
from typing import Any, Optional, TypeVar

from ._cstd import c_free, c_malloc, c_realloc
from .base_pointers import BaseAllocatedPointer, IterDereferencable
from .exceptions import AllocationError, InvalidSizeError
from .stack_pointer import StackAllocatedPointer
from .util import handle

__all__ = ("AllocatedPointer", "malloc", "free", "realloc")


T = TypeVar("T")
A = TypeVar("A", bound=BaseAllocatedPointer)


class AllocatedPointer(IterDereferencable[T], BaseAllocatedPointer[T]):
    """Pointer to allocated memory."""

    def __init__(
        self,
        address: int,
        size: int,
        assigned: bool = False,
        parent: AllocatedPointer[T] | None = None,
    ) -> None:
        """
        Args:
            address: Address of the allocated memory.
            size: Size of the allocated memory.
            assigned: Whether an object is currently inside the memory.
        """
        self._address = address
        self._size = size
        self._freed = False
        self._assigned = assigned
        self._parent: AllocatedPointer[T] | None = parent

    def _indexed(self, amount: int) -> AllocatedPointer[T]:
        return AllocatedPointer(
            self.ensure() + amount,
            self.size - amount,
            self.assigned,
            parent=self._parent,
        )

    def _get_parent(self) -> AllocatedPointer[T]:
        parent = self

        while parent._parent:
            parent = parent._parent

        return parent

    @property
    def freed(self) -> bool:
        return self._get_parent()._freed

    @freed.setter
    def freed(self, value: bool) -> None:
        self._get_parent()._freed = value

    @property
    def address(self) -> Optional[int]:
        return self._address

    @address.setter
    def address(self, value: int) -> None:
        self._address = value

    def __repr__(self) -> str:
        return f"AllocatedPointer(address={self.address}, size={self.size})"

    def __add__(self, amount: int) -> AllocatedPointer[T]:
        return self._indexed(amount)

    def __sub__(self, amount: int) -> AllocatedPointer[T]:
        return self._indexed(amount)

    @handle
    def free(self) -> None:
        self.ensure_valid()
        c_free(self.make_ct_pointer())
        self.freed = True

    @handle
    def __getitem__(self, index: int) -> AllocatedPointer[T]:
        if not isinstance(index, int):
            raise ValueError(
                f"memory indices must be int, not {type(index).__name__}",
            )

        return self._indexed(index)

    @handle
    def __setitem__(self, index: int, value: T) -> None:
        if not isinstance(index, int):
            raise ValueError(
                f"memory indices must be int, not {type(index).__name__}",
            )

        ptr = self._indexed(index)
        ptr  A:
    """Resize a memory block created by malloc.

    Args:
        target: Pointer to reallocate.
        size: New allocation size.

    Returns:
        Original object.

    Raises:
        InvalidSizeError: Object inside allocation is larger than attempted reallocation.
        AllocationError: Raised when allocation fails, presumably due to no memory.

    Example:
        ```py
        ptr = malloc(1)
        realloc(ptr, 2)
        ```
    """  # noqa
    if type(target) is StackAllocatedPointer:
        raise TypeError("pointers to items on the stack may not be resized")

    tsize: int = sys.getsizeof(~target)

    if target.assigned and (tsize > size):
        raise InvalidSizeError(
            f"object inside memory is of size {tsize}, so memory cannot be set to size {size}",  # noqa
        )

    addr = c_realloc(target.address, size)

    if not addr:
        raise AllocationError("failed to resize memory")

    target.size = size
    target.address = addr
    return target

Web Proxy Viewer  |  New URL  |  Original Page