class IndexedOrderedStore(Store):
    """Resource with *capacity* slots for storing objects in order and
    retrieving multiple items simultaneously from arbitrary positions in the
    :class:`IndexedOrderedStore`. All items in an *IndexedOrderedStore*
    instance must be orderable, which is to say that items must implement
    :meth:`~object.__lt__()`.

    """

    put = BoundClass(StorePut)
    """Request to put an *item* into the store."""

    get = BoundClass(IndexedOrderedStoreGet)
    """Request to get *items* at *indices* out of the store."""
    def _do_put(self, event):
        if len(self.items) < self._capacity:
            insort(self.items, event.item)
            event.succeed()

    def _do_get(self, event):
        if len(event.indices) == 1:
            event.succeed([self.items.pop(event.indices[0])])
            return

        result = []

        for idx, val in enumerate(event.indices):
            result.append(self.items[val])
            self.items[val] = self.items[-1 - idx]

        if len(event.indices) > 0:
            del self.items[-len(event.indices):]
            self.items.sort()

        event.succeed(result)
Esempio n. 2
0
class Store(base.BaseResource):
    """Resource with *capacity* slots for storing arbitrary objects. By
    default, the *capacity* is unlimited and objects are put and retrieved from
    the store in a first-in first-out order.

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    container is bound to.

    """
    def __init__(self, env, capacity=float('inf')):
        if capacity <= 0:
            raise ValueError('"capacity" must be > 0.')

        super(Store, self).__init__(env, capacity)

        self.items = []
        """List of the items available in the store."""

    put = BoundClass(StorePut)
    """Request to put *item* into the store."""

    get = BoundClass(StoreGet)
    """Request to get an *item* out of the store."""

    def _do_put(self, event):
        if len(self.items) < self._capacity:
            self.items.append(event.item)
            event.succeed()

    def _do_get(self, event):
        if self.items:
            event.succeed(self.items.pop(0))
Esempio n. 3
0
class FilterStore(Store):
    """Resource with *capacity* slots for storing arbitrary objects supporting
    filtered get requests. Like the :class:`Store`, the *capacity* is unlimited
    by default and objects are put and retrieved from the store in a first-in
    first-out order.

    Get requests can be customized with a filter function to only trigger for
    items for which said filter function returns ``True``.

    .. note::

        In contrast to :class:`Store`, get requests of a :class:`FilterStore`
        won't necessarily be triggered in the same order they were issued.

        *Example:* The store is empty. *Process 1* tries to get an item of type
        *a*, *Process 2* an item of type *b*. Another process puts one item of
        type *b* into the store. Though *Process 2* made his request after
        *Process 1*, it will receive that new item because *Process 1* doesn't
        want it.

    """

    put = BoundClass(StorePut)
    """Request a to put *item* into the store."""

    get = BoundClass(FilterStoreGet)
    """Request a to get an *item*, for which *filter* returns ``True``, out of
    the store."""
    def _do_get(self, event):
        for item in self.items:
            if event.filter(item):
                self.items.remove(item)
                event.succeed(item)
                break
        return True
Esempio n. 4
0
class Resource(base.BaseResource):
    """Resource with *capacity* of usage slots that can be requested by
    processes.

    If all slots are taken, requests are enqueued. Once a usage request is
    released, a pending request will be triggered.

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    resource is bound to.

    """

    def __init__(self, env: Environment, capacity: int = 1):
        if capacity <= 0:
            raise ValueError('"capacity" must be > 0.')

        super().__init__(env, capacity)

        self.users: List[Request] = []
        """List of :class:`Request` events for the processes that are currently
        using the resource."""
        self.queue = self.put_queue
        """Queue of pending :class:`Request` events. Alias of
        :attr:`~simpy.resources.base.BaseResource.put_queue`.
        """

    @property
    def count(self) -> int:
        """Number of users currently using the resource."""
        return len(self.users)

    if TYPE_CHECKING:

        def request(self) -> Request:
            """Request a usage slot."""
            return Request(self)

        def release(self, request: Request) -> Release:
            """Release a usage slot."""
            return Release(self, request)

    else:
        request = BoundClass(Request)
        release = BoundClass(Release)

    def _do_put(self, event: Request) -> None:
        if len(self.users) < self.capacity:
            self.users.append(event)
            event.usage_since = self._env.now
            event.succeed()

    def _do_get(self, event: Release) -> None:
        try:
            self.users.remove(event.request)  # type: ignore
        except ValueError:
            pass
        event.succeed()
