Simplify IndexedQueue API

Although similar to PureQueue, it doesn't make sense to use the exact
same signatures. Also don't make API users use Pair<D, P>.
This commit is contained in:
Michael Bradley 2025-01-13 22:07:43 +13:00
parent 16c1a4d390
commit 63515e2314
Signed by: MichaelBradley
SSH key fingerprint: SHA256:cj/YZ5VT+QOKncqSkx+ibKTIn0Obg7OIzwzl9BL8EO8
3 changed files with 40 additions and 56 deletions

View file

@ -1,6 +1,6 @@
use std::{collections::HashMap, hash::Hash}; use std::{collections::HashMap, hash::Hash};
use crate::backing::{containers::Pair, indexed::IndexedBacking, pure::PureBacking}; use crate::backing::{containers::Pair, indexed::IndexedBacking};
pub struct IndexedBinaryHeap<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> { pub struct IndexedBinaryHeap<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> {
data: Vec<Pair<D, P>>, data: Vec<Pair<D, P>>,
@ -16,26 +16,10 @@ impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> Indexed
} }
} }
impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> FromIterator<Pair<D, P>> impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> FromIterator<(D, P)>
for IndexedBinaryHeap<D, P> for IndexedBinaryHeap<D, P>
{ {
fn from_iter<T: IntoIterator<Item = Pair<D, P>>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = (D, P)>>(iter: T) -> Self {
todo!()
}
}
impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> PureBacking<Pair<D, P>>
for IndexedBinaryHeap<D, P>
{
fn add(&mut self, item: Pair<D, P>) {
todo!()
}
fn pop(&mut self) -> Option<Pair<D, P>> {
todo!()
}
fn len(&self) -> usize {
todo!() todo!()
} }
} }
@ -43,15 +27,23 @@ impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> PureBac
impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> IndexedBacking<D, P> impl<D: Hash + Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync> IndexedBacking<D, P>
for IndexedBinaryHeap<D, P> for IndexedBinaryHeap<D, P>
{ {
fn update(&mut self, data: D, priority: P) -> bool { fn len(&self) -> usize {
todo!()
}
fn remove(&mut self, data: D) -> bool {
todo!() todo!()
} }
fn contains(&self, data: &D) -> bool { fn contains(&self, data: &D) -> bool {
todo!() todo!()
} }
fn set(&mut self, data: D, priority: P) {
todo!()
}
fn remove(&mut self, data: D) -> Option<P> {
todo!()
}
fn pop(&mut self) -> Option<D> {
todo!()
}
} }

View file

@ -3,16 +3,18 @@ mod binary_heap;
pub use binary_heap::IndexedBinaryHeap; pub use binary_heap::IndexedBinaryHeap;
use super::{containers::Pair, pure::PureBacking};
/// A data structure usable for backing an "indexed" queue /// A data structure usable for backing an "indexed" queue
pub trait IndexedBacking<D: Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync>: pub trait IndexedBacking<D: Clone + Send + Sync, P: PartialOrd + Clone + Send + Sync>:
PureBacking<Pair<D, P>> Send + Sync
{ {
/// Update an item's priority /// The length of the queue
fn update(&mut self, data: D, priority: P) -> bool; fn len(&self) -> usize;
/// Remove an item from the queue
fn remove(&mut self, data: D) -> bool;
/// Check if an item is already in the queue /// Check if an item is already in the queue
fn contains(&self, data: &D) -> bool; fn contains(&self, data: &D) -> bool;
/// Set an item's priority, will update if the item is already enqueued
fn set(&mut self, data: D, priority: P);
/// Remove a specific item from the queue, returns the associated priority if the item existed
fn remove(&mut self, data: D) -> Option<P>;
/// Remove the top of the queue, if it exists
fn pop(&mut self) -> Option<D>;
} }

View file

