Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 8 additions & 15 deletions src/double_priority_queue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,9 @@ use crate::core_iterators::*;
use crate::store::{left, level, parent, right};
use crate::store::{Index, Position, Store};
use crate::TryReserveError;
use equivalent::Equivalent;
use iterators::*;

use std::borrow::Borrow;
use std::cmp::{Eq, Ord};
#[cfg(feature = "std")]
use std::collections::hash_map::RandomState;
Expand Down Expand Up @@ -720,8 +720,7 @@ where
/// The operation is performed in **O(log(N))** time.
pub fn change_priority<Q>(&mut self, item: &Q, new_priority: P) -> Option<P>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store
.change_priority(item, new_priority)
Expand All @@ -741,8 +740,7 @@ where
/// The operation is performed in **O(log(N))** time (worst case).
pub fn change_priority_by<Q, F>(&mut self, item: &Q, priority_setter: F) -> bool
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
F: FnOnce(&mut P),
{
self.store
Expand All @@ -756,8 +754,7 @@ where
/// Get the priority of an item, or `None`, if the item is not in the queue
pub fn get_priority<Q>(&self, item: &Q) -> Option<&P>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.get_priority(item)
}
Expand All @@ -767,8 +764,7 @@ where
/// Returns `true` if `item` is in the queue, `false` if it is not.
pub fn contains<Q>(&self, item: &Q) -> bool
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.contains(item)
}
Expand All @@ -777,8 +773,7 @@ where
/// or `None` if the item is not in the queue.
pub fn get<Q>(&self, item: &Q) -> Option<(&I, &P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.get(item)
}
Expand All @@ -795,8 +790,7 @@ where
/// [`change_priority_by`](DoublePriorityQueue::change_priority_by).
pub fn get_mut<Q>(&mut self, item: &Q) -> Option<(&mut I, &P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.get_mut(item)
}
Expand All @@ -808,8 +802,7 @@ where
/// The operation is performed in **O(log(N))** time (worst case).
pub fn remove<Q>(&mut self, item: &Q) -> Option<(I, P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.remove(item).map(|(item, priority, pos)| {
if pos.0 < self.len() {
Expand Down
23 changes: 8 additions & 15 deletions src/priority_queue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ use crate::core_iterators::*;
use crate::store::{left, parent, right};
use crate::store::{Index, Position, Store};
use crate::TryReserveError;
use equivalent::Equivalent;
use iterators::*;

use std::borrow::Borrow;
use std::cmp::{Eq, Ord};
#[cfg(feature = "std")]
use std::collections::hash_map::RandomState;
Expand Down Expand Up @@ -594,8 +594,7 @@ where
/// The operation is performed in **O(log(N))** time.
pub fn change_priority<Q>(&mut self, item: &Q, new_priority: P) -> Option<P>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store
.change_priority(item, new_priority)
Expand All @@ -616,8 +615,7 @@ where
/// The operation is performed in **O(log(N))** time (worst case).
pub fn change_priority_by<Q, F>(&mut self, item: &Q, priority_setter: F) -> bool
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
F: FnOnce(&mut P),
{
self.store
Expand All @@ -631,8 +629,7 @@ where
/// Get the priority of an item, or `None`, if the item is not in the queue
pub fn get_priority<Q>(&self, item: &Q) -> Option<&P>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.get_priority(item)
}
Expand All @@ -642,8 +639,7 @@ where
/// Returns `true` if `item` is in the queue, `false` if it is not.
pub fn contains<Q>(&self, item: &Q) -> bool
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.contains(item)
}
Expand All @@ -652,8 +648,7 @@ where
/// or `None` if the item is not in the queue.
pub fn get<Q>(&self, item: &Q) -> Option<(&I, &P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.get(item)
}
Expand All @@ -670,8 +665,7 @@ where
/// [`change_priority_by`](PriorityQueue::change_priority_by).
pub fn get_mut<Q>(&mut self, item: &Q) -> Option<(&mut I, &P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.get_mut(item)
}
Expand Down Expand Up @@ -707,8 +701,7 @@ where
/// The operation is performed in **O(log(N))** time (worst case).
pub fn remove<Q>(&mut self, item: &Q) -> Option<(I, P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.store.remove(item).map(|(item, priority, pos)| {
if pos.0 < self.len() {
Expand Down
23 changes: 8 additions & 15 deletions src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ use std::vec::Vec;
// as vec instead of the IndexMap
use crate::core_iterators::*;
use crate::TryReserveError;
use equivalent::Equivalent;

use std::borrow::Borrow;
use std::cmp::{Eq, Ord};
#[cfg(feature = "std")]
use std::collections::hash_map::RandomState;
Expand Down Expand Up @@ -420,8 +420,7 @@ where
/// The operation is performed in **O(log(N))** time.
pub fn change_priority<Q>(&mut self, item: &Q, mut new_priority: P) -> Option<(P, Position)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
let Store { map, qp, .. } = self;
map.get_full_mut(item).map(|(index, _, p)| {
Expand All @@ -436,8 +435,7 @@ where
/// The operation is performed in **O(log(N))** time (worst case).
pub fn change_priority_by<Q, F>(&mut self, item: &Q, priority_setter: F) -> Option<Position>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
F: FnOnce(&mut P),
{
let Store { map, qp, .. } = self;
Expand All @@ -450,8 +448,7 @@ where
/// Get the priority of an item, or `None`, if the item is not in the queue
pub fn get_priority<Q>(&self, item: &Q) -> Option<&P>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.map.get(item)
}
Expand All @@ -461,8 +458,7 @@ where
/// Returns `true` if `item` is in the store, `false` if it is not.
pub fn contains<Q>(&self, item: &Q) -> bool
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.map.contains_key(item)
}
Expand All @@ -471,8 +467,7 @@ where
/// or `None` if the item is not in the queue.
pub fn get<Q>(&self, item: &Q) -> Option<(&I, &P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.map.get_full(item).map(|(_, k, v)| (k, v))
}
Expand All @@ -488,16 +483,14 @@ where
/// `change_priority_by`.
pub fn get_mut<Q>(&mut self, item: &Q) -> Option<(&mut I, &P)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.map.get_full_mut2(item).map(|(_, k, v)| (k, &*v))
}

pub fn remove<Q>(&mut self, item: &Q) -> Option<(I, P, Position)>
where
I: Borrow<Q>,
Q: Eq + Hash + ?Sized,
Q: ?Sized + Equivalent<I> + Hash,
{
self.map.swap_remove_full(item).map(|(i, item, priority)| {
let i = Index(i);
Expand Down
139 changes: 139 additions & 0 deletions tests/double_priority_queue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1057,6 +1057,145 @@ mod doublepq_tests {
assert_eq!(dpq.pop_min(), Some(('c', 1)));
}

#[test]
fn equivalent_blanket_implementation() {
let mut dpq = DoublePriorityQueue::new();

// Push with owned String
dpq.push("Alice".to_string(), 10);
dpq.push("Bob".to_string(), 20);

// Test get_priority with &str (uses String's blanket Equivalent impl)
assert_eq!(dpq.get_priority("Alice"), Some(&10));
assert_eq!(dpq.get_priority("Bob"), Some(&20));
assert_eq!(dpq.get_priority("Charlie"), None);

// Test contains with &str
assert!(dpq.contains("Alice"));
assert!(dpq.contains("Bob"));
assert!(!dpq.contains("Charlie"));

// Test change_priority with &str
assert_eq!(dpq.change_priority("Alice", 25), Some(10));
assert_eq!(dpq.get_priority("Alice"), Some(&25));

// Test change_priority_by with &str
assert!(dpq.change_priority_by("Alice", |p| *p += 5));
assert_eq!(dpq.get_priority("Alice"), Some(&30));

// Test get with &str
let (item, priority) = dpq.get("Bob").unwrap();
assert_eq!(item, "Bob");
assert_eq!(*priority, 20);

// Test get_mut with &str
let (item_mut, priority) = dpq.get_mut("Bob").unwrap();
assert_eq!(item_mut, "Bob");
assert_eq!(*priority, 20);

// Test remove with &str
assert_eq!(dpq.remove("Bob"), Some(("Bob".to_string(), 20)));
assert!(!dpq.contains("Bob"));
}

#[test]
fn equivalent_custom_implementation() {
use equivalent::Equivalent;
use std::hash::Hash;

#[derive(Debug, PartialEq, Eq, Hash)]
struct Person {
id: u32,
name: String,
age: u16,
}

#[derive(Debug, PartialEq, Eq, Hash)]
struct PersonView<'a> {
id: u32,
name: &'a str,
age: u16,
}

impl<'a> Equivalent<Person> for PersonView<'a> {
fn equivalent(&self, key: &Person) -> bool {
self.id == key.id && self.name == key.name && self.age == key.age
}
}

let mut dpq = DoublePriorityQueue::new();

// Create test persons
let alice = Person {
id: 1,
name: "Alice".to_string(),
age: 30,
};
let bob = Person {
id: 2,
name: "Bob".to_string(),
age: 25,
};

// Push persons into queue
dpq.push(alice, 100);
dpq.push(bob, 200);

// Create PersonView instances for querying
let alice_view = PersonView {
id: 1,
name: "Alice",
age: 30,
};
let bob_view = PersonView {
id: 2,
name: "Bob",
age: 25,
};
let charlie_view = PersonView {
id: 3,
name: "Charlie",
age: 35,
};

// Test get_priority with PersonView
assert_eq!(dpq.get_priority(&alice_view), Some(&100));
assert_eq!(dpq.get_priority(&bob_view), Some(&200));
assert_eq!(dpq.get_priority(&charlie_view), None);

// Test contains with PersonView
assert!(dpq.contains(&alice_view));
assert!(dpq.contains(&bob_view));
assert!(!dpq.contains(&charlie_view));

// Test change_priority with PersonView
assert_eq!(dpq.change_priority(&alice_view, 300), Some(100));
assert_eq!(dpq.get_priority(&alice_view), Some(&300));

// Test change_priority_by with PersonView
assert!(dpq.change_priority_by(&alice_view, |p| *p += 50));
assert_eq!(dpq.get_priority(&alice_view), Some(&350));

// Test get with PersonView
let (person, priority) = dpq.get(&bob_view).unwrap();
assert_eq!(person.name, "Bob");
assert_eq!(*priority, 200);

// Test get_mut with PersonView
let (person_mut, priority) = dpq.get_mut(&bob_view).unwrap();
assert_eq!(person_mut.name, "Bob");
assert_eq!(*priority, 200);

// Test remove with PersonView
let removed = dpq.remove(&bob_view);
assert!(removed.is_some());
let (removed_person, removed_priority) = removed.unwrap();
assert_eq!(removed_person.id, 2);
assert_eq!(removed_person.name, "Bob");
assert_eq!(removed_priority, 200);
assert!(!dpq.contains(&bob_view));
}

#[test]
fn user_test() {
use priority_queue::PriorityQueue;
Expand Down
Loading