Esempio n. 5
0
class Container(base.BaseResource):
    """Models the production and consumption of a homogeneous, undifferentiated
    bulk. It may either be continuous (like water) or discrete (like apples).

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    container is bound to.

    The *capacity* defines the size of the container and must be a positive
    number (> 0). By default, a container is of unlimited size.  You can
    specify the initial level of the container via *init*. It must be >=
    0 and is 0 by default.

    Raise a :exc:`ValueError` if ``capacity <= 0``, ``init < 0`` or
    ``init > capacity``.

    """
    def __init__(self, env, capacity=float('inf'), init=0):
        super(Container, self).__init__(env)
        if capacity <= 0:
            raise ValueError('"capacity" must be > 0.')
        if init < 0:
            raise ValueError('"init" must be >= 0.')
        if init > capacity:
            raise ValueError('"init" must be <= "capacity".')

        self._capacity = capacity
        self._level = init

    @property
    def capacity(self):
        """The maximum capacity of the container."""
        return self._capacity

    @property
    def level(self):
        """The current level of the container (a number between ``0`` and
        ``capacity``).

        """
        return self._level

    put = BoundClass(ContainerPut)
    """Creates a new :class:`ContainerPut` event."""

    get = BoundClass(ContainerGet)
    """Creates a new :class:`ContainerGet` event."""

    def _do_put(self, event):
        if self._capacity - self._level >= event.amount:
            self._level += event.amount
            event.succeed()

    def _do_get(self, event):
        if self._level >= event.amount:
            self._level -= event.amount
            event.succeed()
Esempio n. 6
0
    def __init__(self, env):
        self._env = env
        self.put_queue = self.PutQueue()
        """Queue/list of events waiting to get something out of the resource.
        """
        self.get_queue = self.GetQueue()
        """Queue/list of events waiting to put something into the resource."""

        # Bind event constructors as methods
        BoundClass.bind_early(self)
Esempio n. 7
0
    def __init__(self, env, capacity):
        self._env = env
        self._capacity = capacity
        self.put_queue = self.PutQueue()
        """Queue of pending *put* requests."""
        self.get_queue = self.GetQueue()
        """Queue of pending *get* requests."""

        # Bind event constructors as methods
        BoundClass.bind_early(self)
Esempio n. 8
0
    def __init__(self, env):
        self._env = env
        self.put_queue = self.PutQueue()
        """Queue/list of events waiting to get something out of the resource.
        """
        self.get_queue = self.GetQueue()
        """Queue/list of events waiting to put something into the resource."""

        # Bind event constructors as methods
        BoundClass.bind_early(self)
Esempio n. 9
0
    def __init__(self, env, capacity):
        self._env = env
        self._capacity = capacity
        self.put_queue = self.PutQueue()
        """Queue of pending *put* requests."""
        self.get_queue = self.GetQueue()
        """Queue of pending *get* requests."""

        # Bind event constructors as methods
        BoundClass.bind_early(self)
    def __init__(self, fds=None):
        if fds is None:
            fds = {}

        self._queue = []
        """A list with all currently scheduled events."""
        self._eid = count()
        self._active_proc = None

        self.fds = fds

        BoundClass.bind_early(self)
Esempio n. 11
0
    def __init__(self, env, capacity=float('inf')):
        # BaseResource
        self._env = env
        self._capacity = capacity
        self.lock = threading.RLock()
        self.put_queue = SynchronizedList(self.lock)
        self.get_queue = SynchronizedList(self.lock)
        BoundClass.bind_early(self)

        self.callbacks = []
        # Store
        self.items = []
Esempio n. 12
0
 def __init__(self, env, capacity=float('inf'), hard_cap=False, items=()):
     self.env = env
     #: Capacity of the queue (maximum number of items).
     self.capacity = capacity
     self._hard_cap = hard_cap
     self.items = list(items)
     self._putters = []
     self._getters = []
     self._any_waiters = []
     self._full_waiters = []
     self._put_hook = None
     self._get_hook = None
     BoundClass.bind_early(self)