@ -1,11 +1,11 @@
use pyo3::{ use pyo3::{
exceptions::{PyIndexError, PyKeyError, PyRuntimeError, PyStopIteration, PyTypeError}, exceptions::{PyIndexError, PyKeyError, PyStopIteration, PyTypeError},
prelude::*, prelude::*,
types::{PyDict, PyType}, types::{PyDict, PyType},
}; };
use crate::backing::{ use crate::backing::{
containers::{Pair, PyItem}, containers::PyItem,
indexed::{IndexedBacking, IndexedBinaryHeap}, indexed::{IndexedBacking, IndexedBinaryHeap},
}; };
@ -35,26 +35,16 @@ impl IndexedQueue {
} }
} }
fn __setitem__(mut self_: PyRefMut<'_, Self>, key: Py<PyAny>, value: f64) -> PyResult<()> { fn __setitem__(mut self_: PyRefMut<'_, Self>, key: Py<PyAny>, value: f64) {
let data = PyItem::new(key); self_.backing.set(PyItem::new(key), value)
if self_.backing.contains(&data) {
if self_.backing.update(data, value) {
Ok(())
} else {
Err(PyErr::new::<PyRuntimeError, _>("Key could not be updated"))
}
} else {
Ok(self_.backing.add(Pair::new(data, value)))
}
} }
fn __delitem__(mut self_: PyRefMut<'_, Self>, key: Py<PyAny>) -> PyResult<()> { fn __delitem__(mut self_: PyRefMut<'_, Self>, key: Py<PyAny>) -> PyResult<()> {
if self_.backing.remove(PyItem::new(key)) { match self_.backing.remove(PyItem::new(key)) {
Ok(()) Some(_) => Ok(()),
} else { None => Err(PyErr::new::<PyKeyError, _>(
Err(PyErr::new::<PyKeyError, _>(
"Key was not contained in queue", "Key was not contained in queue",
)) )),
} }
} }
@ -78,7 +68,7 @@ impl IndexedQueue {
fn __next__(mut self_: PyRefMut<'_, Self>) -> PyResult<Py<PyAny>> { fn __next__(mut self_: PyRefMut<'_, Self>) -> PyResult<Py<PyAny>> {
if let Some(item) = self_.backing.pop() { if let Some(item) = self_.backing.pop() {
Ok(item.data().data()) Ok(item.data())
} else { } else {
Err(PyErr::new::<PyStopIteration, _>(())) Err(PyErr::new::<PyStopIteration, _>(()))
} }
@ -86,7 +76,7 @@ impl IndexedQueue {
fn pop(mut self_: PyRefMut<'_, Self>) -> PyResult<Py<PyAny>> { fn pop(mut self_: PyRefMut<'_, Self>) -> PyResult<Py<PyAny>> {
if let Some(item) = self_.backing.pop() { if let Some(item) = self_.backing.pop() {
Ok(item.data().data()) Ok(item.data())
} else { } else {
Err(PyErr::new::<PyIndexError, _>(())) Err(PyErr::new::<PyIndexError, _>(()))
} }
@ -95,7 +85,7 @@ impl IndexedQueue {
impl<'py> IndexedQueue { impl<'py> IndexedQueue {
/// Tries to a Python object into a vector suitable for ingestion into the backing /// Tries to a Python object into a vector suitable for ingestion into the backing
fn from_any(object: &Bound<'py, PyAny>) -> PyResult<Vec<Pair<PyItem, f64>>> { fn from_any(object: &Bound<'py, PyAny>) -> PyResult<Vec<(PyItem, f64)>> {
if let Ok(vec) = object.extract::<Vec<(Py<PyAny>, f64)>>() { if let Ok(vec) = object.extract::<Vec<(Py<PyAny>, f64)>>() {
Ok(Self::from_vec(vec)) Ok(Self::from_vec(vec))
} else { } else {
@ -116,18 +106,18 @@ impl<'py> IndexedQueue {
} }
/// Converts a vector of Python objects and priorities into a vector of items /// Converts a vector of Python objects and priorities into a vector of items
fn from_vec(list: Vec<(Py<PyAny>, f64)>) -> Vec<Pair<PyItem, f64>> { fn from_vec(list: Vec<(Py<PyAny>, f64)>) -> Vec<(PyItem, f64)> {
list.into_iter() list.into_iter()
.map(|(data, priority)| Pair::new(PyItem::new(data), priority)) .map(|(data, priority)| (PyItem::new(data), priority))
.collect() .collect()
} }
/// Converts a Python dictionary into a vector of items /// Converts a Python dictionary into a vector of items
fn from_dict(dict: &Bound<'py, PyDict>) -> PyResult<Vec<Pair<PyItem, f64>>> { fn from_dict(dict: &Bound<'py, PyDict>) -> PyResult<Vec<(PyItem, f64)>> {
if let Ok(items) = dict if let Ok(items) = dict
.into_iter() .into_iter()
.map(|(data, priority)| match priority.extract::<f64>() { .map(|(data, priority)| match priority.extract::<f64>() {
Ok(value) => Ok(Pair::new(PyItem::new(data.unbind()), value)), Ok(value) => Ok((PyItem::new(data.unbind()), value)),
Err(err) => Err(err), Err(err) => Err(err),
}) })
.collect::<Result<Vec<_>, _>>() .collect::<Result<Vec<_>, _>>()