diff --git a/main.py b/main.py deleted file mode 100755 index 9426ef3..0000000 --- a/main.py +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/env python -from pyority_queue import PureQueue, KeyedQueue - - -def main() -> None: - pure = PureQueue() - pure["second"] = 3.4 - pure["first"] = 1.2 - pure["third"] = 5.6 - print(*pure) - - keyed = KeyedQueue({"third": 5.6, "second": 3.4, "first": 7.8}) - del keyed["third"] - keyed["first"] = 1.2 - print(*keyed) - - -if __name__ == "__main__": - main() diff --git a/pyority_queue.pyi b/pyority_queue.pyi index d2893fd..e76f406 100644 --- a/pyority_queue.pyi +++ b/pyority_queue.pyi @@ -1,12 +1,14 @@ -from typing import Self +from abc import ABC +from typing import Hashable, Iterable, Self -class PureQueue[T]: - """A min-queue that allows duplicates and provides a minimal API allowing insertions and the ability to iterate over the queue in-order""" - def __init__(self, items: dict[T, float] | None = None) -> None: - """ - :param items: An optional mapping of items to priorities to initialize the queue with - """ +type Comparable = float | int + + +class Queue[Data](ABC): + """ + Common queue methods providing a minimal API for iteration. + """ def __len__(self) -> int: """ @@ -18,12 +20,44 @@ class PureQueue[T]: :return: An iterator over the queue """ - def __next__(self) -> T: + def __next__(self) -> Data: """ :return: The next item in the queue """ - def __setitem__(self, key: T, value: float) -> None: + +class PureQueue[Data: Comparable](Queue[Data]): + """ + A min-queue that directly orders its items, allowing duplicates. + """ + + def __init__(self, items: Iterable[Data] | None = None) -> None: + """ + :param items: An optional list of priorities with which to initialize the queue + """ + + def pop(self) -> Data: + """ + :return: The next item in the queue + """ + + def insert(self, item: Data) -> None: + """ + :param item: Item to insert into the queue + """ + + +class KeyedQueue[Data, Priority: Comparable](Queue[Data]): + """ + A min-queue that allows arbitrary data associated with some priority, allowing duplicates of both data and priority. + """ + + def __init__(self, items: dict[Data, Priority] | Iterable[tuple[Data, Priority]] | None = None) -> None: + """ + :param items: An optional mapping/list of items to priorities with which to initialize the queue + """ + + def __setitem__(self, key: Data, value: Priority) -> None: """ Inserts a new item into the queue :param key: The item to insert @@ -31,16 +65,25 @@ class PureQueue[T]: """ -class KeyedQueue[T](PureQueue[T]): - """A min-queue that disallows duplicates but offers the ability to update priorities and delete arbitrary items""" - def __setitem__(self, key: T, value: float) -> None: +class IndexedQueue[Data: Hashable, Priority: Comparable](Queue[Data]): + """ + A min-queue that allows arbitrary data associated with some priority. + Disallows duplicate data but offers the ability to update priorities and delete arbitrary items. + """ + + def __init__(self, items: dict[Data, Priority] | Iterable[tuple[Data, Priority]] | None = None) -> None: + """ + :param items: An optional mapping/list of items to priorities with which to initialize the queue + """ + + def __setitem__(self, key: Data, value: Priority) -> None: """ Inserts an item into the queue, or updates its priority if it already exists :param key: The item to insert or update :param value: The priority of the item """ - def __delitem__(self, key: T) -> None: + def __delitem__(self, key: Data) -> None: """ :param key: The item to delete from the queue """ diff --git a/requirements.txt b/requirements.txt index 880f18f..ba45a50 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,6 @@ +iniconfig==2.0.0 maturin==1.8.1 --e git+ssh://git@git.mmbradley.ca:222/MichaelBradley/pyority_queue.git@a09b71cdb32e2637971629623200cd639f5dcccb#egg=pyority_queue +packaging==24.2 +pluggy==1.5.0 +-e git+ssh://git@git.mmbradley.ca:222/MichaelBradley/pyority_queue.git@661e1d220ae71002d66d2ba2d3dfddfe4ff1035d#egg=pyority_queue +pytest==8.3.4 diff --git a/tests/pure_queue.py b/tests/pure_queue.py new file mode 100644 index 0000000..ce32069 --- /dev/null +++ b/tests/pure_queue.py @@ -0,0 +1,43 @@ +import pytest + +from pyority_queue import PureQueue + + +type PureQueueInitializer = list[int | float] | tuple[int | float, ...] + + +def test_empty_creation(): + queue = PureQueue() + assert len(queue) == 0 + + +@pytest.mark.parametrize("items", ([], [0, 1, 2], (0, 1, 2), (0.0, 1.0, 2.0), range(100))) +def test_creation(items: PureQueueInitializer): + queue = PureQueue() + assert len(queue) == len(items) + +@pytest.mark.parametrize("items", ([], (0,), (-1, 3), range(100))) +def test_iteration(items: PureQueueInitializer): + queue = PureQueue(items) + assert len(list(queue)) == len(items) + + +@pytest.mark.parametrize("items", ([], (-3, 5), (3.0, 2.0, 1.0), (3, 6, 8, 5, 7, 4, 2, 0), range(100))) +def test_sorting(items: PureQueueInitializer): + queue = PureQueue(items) + assert list(queue) == sorted(items) + + +def test_insertion(): + queue = PureQueue[int]((4, 2, 8, 6)) + queue.insert(7) + queue.insert(0) + queue.insert(3) + assert list(queue) == [0, 2, 3, 4, 6, 7, 8] + + +def test_duplicates(): + queue = PureQueue[int]((0, 0, 0, 5, 5)) + queue.insert(3) + queue.insert(3) + assert list(queue) == [0, 0, 0, 3, 3, 5, 5]