Esempio n. 13
0
class Resource(base.BaseResource):
    """A resource has a limited number of slots that can be requested by
    a process.

    If all slots are taken, requesters are put into a queue. If a process
    releases a slot, the next process is popped from the queue and gets one
    slot.

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    resource is bound to.

    The *capacity* defines the number of slots and must be a positive integer.

    """
    def __init__(self, env, capacity=1):
        super(Resource, self).__init__(env)
        self._capacity = capacity
        self.users = []
        """List of :class:`Request` events for the processes that are currently
        using the resource."""
        self.queue = self.put_queue
        """Queue/list of pending :class:`Request` events that represent
        processes waiting to use the resource."""

    @property
    def capacity(self):
        """Maximum capacity of the resource."""
        return self._capacity

    @property
    def count(self):
        """Number of users currently using the resource."""
        return len(self.users)

    request = BoundClass(Request)
    """Create a new :class:`Request` event."""

    release = BoundClass(Release)
    """Create a new :class:`Release` event."""

    def _do_put(self, event):
        if len(self.users) < self.capacity:
            self.users.append(event)
            event.succeed()

    def _do_get(self, event):
        try:
            self.users.remove(event.request)
        except ValueError:
            pass
        event.succeed()
Esempio n. 14
0
class Container(base.BaseResource):
    """Resource containing up to *capacity* of matter which may either be
    continuous (like water) or discrete (like apples). It supports requests to
    put or get matter into/from the container.

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    container is bound to.

    The *capacity* defines the size of the container. By default, a container
    is of unlimited size. The initial amount of matter is specified by *init*
    and defaults to ``0``.

    Raise a :exc:`ValueError` if ``capacity <= 0``, ``init < 0`` or
    ``init > capacity``.

    """
    def __init__(self, env, capacity=float('inf'), init=0):
        if capacity <= 0:
            raise ValueError('"capacity" must be > 0.')
        if init < 0:
            raise ValueError('"init" must be >= 0.')
        if init > capacity:
            raise ValueError('"init" must be <= "capacity".')

        super(Container, self).__init__(env, capacity)

        self._level = init

    @property
    def level(self):
        """The current amount of the matter in the container."""
        return self._level

    put = BoundClass(ContainerPut)
    """Request to put *amount* of matter into the container."""

    get = BoundClass(ContainerGet)
    """Request to get *amount* of matter out of the container."""

    def _do_put(self, event):
        if self._capacity - self._level >= event.amount:
            self._level += event.amount
            event.succeed()
            return True

    def _do_get(self, event):
        if self._level >= event.amount:
            self._level -= event.amount
            event.succeed()
            return True
Esempio n. 15
0
class StampedStore(base.BaseResource):
    """Models the production and consumption of concrete Python objects.

    Items put into the store can be of any type.  By default, they are put and
    retrieved from the store in a first-in first-out order.

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    container is bound to.

    The *capacity* defines the size of the Store and must be a positive number
    (> 0). By default, a Store is of unlimited size. A :exc:`ValueError` is
    raised if the value is negative.

    """
    def __init__(self, env, capacity=float('inf')):
        super(StampedStore, self).__init__(env, capacity=float('inf'))
        if capacity <= 0:
            raise ValueError('"capacity" must be > 0.')
        self._capacity = capacity
        self.items = []  # we are keeping items sorted by stamp
        self.event_count = 0  # Used to break ties with python heap implementation
        # See: https://docs.python.org/3/library/heapq.html?highlight=heappush#priority-queue-implementation-notes
        """List of the items within the store."""

    @property
    def capacity(self):
        """The maximum capacity of the store."""
        return self._capacity

    put = BoundClass(StampedStorePut)
    """Create a new :class:`StorePut` event."""

    get = BoundClass(StampedStoreGet)
    """Create a new :class:`StoreGet` event."""

    # We assume the item is a tuple: (stamp, packet). The stamp is used to
    # sort the packet in the heap.
    def _do_put(self, event):
        self.event_count += 1  # Needed this to break heap ties
        if len(self.items) < self._capacity:
            heappush(self.items,
                     [event.item[0], self.event_count, event.item[1]])
            event.succeed()

    # When we return an item from the stamped store we do not
    # return the stamp but only the content portion.
    def _do_get(self, event):
        if self.items:
            event.succeed(heappop(self.items)[2])
Esempio n. 16
0
 def __init__(self, env, capacity=float('inf'), hard_cap=False, items=(),
              name=None):
     self.env = env
     #: Capacity of the queue (maximum number of items).
     self.capacity = capacity
     self._hard_cap = hard_cap
     self.items = list(items)
     self.name = name
     self._put_waiters = []
     self._get_waiters = []
     self._at_most_waiters = []
     self._at_least_waiters = []
     self._put_hook = None
     self._get_hook = None
     BoundClass.bind_early(self)
Esempio n. 17
0
class PriorityPool(Pool):
    """Pool with prioritizied put() and get() requests.

    A priority is provided with `put()` and `get()` requests. This priority
    determines the strict order in which requests are fulfilled. Requests of
    the same priority are serviced in strict FIFO order.

    """
    def __init__(self,
                 env,
                 capacity=float('inf'),
                 init=0,
                 hard_cap=False,
                 name=None):
        super(PriorityPool, self).__init__(env, capacity, init, hard_cap, name)
        self._event_count = 0

    #: Put amount in the pool.
    put = BoundClass(PriorityPoolPutEvent)

    #: Get amount from the pool.
    get = BoundClass(PriorityPoolGetEvent)

    def _trigger_put(self, _=None):
        while self._put_waiters:
            put_ev = self._put_waiters[0]
            if self.capacity - self.level >= put_ev.amount:
                heapq.heappop(self._put_waiters)
                self.level += put_ev.amount
                put_ev.succeed()
                if self._put_hook:
                    self._put_hook()
            elif self._hard_cap:
                raise OverflowError()
            else:
                break

    def _trigger_get(self, _=None):
        while self._get_waiters:
            get_ev = self._get_waiters[0]
            if get_ev.amount <= self.level:
                heapq.heappop(self._get_waiters)
                self.level -= get_ev.amount
                get_ev.succeed(get_ev.amount)
                if self._get_hook:
                    self._get_hook()
            else:
                break
Esempio n. 18
0
 def __init__(self, env, capacity=float('inf'), init=0, hard_cap=False,
              name=None):
     self.env = env
     #: Capacity of the queue (maximum number of items).
     self.capacity = capacity
     self._hard_cap = hard_cap
     self.level = init
     self.name = name
     self._putters = []
     self._getters = []
     self._new_waiters = []
     self._any_waiters = []
     self._full_waiters = []
     self._put_hook = None
     self._get_hook = None
     BoundClass.bind_early(self)
Esempio n. 19
0
class DPStore(store.Store):
    if TYPE_CHECKING:

        def get(
            self, epsilon: float, block_nr: int
        ) -> DPStoreGet:
            """Request to get an *item*, for which *filter* returns ``True``,
            out of the store."""
            return DPStoreGet(self, epsilon, block_nr )

    else:
        get = BoundClass(DPStoreGet)

    def _do_get(  # type: ignore[override] # noqa: F821
        self, event: DPStoreGet
    ) -> Optional[bool]:
        if len(self.items) >= event.block_nr:
            return_blocks = []
            for i in random.sample(range(len(self.items)), k=event.block_nr):
                block = self.items[i]
                if block["epsilon"] - event.epsilon <0:
                    block["epsilon"] = -1
                else:
                    block["epsilon"] = block["epsilon"] - event.epsilon
                return_blocks.append(block)

            event.succeed(return_blocks)
        return True
Esempio n. 20
0
class ReadableFilterStore(FilterStore):
    """Extends simpy.resources.store.FilterStore with a non-destructive read()
    method."""

    get = BoundClass(FilterStoreGetWithRemove)

    read = BoundClass(FilterStoreGetWithNoRemove)

    def _do_get(self, event):
        for item in self.items:
            if event.filter(item):
                if event.remove_item:
                    self.items.remove(item)
                event.succeed(item)
                break
        return True
Esempio n. 21
0
 def __init__(self, env, capacity=float('inf'), init=0, hard_cap=False,
              name=None):
     self.env = env
     #: Capacity of the pool (maximum level).
     self.capacity = capacity
     #: Current fill level of the pool.
     self.level = init
     self._hard_cap = hard_cap
     self.name = name
     self._put_waiters = []
     self._get_waiters = []
     self._at_most_waiters = []
     self._at_least_waiters = []
     self._put_hook = None
     self._get_hook = None
     BoundClass.bind_early(self)
Esempio n. 22
0
class FilterQueue(Queue[ItemType]):
    """Specialized queue where items are dequeued in priority order.

    Items in `PriorityQueue` must be orderable (implement
    :meth:`~object.__lt__`). Unorderable items may be used with `PriorityQueue`
    by wrapping with :class:`~PriorityItem`.

    Items that evaluate less-than other items will be dequeued first.

    """


    if TYPE_CHECKING:
        def get(self,filter: Callable[[Any], bool] = lambda item: True) -> FilterQueueGet:
            """Dequeue an item from the queue."""
            ...
    else:
        get = BoundClass(FilterQueueGet)

    def _trigger_get(self, _: Optional[Event] = None,*args,**kwargs) -> None:

        idx = 0
        while self._get_waiters and idx < len(self._get_waiters):
            get_ev = self._get_waiters[idx]
            for i,item in enumerate(self.items):
                if get_ev.filter(item):
                    self.items.pop(i)
                    self._get_waiters.pop(idx)
                    get_ev.succeed(item,*args,**kwargs)
                    if self._get_hook:
                        self._get_hook()
                    break
            else:
                idx +=1
Esempio n. 23
0
class Pkt(simpy.resources.store.Store):

    get = BoundClass(PktRX)

    def _do_get(self, event):
        if self.items:
            event.succeed(self.items)
            self.items = []
Esempio n. 24
0
class ModifiedContainer(simpy.Container):

    def __init__(self, env, capacity, init, name, owner, resource):
        super().__init__(env,capacity, init)
        self.name = name
        self.owner = owner
        self.resource = resource

    if TYPE_CHECKING:

        def put(  # type: ignore[override] # noqa: F821
            self, amount: ContainerAmount, name: str, owner, resource: str
        ) -> ModifiedContainerPut:
            """Request to put *amount* of matter into the container."""
            return ModifiedContainerPut(self, amount, self.name, self.owner, self.resource)

        def get(  # type: ignore[override] # noqa: F821
            self, amount: ContainerAmount, name: str, owner, resource: str
        ) -> ModifiedContainerGet:
            """Request to get *amount* of matter out of the container."""
            return ModifiedContainerGet(self, amount, self.name, self.owner, self.resource)

    else:
        put = BoundClass(ModifiedContainerPut)
        get = BoundClass(ModifiedContainerGet)

    def _do_put(self, event: ModifiedContainerPut) -> Optional[bool]:
        if self._capacity - self._level >= event.amount:
            self._level += event.amount
            event.succeed()
            evnt_logger.info(f"\t {self.name} of {self.owner}'s level increased by {event.amount} {self.resource}'",extra={"sim_time":self._env.now})
            return True
        else:
            evnt_logger.info(f"\t {self.name} of {self.owner}'s put failed.'",extra={"sim_time":self._env.now})
            return None

    def _do_get(self, event: ModifiedContainerGet) -> Optional[bool]:
        if self._level >= event.amount:
            self._level -= event.amount
            event.succeed()
            evnt_logger.info(f"\t {self.name} of {self.owner}'s level decreased by {event.amount} {self.resource}'",extra={"sim_time":self._env.now})
            return True
        else:
            evnt_logger.info(f"\t {self.name} of {self.owner}'s put failed.'",extra={"sim_time":self._env.now})
            return None
Esempio n. 25
0
class Store(base.BaseResource):
    """Resource with *capacity* slots for storing arbitrary objects. By
    default, the *capacity* is unlimited and objects are put and retrieved from
    the store in a first-in first-out order.

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    container is bound to.

    """
    def __init__(self,
                 env: Environment,
                 capacity: Union[float, int] = float('inf')):
        if capacity <= 0:
            raise ValueError('"capacity" must be > 0.')

        super().__init__(env, capacity)

        self.items: List[Any] = []
        """List of the items available in the store."""

    if TYPE_CHECKING:

        def put(  # type: ignore[override] # noqa: F821
                self, item: Any) -> StorePut:
            """Request to put *item* into the store."""
            return StorePut(self, item)

        def get(self) -> StoreGet:  # type: ignore[override] # noqa: F821
            """Request to get an *item* out of the store."""
            return StoreGet(self)

    else:
        put = BoundClass(StorePut)
        get = BoundClass(StoreGet)

    def _do_put(self, event: StorePut) -> Optional[bool]:
        if len(self.items) < self._capacity:
            self.items.append(event.item)
            event.succeed()
        return None

    def _do_get(self, event: StoreGet) -> Optional[bool]:
        if self.items:
            event.succeed(self.items.pop(0))
        return None
Esempio n. 26
0
 def __init__(self,
              env,
              capacity=float('inf'),
              init=0,
              hard_cap=False,
              name=None):
     self.env = env
     #: Capacity of the pool (maximum level).
     self.capacity = capacity
     #: Current fill level of the pool.
     self.level = init
     self._hard_cap = hard_cap
     self.name = name
     self._put_waiters = []
     self._get_waiters = []
     self._at_most_waiters = []
     self._at_least_waiters = []
     self._put_hook = None
     self._get_hook = None
     BoundClass.bind_early(self)
Esempio n. 27
0
class Store(base.BaseResource):
    """Models the production and consumption of concrete Python objects.

    Items put into the store can be of any type.  By default, they are put and
    retrieved from the store in a first-in first-out order.

    The *env* parameter is the :class:`~simpy.core.Environment` instance the
    container is bound to.

    The *capacity* defines the size of the Store and must be a positive number
    (> 0). By default, a Store is of unlimited size. A :exc:`ValueError` is
    raised if the value is negative.

    """
    def __init__(self, env, capacity=float('inf')):
        super(Store, self).__init__(env)
        if capacity <= 0:
            raise ValueError('"capacity" must be > 0.')
        self._capacity = capacity
        self.items = []
        """List of the items within the store."""

    @property
    def capacity(self):
        """The maximum capacity of the store."""
        return self._capacity

    put = BoundClass(StorePut)
    """Create a new :class:`StorePut` event."""

    get = BoundClass(StoreGet)
    """Create a new :class:`StoreGet` event."""

    def _do_put(self, event):
        if len(self.items) < self._capacity:
            self.items.append(event.item)
            event.succeed()

    def _do_get(self, event):
        if self.items:
            event.succeed(self.items.pop(0))
Esempio n. 28
0
 def __init__(
     self,
     env: Environment,
     capacity: Union[int, float] = float('inf'),
     hard_cap: bool = False,
     items: Iterable[ItemType] = (),
     name: Optional[str] = None,
 ) -> None:
     self.env = env
     #: Capacity of the queue (maximum number of items).
     self.capacity = capacity
     self._hard_cap = hard_cap
     self.items: List[ItemType] = list(items)
     self.name = name
     self._put_waiters: List[QueuePutEvent] = []
     self._get_waiters: List[QueueGetEvent] = []
     self._at_most_waiters: List[QueueWhenAtMostEvent] = []
     self._at_least_waiters: List[QueueWhenAtLeastEvent] = []
     self._put_hook: Optional[Callable[[], Any]] = None
     self._get_hook: Optional[Callable[[], Any]] = None
     BoundClass.bind_early(self)
class PriorityResource(Resource):
    """A :class:`~simpy.resources.resource.Resource` supporting prioritized
    requests.

    Pending requests in the :attr:`~Resource.queue` are sorted in ascending
    order by their *priority* (that means lower values are more important).

    """
    PutQueue = SortedQueue
    """Type of the put queue. See
    :attr:`~simpy.resources.base.BaseResource.put_queue` for details."""
    GetQueue = list
    """Type of the get queue. See
    :attr:`~simpy.resources.base.BaseResource.get_queue` for details."""
    def __init__(self, env, capacity=1):
        super(PriorityResource, self).__init__(env, capacity)

    request = BoundClass(PriorityRequest)
    """Request a usage slot with the given *priority*."""

    release = BoundClass(Release)
    """Release a usage slot."""
Esempio n. 30
0
 def __init__(
     self,
     env: Environment,
     capacity: PoolAmount = float('inf'),
     init: PoolAmount = 0,
     hard_cap: bool = False,
     name: Optional[str] = None,
 ):
     self.env = env
     #: Capacity of the pool (maximum level).
     self.capacity = capacity
     #: Current fill level of the pool.
     self.level = init
     self._hard_cap = hard_cap
     self.name = name
     self._put_waiters: List[PoolPutEvent] = []
     self._get_waiters: List[PoolGetEvent] = []
     self._at_most_waiters: List[PoolWhenAtMostEvent] = []
     self._at_least_waiters: List[PoolWhenAtLeastEvent] = []
     self._put_hook: Optional[Callable[[], Any]] = None
     self._get_hook: Optional[Callable[[], Any]] = None
     BoundClass.bind_early(self)
Esempio n. 31
0
class PriorityResource(Resource):
    """A :class:`~simpy.resources.resource.Resource` supporting prioritized
    requests.

    Pending requests in the :attr:`~Resource.queue` are sorted in ascending
    order by their *priority* (that means lower values are more important).

    """

    PutQueue = SortedQueue
    """Type of the put queue. See
    :attr:`~simpy.resources.base.BaseResource.put_queue` for details."""

    GetQueue = list
    """Type of the get queue. See
    :attr:`~simpy.resources.base.BaseResource.get_queue` for details."""

    def __init__(self, env: Environment, capacity: int = 1):
        super().__init__(env, capacity)

    if TYPE_CHECKING:

        def request(
            self, priority: int = 0, preempt: bool = True
        ) -> PriorityRequest:
            """Request a usage slot with the given *priority*."""
            return PriorityRequest(self, priority, preempt)

        def release(  # type: ignore[override] # noqa: F821
            self, request: PriorityRequest
        ) -> Release:
            """Release a usage slot."""
            return Release(self, request)

    else:
        request = BoundClass(PriorityRequest)
        release = BoundClass(Release)
Esempio n. 32
0
class Pkt(simpy.resources.store.Store):

    get = BoundClass(PktRX)

    def _do_get (self, event):
        if self.items:
            
            # if no limit - fetch all
            if event.limit is None:
                event.succeed(self.items)
                self.items = []
                
            else:
            # if limit was set - slice the list
                event.succeed(self.items[:event.limit])
                self.items = self.items[event.limit:]
Esempio n. 33
0
class FilterStore(Store):
    """Resource with *capacity* slots for storing arbitrary objects supporting
    filtered get requests. Like the :class:`Store`, the *capacity* is unlimited
    by default and objects are put and retrieved from the store in a first-in
    first-out order.

    Get requests can be customized with a filter function to only trigger for
    items for which said filter function returns ``True``.

    .. note::

        In contrast to :class:`Store`, get requests of a :class:`FilterStore`
        won't necessarily be triggered in the same order they were issued.

        *Example:* The store is empty. *Process 1* tries to get an item of type
        *a*, *Process 2* an item of type *b*. Another process puts one item of
        type *b* into the store. Though *Process 2* made his request after
        *Process 1*, it will receive that new item because *Process 1* doesn't
        want it.

    """

    if TYPE_CHECKING:

        def get(
            self,
            filter: Callable[[Any],
                             bool] = lambda item: True) -> FilterStoreGet:
            """Request to get an *item*, for which *filter* returns ``True``,
            out of the store."""
            return FilterStoreGet(self, filter)

    else:
        get = BoundClass(FilterStoreGet)

    def _do_get(  # type: ignore[override] # noqa: F821
            self, event: FilterStoreGet) -> Optional[bool]:
        for item in self.items:
            if event.filter(item):
                self.items.remove(item)
                event.succeed(item)
                break
        return True
Esempio n. 34
0
class PriorityResource(Resource):
    """This class works like :class:`Resource`, but requests are sorted by
    priority.

    The :attr:`~Resource.queue` is kept sorted by priority in ascending order
    (a lower value for *priority* results in a higher priority), so more
    important request will get the resource earlier.

    """
    PutQueue = SortedQueue
    """The type to be used for the
    :attr:`~simpy.resources.base.BaseResource.put_queue`."""
    GetQueue = list
    """The type to be used for the
    :attr:`~simpy.resources.base.BaseResource.get_queue`."""
    def __init__(self, env, capacity=1):
        super(PriorityResource, self).__init__(env, capacity)

    request = BoundClass(PriorityRequest)
    """Create a new :class:`PriorityRequest` event."""