├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── benches ├── bench_bheap.rs └── bench_priq.rs ├── src ├── rawpq.rs └── priq.rs ├── README.md └── tests └── test_priq.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ main ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 7 | Cargo.lock 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | # Added by cargo 13 | # 14 | # already existing elements were commented out 15 | 16 | /target 17 | #Cargo.lock 18 | 19 | /.idea 20 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "priq" 3 | version = "0.2.0" 4 | edition = "2021" 5 | 6 | authors = ["Beka M. "] 7 | description = "Array implementation of the min/max heap" 8 | documentation = "https://docs.rs/priq" 9 | readme = "README.md" 10 | homepage = "https://github.com/bexxmodd/priq" 11 | 12 | license = "MIT" 13 | categories = ["data-structures"] 14 | keywords = ["priority", "queue", "data-structure"] 15 | 16 | exclude = [ "benches/bench_bheap.rs", ] 17 | 18 | [lib] 19 | name = "priq" 20 | path = "src/priq.rs" 21 | test = true 22 | doctest = true 23 | bench = false 24 | crate-type = ["lib"] 25 | 26 | [[bench]] 27 | name = "bench_priq" 28 | harness = false 29 | 30 | [dev-dependencies] 31 | bencher = "0.1.5" 32 | 33 | [dependencies] 34 | rand = "0.8.4" 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Beka Modebadze 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /benches/bench_bheap.rs: -------------------------------------------------------------------------------- 1 | //! Benchmarks 2 | 3 | #[macro_use] 4 | 5 | extern crate bencher; 6 | extern crate priq; 7 | 8 | use self::bencher::Bencher; 9 | use std::collections::BinaryHeap; 10 | 11 | /// Benchmark pushting 100 elements 12 | fn bh_push_100(b: &mut Bencher) { 13 | let mut bh = BinaryHeap::new(); 14 | let n = 100_usize; 15 | b.iter(|| { 16 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 17 | }); 18 | } 19 | 20 | /// Benchmark pushting 1k elements 21 | fn bh_push_1k(b: &mut Bencher) { 22 | let n = 1_000_usize; 23 | let mut bh = BinaryHeap::new(); 24 | b.iter(|| { 25 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 26 | }); 27 | } 28 | 29 | /// Benchmark pushting 10k elements 30 | fn bh_push_10k(b: &mut Bencher) { 31 | let mut bh = BinaryHeap::new(); 32 | let n = 10_000_usize; 33 | b.iter(|| { 34 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 35 | }); 36 | } 37 | 38 | /// Benchmark pushting 100k elements 39 | fn bh_push_100k(b: &mut Bencher) { 40 | let mut bh = BinaryHeap::new(); 41 | let n = 1_000_000_usize; 42 | b.iter(|| { 43 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 44 | }); 45 | } 46 | 47 | /// Benchmark pushting 1mil elements 48 | fn bh_push_1mil(b: &mut Bencher) { 49 | let n = 1_000_000_usize; 50 | let mut bh = BinaryHeap::new(); 51 | b.iter(|| { 52 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 53 | }); 54 | } 55 | 56 | /// Benchmark pop-ing 100 elements 57 | fn bh_pop_100(b: &mut Bencher) { 58 | let mut bh = BinaryHeap::new(); 59 | let n = 100_usize; 60 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 61 | b.iter(|| { 62 | (0..n).for_each(|_| { bh.pop(); }); 63 | }); 64 | } 65 | 66 | /// Benchmark pop-ing 1k elements 67 | fn bh_pop_1k(b: &mut Bencher) { 68 | let mut bh = BinaryHeap::new(); 69 | let n = 1_000_usize; 70 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 71 | b.iter(|| { 72 | (0..n).for_each(|_| { bh.pop(); }); 73 | }); 74 | } 75 | 76 | /// Benchmark pop-ing 10k elements 77 | fn bh_pop_10k(b: &mut Bencher) { 78 | let mut bh = BinaryHeap::new(); 79 | let n = 10_000_usize; 80 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 81 | b.iter(|| { 82 | (0..n).for_each(|_| { bh.pop(); }); 83 | }); 84 | } 85 | 86 | /// Benchmark pop-ing 100k elements 87 | fn bh_pop_100k(b: &mut Bencher) { 88 | let mut bh = BinaryHeap::new(); 89 | let n = 100_000_usize; 90 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 91 | b.iter(|| { 92 | (0..n).for_each(|_| { bh.pop(); }); 93 | }); 94 | } 95 | 96 | /// Benchmark pop-ing 1mil elements 97 | fn bh_pop_1mil(b: &mut Bencher) { 98 | let mut bh = BinaryHeap::new(); 99 | let n = 1_000_000_usize; 100 | (0..n).for_each(|i| { bh.push((i, i * 2)); }); 101 | b.iter(|| { 102 | (0..n).for_each(|_| { bh.pop(); }); 103 | }); 104 | } 105 | 106 | benchmark_group!( 107 | benches, 108 | bh_push_100, 109 | bh_push_1k, 110 | bh_push_10k, 111 | bh_push_100k, 112 | bh_push_1mil, 113 | bh_pop_100, 114 | bh_pop_1k, 115 | bh_pop_10k, 116 | bh_pop_100k, 117 | bh_pop_1mil, 118 | ); 119 | benchmark_main!(benches); 120 | -------------------------------------------------------------------------------- /src/rawpq.rs: -------------------------------------------------------------------------------- 1 | use std::mem; 2 | use std::ptr; 3 | use std::marker; 4 | use std::alloc; 5 | 6 | const INITIAL_CAPACITY: usize = 7; 7 | pub const MAX_ZST_CAPACITY: usize = 1 << (usize::BITS - 1); 8 | pub const MIN_CAPACITY: usize = 4; 9 | 10 | #[derive(Debug)] 11 | pub struct RawPQ { 12 | pub ptr: ptr::NonNull<(S, T)>, 13 | pub cap: usize, 14 | _marker: marker::PhantomData<(S, T)>, 15 | } 16 | 17 | unsafe impl Send for RawPQ {} 18 | unsafe impl Sync for RawPQ {} 19 | 20 | impl RawPQ { 21 | pub fn new() -> Self { 22 | let cap = match mem::size_of::<(S, T)>() { 23 | 0 => MAX_ZST_CAPACITY, 24 | _ => 0, 25 | }; 26 | 27 | RawPQ { 28 | ptr: ptr::NonNull::dangling(), 29 | cap, 30 | _marker: marker::PhantomData, 31 | } 32 | } 33 | 34 | pub fn with_capacity(cap: usize) -> Self { 35 | assert_ne!(cap, 0, "Capacity Overflow"); 36 | let layout = alloc::Layout::array::<(S, T)>(cap).unwrap(); 37 | 38 | assert!(layout.size() <= MAX_ZST_CAPACITY, "Allocation is too large"); 39 | let new_ptr = unsafe { alloc::alloc(layout) }; 40 | 41 | RawPQ { 42 | ptr: match ptr::NonNull::new(new_ptr as *mut (S, T)) { 43 | Some(p) => p, 44 | None => alloc::handle_alloc_error(layout), 45 | }, 46 | cap, 47 | _marker: marker::PhantomData, 48 | } 49 | } 50 | 51 | pub fn grow(&mut self) { 52 | assert_ne!(mem::size_of::<(S, T)>(), 0, "Capacity Overflow"); 53 | 54 | let (new_cap, new_layout) = match self.cap { 55 | 0 => (INITIAL_CAPACITY, 56 | alloc::Layout::array::<(S, T)>(INITIAL_CAPACITY).unwrap()), 57 | _ => { 58 | let new_cap = 2 * self.cap; 59 | let new_layout = alloc::Layout::array::<(S, T)>(new_cap) 60 | .unwrap(); 61 | (new_cap, new_layout) 62 | } 63 | }; 64 | 65 | assert!( 66 | new_layout.size() <= MAX_ZST_CAPACITY, "Allocation is too large" 67 | ); 68 | let new_ptr = match self.cap { 69 | 0 => unsafe { alloc::alloc(new_layout) }, 70 | _ => { 71 | let old_layout = alloc::Layout::array::<(S, T)>(self.cap) 72 | .unwrap(); 73 | let old_ptr = self.ptr.as_ptr() as *mut u8; 74 | unsafe { 75 | alloc::realloc(old_ptr, old_layout, new_layout.size()) 76 | } 77 | } 78 | }; 79 | 80 | self.ptr = match ptr::NonNull::new(new_ptr as *mut (S, T)) { 81 | Some(p) => p, 82 | None => alloc::handle_alloc_error(new_layout), 83 | }; 84 | self.cap = new_cap; 85 | } 86 | 87 | pub fn shrink(&mut self) { 88 | let old_layout = alloc::Layout::array::<(S, T)>(self.cap).unwrap(); 89 | let old_ptr = self.ptr.as_ptr() as *mut u8; 90 | let new_cap = self.cap / 2; 91 | let new_layout = alloc::Layout::array::<(S, T)>(new_cap).unwrap(); 92 | 93 | let new_ptr = unsafe { 94 | alloc::realloc(old_ptr, old_layout, new_layout.size()) 95 | }; 96 | 97 | self.ptr = match ptr::NonNull::new(new_ptr as *mut (S, T)) { 98 | Some(p) => p, 99 | None => alloc::handle_alloc_error(new_layout), 100 | }; 101 | self.cap = new_cap; 102 | } 103 | } 104 | 105 | impl Drop for RawPQ { 106 | fn drop(&mut self) { 107 | let elem_size = mem::size_of::<(S, T)>(); 108 | if self.cap != 0 && elem_size != 0 { 109 | unsafe { 110 | alloc::dealloc( 111 | self.ptr.as_ptr() as *mut u8, 112 | alloc::Layout::array::<(S, T)>(self.cap).unwrap(), 113 | ) 114 | } 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /benches/bench_priq.rs: -------------------------------------------------------------------------------- 1 | //! Benchmarks 2 | 3 | #[macro_use] 4 | 5 | extern crate bencher; 6 | extern crate priq; 7 | 8 | use priq::*; 9 | use self::bencher::Bencher; 10 | 11 | /// Benchmark putting 100 elements 12 | fn pq_put_100(b: &mut Bencher) { 13 | let mut pq: PriorityQueue = PriorityQueue::new(); 14 | let n = 100_usize; 15 | b.iter(|| { 16 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 17 | }); 18 | } 19 | 20 | /// Benchmark putting 1k elements 21 | fn pq_put_1k(b: &mut Bencher) { 22 | let mut pq: PriorityQueue = PriorityQueue::new(); 23 | let n = 1_000_usize; 24 | b.iter(|| { 25 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 26 | }); 27 | } 28 | 29 | /// Benchmark putting 10k elements 30 | fn pq_put_10k(b: &mut Bencher) { 31 | let mut pq: PriorityQueue = PriorityQueue::new(); 32 | let n = 10_000_usize; 33 | b.iter(|| { 34 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 35 | }); 36 | } 37 | 38 | /// Benchmark putting 100k elements 39 | fn pq_put_100k(b: &mut Bencher) { 40 | let mut pq: PriorityQueue = PriorityQueue::new(); 41 | let n = 100_000_usize; 42 | b.iter(|| { 43 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 44 | }); 45 | } 46 | 47 | /// Benchmark putting 1mil elements 48 | fn pq_put_1mil(b: &mut Bencher) { 49 | let mut pq: PriorityQueue = PriorityQueue::new(); 50 | let n = 1_000_000_usize; 51 | b.iter(|| { 52 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 53 | }); 54 | } 55 | 56 | /// Benchmark putting 100k elements with capacity constructor 57 | fn pq_put_100k_wcap(b: &mut Bencher) { 58 | let n = 100_000_usize; 59 | let mut pq: PriorityQueue = PriorityQueue::with_capacity(n); 60 | b.iter(|| { 61 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 62 | }); 63 | } 64 | 65 | /// Benchmark putting 1mil elements 66 | fn pq_put_1mil_wcap(b: &mut Bencher) { 67 | let n = 1_000_000_usize; 68 | let mut pq: PriorityQueue = PriorityQueue::with_capacity(n); 69 | b.iter(|| { 70 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 71 | }); 72 | } 73 | 74 | /// Benchmark pop-ing 100 elements 75 | fn pq_pop_100(b: &mut Bencher) { 76 | let mut pq: PriorityQueue = PriorityQueue::new(); 77 | let n = 100_usize; 78 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 79 | b.iter(|| { 80 | (0..n).for_each(|_| { pq.pop(); }); 81 | }); 82 | } 83 | 84 | /// Benchmark pop-ing 1k elements 85 | fn pq_pop_1k(b: &mut Bencher) { 86 | let mut pq: PriorityQueue = PriorityQueue::new(); 87 | let n = 1_000_usize; 88 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 89 | b.iter(|| { 90 | (0..n).for_each(|_| { pq.pop(); }); 91 | }); 92 | } 93 | 94 | /// Benchmark pop-ing 10k elements 95 | fn pq_pop_10k(b: &mut Bencher) { 96 | let mut pq: PriorityQueue = PriorityQueue::new(); 97 | let n = 10_000_usize; 98 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 99 | b.iter(|| { 100 | (0..n).for_each(|_| { pq.pop(); }); 101 | }); 102 | } 103 | 104 | /// Benchmark pop-ing 100k elements 105 | fn pq_pop_100k(b: &mut Bencher) { 106 | let mut pq: PriorityQueue = PriorityQueue::new(); 107 | let n = 100_000_usize; 108 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 109 | b.iter(|| { 110 | (0..n).for_each(|_| { pq.pop(); }); 111 | }); 112 | } 113 | 114 | /// Benchmark pop-ing 1mil elements 115 | fn pq_pop_1mil(b: &mut Bencher) { 116 | let mut pq: PriorityQueue = PriorityQueue::new(); 117 | let n = 1_000_000_usize; 118 | (0..n).for_each(|i| { pq.put(i, i * 2); }); 119 | b.iter(|| { 120 | (0..n).for_each(|_| { pq.pop(); }); 121 | }); 122 | } 123 | 124 | 125 | 126 | benchmark_group!( 127 | benches, 128 | pq_put_100, 129 | pq_put_1k, 130 | pq_put_10k, 131 | pq_put_100k, 132 | pq_put_1mil, 133 | pq_pop_100, 134 | pq_pop_1k, 135 | pq_pop_10k, 136 | pq_pop_100k, 137 | pq_pop_1mil, 138 | pq_put_100k_wcap, 139 | pq_put_1mil_wcap, 140 | ); 141 | benchmark_main!(benches); 142 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # priq 2 | 3 | Priority queue (min/max heap) using raw binary heap. 4 | 5 | `PriorityQueue` is built using raw array for efficient performance. 6 | 7 | There are two major reasons what makes this `PriorityQueue` different from 8 | other binary heap implementations currently available: 9 | 10 | 1 - Allows data ordering to scores with `PartialOrd`. 11 | - Every other min-max heap requires [total ordering](https://bit.ly/3GCWvYL) 12 | of scores (e.g. should implement `Ord` trait). This can be an issue, 13 | for example, when you want to order items based on a float scores, 14 | which doesn't implement `Ord` trait. 15 | - Because of partial ordering, non-comparable values are thrown in 16 | the end of the queue. One will see non-comparable values only after all 17 | the comparable elements have been `pop`-ed. 18 | - You can read about Rust's implementation or `Ord`, `PartialOrd` and 19 | what's the different [here](https://bit.ly/3J7NwQI) 20 | 21 | 2 - Separation of score and item you wish to store. 22 | - This frees enforcement for associated items to implement any ordering. 23 | - Makes easier to evaluate items' order. 24 | 25 | 3 - Equal scoring items are stored at first available free space. 26 | - This gives performance boost for large number of entries. 27 | 28 | 4 - Easy to use! 29 | 30 | You can read more about this crate on [my blog](https://www.bexxmodd.com) 31 | 32 | # Implementation 33 | 34 | A Min-Max Heap with designated arguments for `score` and associated `item`! 35 | 36 | A `Default` implementation is a Min-Heap where the top node (root) is the 37 | lowest scoring element: 38 | 39 | 10 40 | / \ 41 | 58 70 42 | / \ / \ 43 | 80 92 97 99 44 | 45 | > The value of Parent Node is small than Child Node. 46 | 47 | Every parent node, including the top (root) node, is less than or equal to 48 | equal to the right child. 49 | 50 | `PriorityQueue ` allows duplicate score/item values. When you [`put`]the 51 | item with a similar score that’s already in the queue new entry will be 52 | stored at the first empty location in memory. This gives an incremental 53 | performance boost (instead of resolving by using the associated item as a 54 | secondary tool to priority evaluation). Also, this form of implementation 55 | doesn’t enforce for the element `T` to have any implemented ordering. This 56 | guarantees that the top node will always be of minimum value. 57 | 58 | You can initialize an empty `PriorityQueue` and later add items: 59 | 60 | ```rust 61 | use priq::PriorityQueue; 62 | 63 | // create queue with `usize` key and `String` elements 64 | let pq: PriorityQueue = PriorityQueue::new(); 65 | ``` 66 | 67 | Or you can _heapify_ a `Vec` and/or a `slice`: 68 | 69 | ```rust 70 | use priq::PriorityQueue; 71 | 72 | let pq_from_vec = PriorityQueue::from(vec![(5, 55), (1, 11), (4, 44)]); 73 | let pq_from_slice = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 74 | ``` 75 | 76 | # Partial Ordering 77 | 78 | Because `priq` allows `score` arguments that only implement `PartialOrd`, 79 | elements that can't be compared are evaluated and are put in the back of 80 | the queue: 81 | 82 | ```rust 83 | use priq::PriorityQueue; 84 | 85 | let mut pq: PriorityQueue = PriorityQueue::new(); 86 | 87 | pq.put(1.1, 10); 88 | pq.put(f32::NAN, -1); 89 | pq.put(2.2, 20); 90 | pq.put(3.3, 30); 91 | pq.put(f32::NAN, -3); 92 | pq.put(4.4, 40); 93 | 94 | (1..=4).for_each(|i| assert_eq!(i * 10, pq.pop().unwrap().1)); 95 | 96 | // NAN scores will not have deterministic order 97 | // they are just stored after all the comparable scores 98 | assert!(0 > pq.pop().unwrap().1); 99 | assert!(0 > pq.pop().unwrap().1); 100 | ``` 101 | 102 | # Time 103 | 104 | The standard usage of this data structure is to [`put`] an element to the 105 | queue and [`pop`] to remove the top element and peek to check what’s the 106 | top element in the queue. The stored structure of the elements is a balanced 107 | tree realized using an array with a contiguous memory location. This allows 108 | maintaining a proper parent-child relationship between put-ed items. 109 | 110 | [`put`]: PriorityQueue::put 111 | [`peek`]: PriorityQueue::peek 112 | [`pop`]: PriorityQueue::pop 113 | 114 | 115 | Runtime complexity with Big-O Notation: 116 | 117 | | method | Time Complexity | 118 | |-----------|-----------------| 119 | | [`put`] | _O(log(n))_ | 120 | | [`pop`] | _O(log(n))_ | 121 | | [`peek`] | _O(1)_ | 122 | 123 | You can also iterate over elements using for loop but the returned slice 124 | will not be properly order as the heap is re-balanced after each insertion 125 | and deletion. If you want to grab items in a proper priority call [`pop`] 126 | in a loop until it returns `None`. 127 | 128 | 129 | # Custom `struct` 130 | 131 | What if you want to custom `struct ` without having a separate and 132 | specific score? You can pass the `struct`’s clone as a `score` and as an 133 | associated value, but if in this kind of scenario I’d recommend using 134 | [`BinaryHeap`] as it better fits the purpose. 135 | 136 | 137 | # Min-Heap 138 | 139 | If instead of Min-Heap you want to have Max-Heap, where the highest-scoring 140 | element is on top you can pass score using [`Reverse`] or a custom [`Ord`] 141 | implementation can be used to have custom prioritization logic. 142 | 143 | [`BinaryHeap`]: std::collections::BinaryHeap 144 | [`Reverse`]: std::cmp::Reverse 145 | 146 | # Example 147 | 148 | ```rust 149 | use priq::PriorityQueue; 150 | use std::cmp::Reverse; 151 | 152 | let mut pq: PriorityQueue, String> = PriorityQueue::new(); 153 | 154 | pq.put(Reverse(26), "Z".to_string()); 155 | pq.put(Reverse(1), "A".to_string()); 156 | 157 | assert_eq!(pq.pop().unwrap().1, "Z"); 158 | ``` 159 | # Merging and Combining 160 | 161 | You can merge another priority queue to this one. Right hand side priority 162 | queue will be drained into the left hand side priority queue. 163 | 164 | # Examples 165 | 166 | ```rust 167 | use priq::PriorityQueue; 168 | 169 | let mut pq1 = PriorityQueue::from([(5, 55), (6, 66), (3, 33), (2, 22)]); 170 | let mut pq2 = PriorityQueue::from([(4, 44), (1, 11)]); 171 | 172 | pq1.merge(&mut pq2); 173 | // at this point `pq2` is empty 174 | 175 | assert_eq!(6, pq1.len()); 176 | assert_eq!(11, pq1.peek().unwrap().1); 177 | ``` 178 | 179 | You can also use `+` operator to combine two priority queues. Operands will 180 | be intact. New priority queue will be build from cloning and merging them. 181 | 182 | # Example 183 | 184 | ```rust 185 | use priq::PriorityQueue; 186 | 187 | let pq1 = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 188 | let pq2 = PriorityQueue::from([(8, 44), (1, 22)]); 189 | 190 | let res = pq1 + pq2; 191 | 192 | assert_eq!(6, res.len()); 193 | assert_eq!(11, res.peek().unwrap().1); 194 | ``` 195 | 196 | ## Performance 197 | 198 | This are the benchmark results for `priq::PriorityQueue`: 199 | 200 | 201 | | `priq` benches | median | nanosecs | std.dev | 202 | |-----|-------:|:----------:|:--------| 203 | | pq_pop_100 | 146 | ns/iter | (+/- 1) 204 | | pq_pop_100k | 291,818 | ns/iter | (+/- 5,686) 205 | | pq_pop_10k | 14,129 | ns/iter | (+/- 39) 206 | | pq_pop_1k | 1,646 | ns/iter | (+/- 32) 207 | | pq_pop_1mil | 16,517,047 | ns/iter | (+/- 569,128| 208 | | pq_put_100 | 488 | ns/iter | (+/- 21) 209 | | pq_put_100k | 758,422 | ns/iter | (+/- 13,961) 210 | | pq_put_100k_wcap| 748,824 | ns/iter | (+/- 7,926) 211 | | pq_put_10k | 80,668 | ns/iter | (+/- 1,324) 212 | | pq_put_1k | 8,769 | ns/iter | (+/- 78) 213 | | pq_put_1mil | 6,728,203 | ns/iter | (+/- 76,416) 214 | | pq_put_1mil_wcap| 6,622,341 | ns/iter | (+/- 77,162) 215 | 216 | 217 | How it compares to `std::collections::BinaryHeap`: 218 | 219 | | `BinaryHeap` benches | median | nanosecs | std.dev | 220 | |-----|-------:|:----------:|:--------| 221 | | bh_pop_100 | 272 | ns/iter | (+/- 90) 222 | | bh_pop_100k | 171,071 | ns/iter | (+/- 6,131) 223 | | bh_pop_10k | 13,904 | ns/iter | (+/- 130) 224 | | bh_pop_1k | 1,847 | ns/iter | (+/- 6) 225 | | bh_pop_1mil | 8,772,066 | ns/iter | (+/- 611,613) 226 | | bh_push_100 | 857 | ns/iter | (+/- 50) 227 | | bh_push_100k| 943,465 | ns/iter | (+/- 108,698) 228 | | bh_push_10k | 92,807 | ns/iter | (+/- 7,930) 229 | | bh_push_1k | 8,606 | ns/iter | (+/- 639) 230 | | bh_push_1mil| 12,946,815 | ns/iter | (+/- 900,347) 231 | 232 | 233 | ------------ 234 | Project is distributed under the MIT license. Please see the `LICENSE` for more information. 235 | -------------------------------------------------------------------------------- /tests/test_priq.rs: -------------------------------------------------------------------------------- 1 | #![feature(test)] 2 | 3 | use priq::PriorityQueue; 4 | 5 | use std::cmp::Reverse; 6 | use rand::{seq::SliceRandom, thread_rng}; 7 | 8 | 9 | #[test] 10 | fn pq_base() { 11 | let pq: PriorityQueue = PriorityQueue::new(); 12 | assert!(pq.is_empty()); 13 | } 14 | 15 | #[test] 16 | fn pq_wcapacity() { 17 | let pq: PriorityQueue = PriorityQueue::with_capacity(100); 18 | assert!(pq.is_empty()); 19 | } 20 | 21 | #[test] 22 | fn pq_put_one() { 23 | let mut pq: PriorityQueue = PriorityQueue::new(); 24 | pq.put(24, String::from("Erti")); 25 | assert_eq!(1, pq.len()); 26 | } 27 | 28 | #[test] 29 | fn pq_put_two() { 30 | let mut pq: PriorityQueue = PriorityQueue::new(); 31 | pq.put(1.0, String::from("Erti")); 32 | pq.put(2.0, String::from("Ori")); 33 | assert_eq!(2, pq.len()); 34 | } 35 | 36 | #[test] 37 | fn pq_put_three() { 38 | let mut pq: PriorityQueue = PriorityQueue::new(); 39 | pq.put(1.0, String::from("Erti")); 40 | pq.put(2.0, String::from("Ori")); 41 | pq.put(3.0, String::from("Sami")); 42 | assert_eq!(3, pq.len()); 43 | } 44 | 45 | #[test] 46 | fn pq_as_max_heap() { 47 | let mut pq: PriorityQueue, String> = PriorityQueue::new(); 48 | pq.put(Reverse(26), "Z".to_string()); 49 | pq.put(Reverse(1), "A".to_string()); 50 | assert_eq!(pq.pop().unwrap().1, "Z"); 51 | } 52 | 53 | #[test] 54 | fn pq_put_four_and_grow() { 55 | let mut pq: PriorityQueue = PriorityQueue::new(); 56 | pq.put(1, String::from("Erti")); 57 | pq.put(2, String::from("Ori")); 58 | pq.put(3, String::from("Sami")); 59 | pq.put(4, String::from("Otxi")); 60 | assert_eq!(4, pq.len()); 61 | } 62 | 63 | #[test] 64 | fn pq_put_100000_items() { 65 | let mut pq: PriorityQueue = PriorityQueue::new(); 66 | (0..100000).rev().for_each(|i| { pq.put(i, i * 2); }); 67 | assert_eq!(100000, pq.len()); 68 | assert_eq!(0, pq.peek().unwrap().1); 69 | } 70 | 71 | #[test] 72 | fn pq_peek_base() { 73 | let mut pq: PriorityQueue = PriorityQueue::new(); 74 | pq.put(1, String::from("Erti")); 75 | assert_eq!("Erti", pq.peek().unwrap().1); 76 | } 77 | 78 | #[test] 79 | fn pq_peek_sorted_items() { 80 | let mut pq: PriorityQueue = PriorityQueue::new(); 81 | pq.put(1, String::from("Erti")); 82 | pq.put(2, String::from("Ori")); 83 | pq.put(3, String::from("Sami")); 84 | assert_eq!(1, pq.peek().unwrap().0); 85 | assert_eq!("Erti", pq.peek().unwrap().1); 86 | } 87 | 88 | #[test] 89 | fn pq_peek_unsorted_items() { 90 | let mut pq: PriorityQueue = PriorityQueue::new(); 91 | pq.put(2, String::from("Ori")); 92 | pq.put(3, String::from("Sami")); 93 | pq.put(0, String::from("Me")); 94 | pq.put(1, String::from("Erti")); 95 | assert_eq!(0, pq.peek().unwrap().0); 96 | assert_eq!("Me", pq.peek().unwrap().1); 97 | } 98 | 99 | #[test] 100 | fn pq_pop_base() { 101 | let mut pq: PriorityQueue = PriorityQueue::new(); 102 | assert!(pq.pop().is_none()); 103 | 104 | pq.put(1, String::from("Beka")); 105 | assert_eq!("Beka", pq.pop().unwrap().1); 106 | assert!(pq.is_empty()); 107 | } 108 | 109 | #[test] 110 | fn pq_pop_with_four_unordered_items() { 111 | let mut pq: PriorityQueue = PriorityQueue::new(); 112 | pq.put(2, String::from("Ori")); 113 | pq.put(3, String::from("Sami")); 114 | pq.put(4, String::from("Otxi")); 115 | pq.put(0, String::from("Me")); 116 | assert_eq!(4, pq.len()); 117 | assert_eq!("Me", pq.pop().unwrap().1); 118 | assert_eq!("Ori", pq.pop().unwrap().1); 119 | assert_eq!("Sami", pq.pop().unwrap().1); 120 | assert_eq!("Otxi", pq.pop().unwrap().1); 121 | assert!(pq.pop().is_none()); 122 | } 123 | 124 | #[test] 125 | fn pq_pop_100000_items_ordered() { 126 | let mut pq: PriorityQueue = PriorityQueue::new(); 127 | (0..100000).for_each(|i| { 128 | pq.put(i, -i); 129 | }); 130 | assert_eq!(100000, pq.len()); 131 | 132 | (0..100000).for_each(|i| { 133 | let item = pq.pop().unwrap(); 134 | assert_eq!(i, item.0, "Incorrect order of Scores"); 135 | assert_eq!(-i, item.1, "Incorrect write of Items"); 136 | }); 137 | assert!(pq.is_empty()); 138 | } 139 | 140 | #[test] 141 | fn pq_pop_100000_items_unordered() { 142 | let mut pq: PriorityQueue = PriorityQueue::new(); 143 | let mut rng = thread_rng(); 144 | 145 | let mut scores: Vec = (0..100000).collect(); 146 | scores.shuffle(&mut rng); 147 | 148 | (0..100000).for_each(|i| { 149 | pq.put(scores[i], i + 1); 150 | }); 151 | assert_eq!(100000, pq.len()); 152 | 153 | (0..100000).for_each(|i| { 154 | let item = pq.pop().unwrap(); 155 | assert_eq!(i, item.0, "Incorrect order of Scores"); 156 | }); 157 | assert!(pq.is_empty()); 158 | } 159 | 160 | #[test] 161 | #[should_panic] 162 | fn pq_try_pop_when_empty() { 163 | let mut pq = PriorityQueue::::new(); 164 | pq.try_pop(); 165 | } 166 | 167 | #[test] 168 | fn pq_try_pop_base() { 169 | let mut pq = PriorityQueue::::new(); 170 | pq.put(4, 39); 171 | assert_eq!(39, pq.try_pop().1); 172 | } 173 | 174 | 175 | #[test] 176 | fn pq_from_vec() { 177 | let vec = vec![(5, 55), (1, 11), (4, 44), (2, 22), (3, 33)]; 178 | let mut pq = PriorityQueue::from(vec); 179 | assert_eq!(5, pq.len()); 180 | assert_eq!(11, pq.pop().unwrap().1); 181 | assert_eq!(22, pq.pop().unwrap().1); 182 | } 183 | 184 | #[test] 185 | fn pq_from_slice() { 186 | let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 187 | assert_eq!(3, pq.len()); 188 | assert_eq!(11, pq.pop().unwrap().1); 189 | assert_eq!(44, pq.pop().unwrap().1); 190 | } 191 | 192 | #[test] 193 | fn pq_clear() { 194 | let mut pq: PriorityQueue = PriorityQueue::new(); 195 | pq.put(1, String::from("Erti")); 196 | pq.put(2, String::from("Ori")); 197 | pq.put(3, String::from("Sami")); 198 | pq.put(4, String::from("Otxi")); 199 | assert!(!pq.is_empty()); 200 | pq.clear(); 201 | assert!(pq.is_empty()); 202 | } 203 | 204 | #[test] 205 | fn pq_drain() { 206 | let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 207 | assert!(!pq.is_empty()); 208 | 209 | for (s, e) in pq.drain(..) { assert!(s > 0 && e > 0) }; 210 | assert!(pq.is_empty()); 211 | 212 | } 213 | 214 | #[test] 215 | fn pq_with_nan() { 216 | let mut pq: PriorityQueue = PriorityQueue::new(); 217 | pq.put(1.1, 10); 218 | pq.put(f32::NAN, -1); 219 | pq.put(2.2, 20); 220 | pq.put(3.3, 30); 221 | pq.put(f32::NAN, -3); 222 | pq.put(4.4, 40); 223 | 224 | (1..=4).for_each(|i| assert_eq!(i * 10, pq.pop().unwrap().1)); 225 | assert!(0 > pq.pop().unwrap().1); 226 | assert!(0 > pq.pop().unwrap().1); 227 | } 228 | 229 | #[test] 230 | fn pq_into_sorted_vec() { 231 | let pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 232 | assert_eq!(3, pq.len()); 233 | 234 | let mut res = pq.into_sorted_vec(); 235 | assert_eq!(3, res.len()); 236 | 237 | assert_eq!(55, res.pop().unwrap().1); 238 | assert_eq!(44, res.pop().unwrap().1); 239 | assert_eq!(11, res.pop().unwrap().1); 240 | } 241 | 242 | #[test] 243 | fn pq_into_sorted_vec_with_nan() { 244 | let mut pq: PriorityQueue = PriorityQueue::new(); 245 | pq.put(1.1, 10); 246 | pq.put(f32::NAN, -1); 247 | pq.put(2.2, 20); 248 | pq.put(3.3, 30); 249 | pq.put(f32::NAN, -3); 250 | pq.put(4.4, 40); 251 | let res = pq.into_sorted_vec(); 252 | 253 | assert_eq!(10, res[0].1); 254 | assert_eq!(20, res[1].1); 255 | assert_eq!(30, res[2].1); 256 | assert_eq!(40, res[3].1); 257 | assert!(res[4].1 < 0 && res[4].1 > -4); 258 | assert!(res[5].1 < 0 && res[5].1 > -4); 259 | } 260 | 261 | #[test] 262 | fn pq_build_from_iter() { 263 | let iter = (0..5).into_iter() 264 | .map(|i| (i, i * 2)); 265 | let pq = PriorityQueue::from_iter(iter); 266 | assert_eq!(5, pq.len()); 267 | assert_eq!(0, pq.peek().unwrap().1); 268 | } 269 | 270 | #[test] 271 | fn pq_build_and_collect() { 272 | let pq: PriorityQueue = (1..6).into_iter() 273 | .map(|i| (i, i + i)) 274 | .collect(); 275 | assert_eq!(5, pq.len()); 276 | assert_eq!(1, pq.peek().unwrap().0); 277 | } 278 | 279 | #[test] 280 | fn pq_into_ter() { 281 | let pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 282 | let res: PriorityQueue = pq.into_iter() 283 | .filter(|(s, _)| s > &2) 284 | .collect(); 285 | assert_eq!(2, res.len()); 286 | assert_eq!(44, res.peek().unwrap().1); 287 | } 288 | 289 | #[test] 290 | fn pq_drain_slice() { 291 | let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 292 | let res: PriorityQueue = pq.drain(1..).collect(); 293 | assert_eq!(3, res.len()); 294 | } 295 | 296 | #[test] 297 | fn pq_truncate_larger_len() { 298 | let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 299 | pq.truncate(6); 300 | assert_eq!(4, pq.len()); 301 | } 302 | 303 | #[test] 304 | fn pq_truncate() { 305 | let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 306 | pq.truncate(2); 307 | assert_eq!(2, pq.len()); 308 | assert_eq!(1, pq.pop().unwrap().0); 309 | assert_eq!(2, pq.pop().unwrap().0); 310 | assert_eq!(None, pq.peek()); 311 | } 312 | 313 | #[test] 314 | fn pq_truncate_clear() { 315 | let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 316 | pq.truncate(0); 317 | assert!(pq.is_empty()); 318 | } 319 | 320 | #[test] 321 | fn pq_clone() { 322 | let pq1 = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 323 | let pq2 = pq1.clone(); 324 | assert_eq!(4, pq1.len()); 325 | assert_eq!(4, pq2.len()); 326 | } 327 | 328 | #[test] 329 | fn pq_merge() { 330 | let mut pq1 = PriorityQueue::from([(5, 55), (1, 11), (3, 33), (2, 22)]); 331 | let mut pq2 = PriorityQueue::from([(4, 44), (6, 66)]); 332 | pq1.merge(&mut pq2); 333 | 334 | assert!(pq2.is_empty()); 335 | assert_eq!(6, pq1.len()); 336 | (1..=6).for_each(|i| { assert_eq!(i * 11, pq1.pop().unwrap().1); }) 337 | } 338 | 339 | #[test] 340 | fn pq_add_to_pq() { 341 | let pq1 = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 342 | let pq2 = PriorityQueue::from([(8, 44), (1, 22)]); 343 | let res = pq1 + pq2; 344 | assert_eq!(6, res.len()); 345 | assert_eq!(11, res.peek().unwrap().1); 346 | } 347 | 348 | #[test] 349 | fn pq_high_number_of_nan() { 350 | let mut pq = PriorityQueue::new(); 351 | pq.put(1f64, ()); 352 | pq.put(3f64, ()); 353 | pq.put(f64::NAN, ()); 354 | pq.put(f64::NAN, ()); 355 | println!("{:?}", pq.into_sorted_vec()); 356 | // assert_eq!(1f64, pq.try_pop().0); 357 | // assert_eq!(3f64, pq.try_pop().0); 358 | } 359 | 360 | #[test] 361 | fn pq_points_as_scores() { 362 | let mut pq = PriorityQueue::new(); 363 | pq.put((1, 2), ()); 364 | pq.put((0, 3), ()); 365 | pq.put((2, 4), ()); 366 | pq.put((5, 3), ()); 367 | pq.put((6, 7), ()); 368 | println!("{:?}", pq.into_sorted_vec()); 369 | } 370 | -------------------------------------------------------------------------------- /src/priq.rs: -------------------------------------------------------------------------------- 1 | #![feature(slice_range)] 2 | //! Priority queue (min/max heap) using raw binary heap. 3 | //! 4 | //! `PriorityQueue` is built using raw array for efficient performance. 5 | //! 6 | //! There are two major reasons what makes this `PriorityQueue` different from 7 | //! other binary heap implementations currently available: 8 | //! 9 | //! 1 - Allows data ordering to scores with `PartialOrd`. 10 | //! * Every other min-max heap requires [total ordering](https://bit.ly/3GCWvYL) 11 | //! of scores (e.g. should implement `Ord` trait). This can be an issue, 12 | //! for example, when you want to order items based on a float scores, 13 | //! which doesn't implement `Ord` trait. 14 | //! * Because of partial ordering, non-comparable values are thrown in 15 | //! the end of the queue. One will see non-comparable values only after all 16 | //! the comparable elements have been `pop`-ed. 17 | //! * You can read about Rust's implementation or `Ord`, `PartialOrd` and 18 | //! what's the different [here](https://bit.ly/3J7NwQI) 19 | //! 20 | //! 2 - Separation of score and item you wish to store. 21 | //! * This frees enforcement for associated items to implement any ordering. 22 | //! * Makes easier to evaluate items' order. 23 | //! 24 | //! 3 - Equal scoring items are stored at first available free space. 25 | //! * This gives performance boost for large number of entries. 26 | //! 27 | //! 4 - Easy to use! 28 | //! 29 | //! You can read more about this crate on [my blog](https://www.bexxmodd.com) 30 | 31 | extern crate rand; 32 | 33 | use std::mem; 34 | use std::ptr; 35 | use std::slice; 36 | use std::marker::PhantomData; 37 | use std::convert::From; 38 | use std::cmp::{self, Ordering}; 39 | use std::ops::{Add, Deref, DerefMut, Range, RangeBounds}; 40 | 41 | mod rawpq; 42 | use rawpq::RawPQ; 43 | 44 | /// A Min-Max Heap with designated arguments for `score` and associated `item`! 45 | /// 46 | /// A `Default` implementation is a Min-Heap where the top node (root) is the 47 | /// lowest scoring element: 48 | /// 49 | /// ```text 50 | /// 10 51 | /// / \ 52 | /// 58 70 53 | /// / \ / \ 54 | /// 80 92 97 99 55 | /// 56 | /// ``` 57 | /// 58 | /// > The value of Parent Node is small than Child Node. 59 | /// 60 | /// Every parent node, including the top (root) node, is less than or equal to 61 | /// equal to the right child. 62 | /// 63 | /// `PriorityQueue ` allows duplicate score/item values. When you [`put`]the 64 | /// item with a similar score that’s already in the queue new entry will be 65 | /// stored at the first empty location in memory. This gives an incremental 66 | /// performance boost (instead of resolving by using the associated item as a 67 | /// secondary tool to priority evaluation). Also, this form of implementation 68 | /// doesn’t enforce for the element `T` to have any implemented ordering. This 69 | /// guarantees that the top node will always be of minimum value. 70 | /// 71 | /// You can initialize an empty `PriorityQueue` and later add items: 72 | /// 73 | /// ``` 74 | /// use priq::PriorityQueue; 75 | /// 76 | /// // create queue with `usize` score and `String` elements 77 | /// let pq: PriorityQueue = PriorityQueue::new(); 78 | /// ``` 79 | /// 80 | /// You can _heapify_ a `Vec` and/or a `slice`: 81 | /// 82 | /// ``` 83 | /// use priq::PriorityQueue; 84 | /// 85 | /// let pq_from_vec = PriorityQueue::from(vec![(5, 55), (1, 11), (4, 44)]); 86 | /// let pq_from_slice = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 87 | /// ``` 88 | /// 89 | /// You can build priority queue from any iterable and collect elements. 90 | /// 91 | /// ``` 92 | /// use priq::PriorityQueue; 93 | /// 94 | /// // this will yield: (1, 2), (2, 4), (3, 6), (4, 8) 95 | /// let pq: PriorityQueue<_, _> = (1..5).into_iter() 96 | /// .map(|i| (i, i + i)) 97 | /// .collect(); 98 | /// assert_eq!(4, pq.len()); 99 | /// assert_eq!(1, pq.peek().unwrap().0); 100 | /// ``` 101 | /// 102 | /// # Partial Ordering 103 | /// 104 | /// Because `priq` allows `score` arguments that only implement `PartialOrd`, 105 | /// elements that can't be compared are evaluated and are put in the back of 106 | /// the queue: 107 | /// 108 | /// ``` 109 | /// use priq::PriorityQueue; 110 | /// 111 | /// let mut pq: PriorityQueue = PriorityQueue::new(); 112 | /// 113 | /// pq.put(1.1, 10); 114 | /// pq.put(f32::NAN, -1); 115 | /// pq.put(2.2, 20); 116 | /// pq.put(3.3, 30); 117 | /// pq.put(f32::NAN, -3); 118 | /// pq.put(4.4, 40); 119 | /// 120 | /// (1..=4).for_each(|i| assert_eq!(i * 10, pq.pop().unwrap().1)); 121 | /// 122 | /// // NAN scores will not have deterministic order 123 | /// // they are just stored after all the comparable scores 124 | /// assert!(0 > pq.pop().unwrap().1); 125 | /// assert!(0 > pq.pop().unwrap().1); 126 | /// ``` 127 | /// 128 | /// # Time 129 | /// 130 | /// The standard usage of this data structure is to [`put`] an element to the 131 | /// queue and [`pop`] to remove the top element and peek to check what’s the 132 | /// top element in the queue. The stored structure of the elements is a balanced 133 | /// tree realized using an array with a contiguous memory location. This allows 134 | /// maintaining a proper parent-child relationship between put-ed items. 135 | /// 136 | /// Runtime complexity with Big-O Notation: 137 | /// 138 | /// | method | Time Complexity | 139 | /// |-----------|-----------------| 140 | /// | [`put`] | _O(log(n))_ | 141 | /// | [`pop`] | _O(log(n))_ | 142 | /// | [`peek`] | _O(1)_ | 143 | /// 144 | /// You can also iterate over elements using for loop but the returned slice 145 | /// will not be properly order as the heap is re-balanced after each insertion 146 | /// and deletion. If you want to grab items in a proper priority call [`pop`] 147 | /// in a loop until it returns `None`. 148 | /// 149 | /// 150 | /// # Custom `struct` 151 | /// 152 | /// What if you want to custom `struct ` without having a separate and 153 | /// specific score? You can pass the `struct`’s clone as a `score` and as an 154 | /// associated value, but if in this kind of scenario I’d recommend using 155 | /// [`BinaryHeap`] as it better fits the purpose. 156 | /// 157 | /// 158 | /// # Min-Heap 159 | /// 160 | /// If instead of Min-Heap you want to have Max-Heap, where the highest-scoring 161 | /// element is on top you can pass score using [`Reverse`] or a custom [`Ord`] 162 | /// implementation can be used to have custom prioritization logic. 163 | /// 164 | /// # Example 165 | /// 166 | /// ``` 167 | /// use priq::PriorityQueue; 168 | /// use std::cmp::Reverse; 169 | /// 170 | /// let mut pq: PriorityQueue, String> = PriorityQueue::new(); 171 | /// 172 | /// pq.put(Reverse(26), "Z".to_string()); 173 | /// pq.put(Reverse(1), "A".to_string()); 174 | /// 175 | /// assert_eq!(pq.pop().unwrap().1, "Z"); 176 | /// ``` 177 | /// 178 | /// # Merging and Combining 179 | /// 180 | /// You can merge another priority queue to this one. Right hand side priority 181 | /// queue will be drained into the left hand side priority queue. 182 | /// 183 | /// # Examples 184 | /// 185 | /// ``` 186 | /// use priq::PriorityQueue; 187 | /// 188 | /// let mut pq1 = PriorityQueue::from([(5, 55), (6, 66), (3, 33), (2, 22)]); 189 | /// let mut pq2 = PriorityQueue::from([(4, 44), (1, 11)]); 190 | /// 191 | /// pq1.merge(&mut pq2); 192 | /// // at this point `pq2` is empty 193 | /// 194 | /// assert_eq!(6, pq1.len()); 195 | /// assert_eq!(11, pq1.peek().unwrap().1); 196 | /// ``` 197 | /// 198 | /// You can also use `+` operator to combine two priority queues. Operands will 199 | /// be intact. New priority queue will be build from cloning and merging them. 200 | /// 201 | /// # Example 202 | /// 203 | /// ``` 204 | /// use priq::PriorityQueue; 205 | /// 206 | /// let pq1 = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (2, 22)]); 207 | /// let pq2 = PriorityQueue::from([(8, 44), (1, 22)]); 208 | /// 209 | /// let res = pq1 + pq2; 210 | /// 211 | /// assert_eq!(6, res.len()); 212 | /// assert_eq!(11, res.peek().unwrap().1); 213 | /// ``` 214 | /// 215 | /// [`BinaryHeap`]: std::collections::BinaryHeap 216 | /// [`Reverse`]: std::cmp::Reverse 217 | /// [`put`]: PriorityQueue::put 218 | /// [`peek`]: PriorityQueue::peek 219 | /// [`pop`]: PriorityQueue::pop 220 | /// 221 | #[derive(Debug)] 222 | pub struct PriorityQueue 223 | where 224 | S: PartialOrd, 225 | { 226 | data: RawPQ, 227 | len: usize, 228 | } 229 | 230 | 231 | impl PriorityQueue 232 | where 233 | S: PartialOrd, 234 | { 235 | /// Create an empty `PriorityQueue` 236 | /// 237 | /// # Examples 238 | /// 239 | /// ``` 240 | /// use priq::PriorityQueue; 241 | /// 242 | /// let pq: PriorityQueue = PriorityQueue::new(); 243 | /// ``` 244 | #[inline] 245 | #[must_use] 246 | pub fn new() -> Self { 247 | PriorityQueue { 248 | data: RawPQ::new(), 249 | len: 0, 250 | } 251 | } 252 | 253 | /// If you expect that you’ll be putting at least `n` number of items in 254 | /// `PriorityQueue` you can create it with space of at least elements equal 255 | /// to `cap`. This can boost the performance for a large number of sets 256 | /// because it'll eliminate the need to grow the underlying array often. 257 | /// 258 | /// # Examples 259 | /// 260 | /// ``` 261 | /// use priq::PriorityQueue; 262 | /// 263 | /// let pq: PriorityQueue = PriorityQueue::with_capacity(100); 264 | /// ``` 265 | #[inline] 266 | #[must_use] 267 | pub fn with_capacity(cap: usize) -> Self { 268 | PriorityQueue { 269 | data: RawPQ::with_capacity(cap), 270 | len: 0, 271 | } 272 | } 273 | 274 | /// Inserts an element in the heap. 275 | /// 276 | /// # Examples 277 | /// 278 | /// ``` 279 | ///use priq::PriorityQueue; 280 | /// 281 | /// let mut pq: PriorityQueue = PriorityQueue::new(); 282 | /// pq.put(1, "Velkhana".to_string()); 283 | /// pq.put(2, "Shara".to_string()); 284 | /// assert_eq!(2, pq.len()); 285 | /// assert_eq!("Velkhana", pq.pop().unwrap().1); 286 | /// ``` 287 | /// 288 | /// Element’s exact location will be determined based on its `score`. The 289 | /// element will start as a last element in the `PriorityQueue` and then 290 | /// percolate up using insertion sort operations on the path from the end 291 | /// to the root to find the correct place for it. 292 | /// 293 | /// For example, we have a tree with scores **[2, 3, 4, 6, 9, 5, 4]** and 294 | /// we want to `put` an element with a score of ***1***: 295 | /// 296 | /// ```text 297 | /// 2 2 X <- 1 298 | /// / \ / \ / \ 299 | /// 3 4 3 X <- 1 3 2 300 | /// / \ / \ / \ / \ / \ / \ 301 | /// 6 9 5 X <- 1 6 9 5 4 6 9 5 4 302 | /// 303 | /// step 1. step 2. step 3. 304 | /// ``` 305 | /// 306 | /// On a `PriorityQueue` with `len == 7` to `put` a new element it made 307 | /// three operations, from the last position to the top (worst case). 308 | /// 309 | /// # Time Complexity 310 | /// 311 | /// For worst case scenario ***O(log(n))***. 312 | /// 313 | pub fn put(&mut self, score: S, item: T) { 314 | if self.cap() == self.len { self.data.grow(); } 315 | self.len += 1; 316 | 317 | // SAFETY: We're writing new element in the back of the array. We ensure 318 | // that this is safe by first checking if we have enough capacity 319 | // allocated, and if not we grow it to accommodate new entries. 320 | unsafe { 321 | ptr::write(self.ptr().add(self.len - 1), (score, item)) 322 | }; 323 | self.heapify_up(self.len - 1); 324 | } 325 | 326 | /// Get the top priority element from `PriorityQueue`. 327 | /// 328 | /// # Examples 329 | /// 330 | /// ``` 331 | /// use priq::PriorityQueue; 332 | /// 333 | /// let mut pq: PriorityQueue = PriorityQueue::new(); 334 | /// pq.put(2, String::from("Odo")); 335 | /// pq.put(3, String::from("Vaal")); 336 | /// pq.put(0, String::from("Nergi")); 337 | /// assert_eq!("Nergi", pq.pop().unwrap().1); 338 | /// assert_eq!("Odo", pq.pop().unwrap().1); 339 | /// ``` 340 | /// 341 | /// Element will be removed from the `PriorityQueue` and next lowest 342 | /// scoring item will be promoted as a top element (highest scoring if 343 | /// `PriorityQueue` is used as a Max Heap). 344 | /// 345 | /// After priority is removed and returned `PriorityQueue` will balance 346 | /// itself by promoting the next lowest scoring (or highest if Max Heap) 347 | /// element as a top node. First the last element in the array is moved as 348 | /// a top and percolated down with an insertion sort algorithm to find its 349 | /// correct place. This allows the next prioritized item to end at top. 350 | /// 351 | /// For example, we have a tree with scores **[1, 3, 2, 6, 9, 5, 4]**. 352 | /// After we `pop` top element we get following movement: 353 | /// 354 | /// ```text 355 | /// o -> 1 4 << 2 <- new top 356 | /// / \ / \ / \ 357 | /// 3 2 3 2 3 4 << 358 | /// / \ / \ / \ / / \ / 359 | /// 6 9 5 4 << 6 9 5 6 9 5 360 | /// 361 | /// step 1. step 2. step 3. 362 | /// ``` 363 | /// 364 | /// Parent-child relationship balanced itself from top to down and **2** 365 | /// became a new top (prioritized) element. 366 | /// 367 | /// # Time Complexity 368 | /// 369 | /// Worst case is ***O(log(n))***. 370 | pub fn pop(&mut self) -> Option<(S, T)> { 371 | if self.len > 0 { 372 | // TODO fix the algo 373 | let last_ = self.len - 1; 374 | // If any of the scores is uncomparable move it to the back 375 | let mut i = last_; 376 | while i > 0 && !self.comparable(&self[i].0, &self[i].0) { 377 | i -= 1; 378 | } 379 | if i != last_ { 380 | self.swap(0, i + 1); 381 | } 382 | 383 | unsafe { 384 | let _top = ptr::read(self.ptr()); 385 | let _tmp = ptr::read(self.ptr().add(self.len - 1)); 386 | 387 | // SAFETY: this is safe because the last element will written 388 | // in-place of the first element in an allocated space. 389 | ptr::write(self.ptr(), _tmp); 390 | 391 | self.len -= 1; 392 | 393 | if self.len > 1 { self.heapify_down(0); } 394 | if self.cap() > 1_000 && self.cap() / 4 >= self.len { 395 | self.data.shrink(); 396 | } 397 | Some(_top) 398 | } 399 | } else { None } 400 | } 401 | 402 | /// If you are sure that priority queue is NOT empty you can call `try_pop` 403 | /// to get prioritized element without a need to unwrap it. If the queue is 404 | /// empty this method will panic. 405 | /// 406 | /// # Examples 407 | /// 408 | /// ```should_panic 409 | /// use priq::PriorityQueue; 410 | /// 411 | /// let mut pq = PriorityQueue::::new(); 412 | /// pq.try_pop(); 413 | /// ``` 414 | /// 415 | /// But when priority queue is not empty it removes one layer of unwrapping 416 | /// 417 | /// ``` 418 | /// use priq::PriorityQueue; 419 | /// 420 | /// let mut pq = PriorityQueue::from([(4, -23), (76, 2)]); 421 | /// assert_eq!(-23, pq.try_pop().1); 422 | /// ``` 423 | pub fn try_pop(&mut self) -> (S, T) { 424 | if self.is_empty() { 425 | panic!("Can't `pop` from an empty priority queue"); 426 | } else { 427 | self.pop().unwrap() 428 | } 429 | } 430 | 431 | /// Check what is a top element in `PriorityQueue`, by getting the reference. 432 | /// 433 | /// # Examples 434 | /// 435 | /// ``` 436 | /// use priq::PriorityQueue; 437 | /// 438 | /// let mut pq: PriorityQueue = PriorityQueue::new(); 439 | /// assert!(pq.peek().is_none()); 440 | /// 441 | /// pq.put(1, String::from("Ruiner")); 442 | /// pq.put(3, String::from("Bazel")); 443 | /// pq.put(2, String::from("Jho")); 444 | /// assert_eq!(3, pq.len()); 445 | /// assert_eq!("Ruiner", pq.peek().unwrap().1); 446 | /// assert_eq!(3, pq.len()); 447 | /// ``` 448 | /// 449 | /// If `PriorityQueue` is empty it will return `None`. 450 | /// 451 | /// # Time Complexity 452 | /// 453 | /// `peek`-ing is done in a constant time ***O(1)*** 454 | pub fn peek(&self) -> Option<&(S, T)> { 455 | if !self.is_empty() { 456 | Some(&self[0]) 457 | } else { None } 458 | } 459 | 460 | /// Returns the number of elements in the `PriorityQueue` 461 | /// 462 | /// # Examples 463 | /// 464 | /// ``` 465 | /// use priq::PriorityQueue; 466 | /// 467 | /// let mut pq: PriorityQueue = PriorityQueue::new(); 468 | /// assert_eq!(0, pq.len()); 469 | /// 470 | /// pq.put(1, 99); 471 | /// assert_eq!(1, pq.len()); 472 | /// ``` 473 | #[inline] 474 | pub fn len(&self) -> usize { 475 | self.len 476 | } 477 | 478 | /// Returns `true` is there are no elements in `PriorityQueue` 479 | /// 480 | /// # Examples 481 | /// 482 | /// ``` 483 | /// use priq::PriorityQueue; 484 | 485 | /// let mut pq: PriorityQueue = PriorityQueue::new(); 486 | /// assert!(pq.is_empty()); 487 | /// 488 | /// pq.put(1, 99); 489 | /// assert!(!pq.is_empty()); 490 | /// ``` 491 | pub fn is_empty(&self) -> bool { 492 | self.len == 0 493 | } 494 | 495 | /// Remove all the elements from `PriorityQueue` 496 | /// 497 | /// # Example 498 | /// 499 | /// ``` 500 | /// use priq::PriorityQueue; 501 | /// 502 | /// let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 503 | /// assert!(!pq.is_empty()); 504 | /// 505 | /// pq.clear(); 506 | /// assert!(pq.is_empty()); 507 | /// ``` 508 | pub fn clear(&mut self) { 509 | self.drain(..); 510 | } 511 | 512 | /// Clears the priority queue, returning iterator over the removed elements 513 | /// returned items will NOT be in a sorted order. Method takes range as an 514 | /// argument. 515 | /// 516 | /// # Example 517 | /// 518 | /// ``` 519 | /// use priq::PriorityQueue; 520 | /// 521 | /// let mut pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44), (7, 77)]); 522 | /// assert!(!pq.is_empty()); 523 | /// 524 | /// // drain everything starting from index 2 till the end. 525 | /// let mut res: PriorityQueue = pq.drain(2..).collect(); 526 | /// assert!(pq.is_empty()); 527 | /// assert_eq!(2, res.len()); 528 | /// 529 | /// // drain the remaining priority queue by giving it full range (..) arg. 530 | /// res.drain(..); 531 | /// assert!(res.is_empty()); 532 | /// ``` 533 | pub fn drain(&mut self, range: R) -> Drain<'_, S, T> 534 | where 535 | R: RangeBounds, 536 | { 537 | let len = self.len(); 538 | let Range { start, end } = slice::range(range, ..len); 539 | 540 | // SAFETY: we are reading from row memory within a range from start to 541 | // the `len` where `len` we know is within a memory space of this 542 | // priority queue. 543 | unsafe { 544 | let range_slice = slice::from_raw_parts_mut( 545 | self.as_mut_ptr().add(start), end - start); 546 | 547 | let iter = RawPQIter::new(range_slice); 548 | 549 | // SAFETY: we set up `len` to zero so even if method panics, memory 550 | // leak will never happen. 551 | self.len = 0; 552 | 553 | Drain { 554 | pq: PhantomData, 555 | iter, 556 | } 557 | } 558 | } 559 | 560 | /// Clears the priority queue and returns `Vec` with elements in a 561 | /// sorted order. 562 | /// 563 | /// # Example 564 | /// 565 | /// ``` 566 | /// use priq::PriorityQueue; 567 | /// 568 | /// let pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 569 | /// 570 | /// let mut res = pq.into_sorted_vec(); 571 | /// assert_eq!(3, res.len()); 572 | /// 573 | /// // we'll be `pop`-ing values from the back of the vector. 574 | /// // this means highest scoring will be all the way back into the `Vec` 575 | /// assert_eq!(55, res.pop().unwrap().1); 576 | /// assert_eq!(44, res.pop().unwrap().1); 577 | /// assert_eq!(11, res.pop().unwrap().1); 578 | /// ``` 579 | /// 580 | /// If priority queue has NAN values they will be sorted after all 581 | /// comparable scores without any particular order 582 | /// 583 | /// ``` 584 | /// use priq::PriorityQueue; 585 | /// 586 | /// let mut pq: PriorityQueue = PriorityQueue::new(); 587 | /// pq.put(1.1, 10); 588 | /// pq.put(f32::NAN, -1); 589 | /// pq.put(2.2, 20); 590 | /// pq.put(3.3, 30); 591 | /// pq.put(f32::NAN, -3); 592 | /// pq.put(4.4, 40); 593 | /// let res = pq.into_sorted_vec(); 594 | /// 595 | /// assert_eq!(10, res[0].1); 596 | /// assert_eq!(20, res[1].1); 597 | /// assert_eq!(30, res[2].1); 598 | /// assert_eq!(40, res[3].1); 599 | /// assert!(res[4].1 < 0 && res[4].1 > -4); 600 | /// assert!(res[5].1 < 0 && res[5].1 > -4); 601 | /// ``` 602 | /// 603 | /// # Time 604 | /// 605 | /// This method drains priority queue into vector and sorts in 606 | /// ***O(n log(n))*** time. 607 | pub fn into_sorted_vec(mut self) -> Vec<(S, T)> { 608 | let mut res: Vec<(S, T)> = self.drain(..) 609 | .collect(); 610 | 611 | res.sort_by(|a, b| { 612 | match a.0.partial_cmp(&b.0) { 613 | Some(r) => r, 614 | None => Ordering::Less, 615 | } 616 | }); 617 | res 618 | } 619 | 620 | /// Reduce the length of a priority queue by keeping the first `len` 621 | /// elements and dropping the rest. 622 | /// 623 | /// If you pass `len` greater than the length of a priority queue this 624 | /// will have no effect. 625 | /// 626 | /// # Example 627 | /// 628 | /// truncate to keep the first three elements of priority queue. 629 | /// 630 | /// ``` 631 | /// use priq::PriorityQueue; 632 | /// 633 | /// let mut pq = PriorityQueue::from( 634 | /// [(5, 55), (1, 11), (4, 44), (2, 22), (7, 77), (8, 88)] 635 | /// ); 636 | /// 637 | /// pq.truncate(3); 638 | /// assert_eq!(3, pq.len()); 639 | /// assert_eq!(11, pq.peek().unwrap().1); 640 | /// ``` 641 | /// 642 | /// If we try to truncate with `len` > the length of a priority queue: 643 | /// 644 | /// ``` 645 | /// use priq::PriorityQueue; 646 | /// 647 | /// let mut pq = PriorityQueue::from([(4, 44), (2, 22), (7, 77), (8, 88)]); 648 | /// pq.truncate(5); 649 | /// 650 | /// assert_eq!(4, pq.len()); 651 | /// ``` 652 | pub fn truncate(&mut self, len: usize) { 653 | if len > self.len { 654 | return 655 | } 656 | 657 | // SAFETY: concerns are none for this because: 658 | // * `len` passed to the method is less than self.len so no invalid 659 | // slice can be created. 660 | // * self.len is reduced to a new size before `drop_in_place` is called. 661 | // no double free error in case `drop_in_place` panics. 662 | unsafe { 663 | let remaining = self.len - len; 664 | let s_ = ptr::slice_from_raw_parts_mut( 665 | self.as_mut_ptr().add(len), remaining); 666 | self.len = len; 667 | ptr::drop_in_place(s_); 668 | } 669 | } 670 | 671 | /// Merge second priority queue into this one. Values from the right hand 672 | /// side queue will be drained into the left hand side queue, leaving 673 | /// right hand side queue empty. 674 | /// 675 | /// # Examples 676 | /// 677 | /// ``` 678 | /// use priq::PriorityQueue; 679 | /// 680 | /// let mut pq1 = PriorityQueue::from([(5, 55), (1, 11), (3, 33), (2, 22)]); 681 | /// let mut pq2 = PriorityQueue::from([(4, 44), (6, 66)]); 682 | /// pq1.merge(&mut pq2); 683 | /// 684 | /// assert_eq!(6, pq1.len()); 685 | /// assert!(pq2.is_empty()); // rhs queue's elements are moved 686 | /// 687 | /// // assert that added elements are properly placed 688 | /// (1..=6).for_each(|i| { 689 | /// assert_eq!(i * 11, pq1.pop().unwrap().1); 690 | /// }); 691 | /// ``` 692 | pub fn merge(&mut self, pq: &mut PriorityQueue) { 693 | while !pq.is_empty() { 694 | let elem = pq.pop().unwrap(); 695 | self.put(elem.0, elem.1); 696 | } 697 | } 698 | 699 | /// Provides the raw pointer to the contiguous block of memory of data 700 | #[inline] 701 | fn ptr(&self) -> *mut (S, T) { 702 | self.data.ptr.as_ptr() 703 | } 704 | 705 | #[inline] 706 | /// Provides what's the current capacity of a underlying array 707 | fn cap(&self) -> usize { 708 | self.data.cap 709 | } 710 | 711 | /// Check if two values are comparable 712 | fn comparable(&self, lhs: &S, rhs: &S) -> bool { 713 | lhs.partial_cmp(rhs).is_some() 714 | } 715 | 716 | /// Generates the index of a left child (if any) of a item on a given index 717 | #[inline] 718 | fn left_child(&self, index: usize) -> usize { 719 | 2 * index + 1 720 | } 721 | 722 | /// Generates the index of a right child (if any) of a item on a given index 723 | #[inline] 724 | fn right_child(&self, index: usize) -> usize { 725 | 2 * index + 2 726 | } 727 | 728 | /// Generates the index of a parent item (if any) of a item on a given index 729 | #[inline] 730 | fn parent(&self, index: usize) -> usize { 731 | (index - 1) / 2 732 | } 733 | 734 | /// Checks if given item on provided index has a left child 735 | #[inline] 736 | fn has_left(&self, index: usize) -> bool { 737 | self.left_child(index) < self.len 738 | } 739 | 740 | /// Checks if given item on provided index has a right child 741 | #[inline] 742 | fn has_right(&self, index: usize) -> bool { 743 | self.right_child(index) < self.len 744 | } 745 | 746 | #[inline] 747 | #[allow(dead_code)] 748 | fn push(&mut self, elem: (S, T)) { 749 | unsafe { 750 | ptr::write(self.ptr().add(self.len), elem); 751 | } 752 | } 753 | 754 | /// After item is `pop`-ed this methods helps to balance remaining values 755 | /// so the prioritized item remains as a root. 756 | #[inline] 757 | fn heapify_up(&mut self, index: usize) { 758 | if index > 0 { 759 | let parent_ = self.parent(index); 760 | if self[parent_].0 > self[index].0 { 761 | self.swap(parent_, index); 762 | self.heapify_up(parent_); 763 | } 764 | } 765 | } 766 | 767 | /// Store inserted value into a proper position to maintain the balanced 768 | /// order of parent child relationships and prioritized item as a root. 769 | #[inline] 770 | fn heapify_down(&mut self, index: usize) { 771 | let _left = self.left_child(index); 772 | let _right = self.right_child(index); 773 | let mut min_ = index; 774 | if self.has_left(index) && self[_left].0 < self[min_].0 { 775 | min_ = _left; 776 | } 777 | if self.has_right(index) && self[_right].0 < self[min_].0 { 778 | min_ = _right; 779 | } 780 | if min_ != index { 781 | self.swap(index, min_); 782 | self.heapify_down(min_); 783 | } 784 | } 785 | } 786 | 787 | impl Default for PriorityQueue 788 | where 789 | S: PartialOrd, 790 | { 791 | #[inline] 792 | fn default() -> Self { 793 | PriorityQueue::new() 794 | } 795 | } 796 | 797 | impl Drop for PriorityQueue 798 | where 799 | S: PartialOrd, 800 | { 801 | fn drop(&mut self) { 802 | while self.pop().is_some() {} 803 | } 804 | } 805 | 806 | impl Deref for PriorityQueue 807 | where 808 | S: PartialOrd, 809 | { 810 | type Target = [(S, T)]; 811 | fn deref(&self) -> &[(S, T)] { 812 | unsafe { std::slice::from_raw_parts(self.ptr(), self.len) } 813 | } 814 | } 815 | 816 | impl DerefMut for PriorityQueue 817 | where 818 | S: PartialOrd, 819 | { 820 | fn deref_mut(&mut self) -> &mut [(S, T)] { 821 | unsafe { std::slice::from_raw_parts_mut(self.ptr(), self.len) } 822 | } 823 | } 824 | 825 | impl From> for PriorityQueue 826 | where 827 | S: PartialOrd, 828 | { 829 | /// Create `PriorityQueue` from a `Vec` 830 | /// 831 | /// # Examples 832 | /// 833 | /// ``` 834 | /// use priq::PriorityQueue; 835 | /// 836 | /// let vec = vec![(5, 55), (4, 44), (2, 22), (3, 33)]; 837 | /// let mut pq = PriorityQueue::from(vec); 838 | /// assert_eq!(4, pq.len()); 839 | /// assert_eq!(22, pq.pop().unwrap().1); 840 | /// ``` 841 | fn from(other: Vec<(S, T)>) -> Self { 842 | let len = other.len(); 843 | let _cap = rawpq::MIN_CAPACITY; 844 | match mem::size_of::<(S, T)>() { 845 | 0 => assert!(len < rawpq::MAX_ZST_CAPACITY, "Capacity Overflow"), 846 | _ => { 847 | let min_cap = cmp::max(rawpq::MIN_CAPACITY, len) + 1; 848 | let _cap = cmp::max(min_cap, other.capacity()) 849 | .next_power_of_two(); 850 | } 851 | } 852 | 853 | let mut pq: PriorityQueue = PriorityQueue::with_capacity(_cap); 854 | other.into_iter() 855 | .for_each(|(s, e)| pq.put(s, e)); 856 | pq 857 | } 858 | } 859 | 860 | impl From<[(S, T); N]> for PriorityQueue 861 | where 862 | S: PartialOrd, 863 | { 864 | /// Create `PriorityQueue` from a slice 865 | /// 866 | /// # Examples 867 | /// 868 | /// ``` 869 | /// use priq::PriorityQueue; 870 | /// 871 | /// let pq = PriorityQueue::from([(5, 55), (1, 11), (4, 44)]); 872 | /// assert_eq!(3, pq.len()); 873 | /// assert_eq!(11, pq.peek().unwrap().1); 874 | /// ``` 875 | fn from(arr: [(S, T); N]) -> Self { 876 | let mut pq: PriorityQueue = PriorityQueue::with_capacity(N); 877 | if mem::size_of::<(S, T)>() != 0 { 878 | arr.into_iter() 879 | .for_each(|(s, e)| pq.put(s, e)); 880 | } 881 | pq 882 | } 883 | } 884 | 885 | impl FromIterator<(S, T)> for PriorityQueue 886 | where 887 | S: PartialOrd 888 | { 889 | /// Or you can create `PriorityQueue` from any iterable collection. This 890 | /// also allows to use `collect` method to collect iterable elements into 891 | /// a `PriorityQueue`. This allows to build a PriorityQueuety collection 892 | /// through `into_iter`. 893 | /// 894 | /// # Example 895 | /// 896 | /// ``` 897 | /// use priq::PriorityQueue; 898 | /// 899 | /// // build an iterator 900 | /// let iter = (0..5).into_iter() 901 | /// .map(|i| (i, i * 2)); 902 | /// 903 | /// // create a priority queue from it 904 | /// let pq = PriorityQueue::from_iter(iter); 905 | /// 906 | /// assert_eq!(5, pq.len()); 907 | /// assert_eq!(0, pq.peek().unwrap().1); 908 | /// ``` 909 | /// 910 | /// Building priority queue while iterating over values with `collect` 911 | /// 912 | /// ``` 913 | /// use priq::PriorityQueue; 914 | /// 915 | /// let pq: PriorityQueue<_, _> = (1..6).into_iter() 916 | /// .map(|i| (i, i + i)) 917 | /// .collect(); 918 | /// assert_eq!(5, pq.len()); 919 | /// assert_eq!(1, pq.peek().unwrap().0); 920 | /// ``` 921 | fn from_iter>(iter: I) -> Self { 922 | let mut pq_ = PriorityQueue::new(); 923 | iter.into_iter() 924 | .for_each(|(s, e)| pq_.put(s, e)); 925 | pq_ 926 | } 927 | } 928 | 929 | impl Clone for PriorityQueue 930 | where 931 | S: PartialOrd 932 | { 933 | fn clone(&self) -> Self { 934 | let mut dst = PriorityQueue::::with_capacity(self.len + 1); 935 | 936 | // SAFETY: precondition ensures the source is aligned and valid, 937 | // and creating `with_capacity` ensures there is enough memory 938 | // allocated for a copy priority queue. 939 | unsafe { 940 | ptr::copy(self.ptr(), dst.as_mut_ptr(), self.len); 941 | } 942 | 943 | // SAFETY: we cloned queue with this capacity so we update its `len` too. 944 | dst.len = self.len; 945 | dst 946 | } 947 | } 948 | 949 | impl Add for PriorityQueue 950 | where 951 | S: PartialOrd 952 | { 953 | type Output = Self; 954 | fn add(self, rhs: Self) -> Self::Output { 955 | let mut res: PriorityQueue = self; 956 | let mut rhs_ = rhs; 957 | res.merge(&mut rhs_); 958 | res 959 | } 960 | } 961 | 962 | pub struct IntoIter { 963 | _buf: RawPQ, 964 | iter: RawPQIter, 965 | } 966 | 967 | impl Iterator for IntoIter { 968 | type Item = (S, T); 969 | 970 | fn next(&mut self) -> Option { 971 | self.iter.next() 972 | } 973 | 974 | fn size_hint(&self) -> (usize, Option) { 975 | self.iter.size_hint() 976 | } 977 | } 978 | 979 | impl Drop for IntoIter { 980 | fn drop(&mut self) { 981 | for _ in &mut *self {} 982 | } 983 | } 984 | 985 | impl IntoIterator for PriorityQueue 986 | where 987 | S: PartialOrd + Clone 988 | { 989 | type Item = (S, T); 990 | type IntoIter = IntoIter; 991 | 992 | fn into_iter(self) -> Self::IntoIter { 993 | unsafe { 994 | let iter = RawPQIter::new(&self); 995 | let _buf = ptr::read(&self.data); 996 | mem::forget(self); 997 | 998 | IntoIter { iter, _buf, } 999 | } 1000 | } 1001 | } 1002 | 1003 | struct RawPQIter { 1004 | start: *const (S, T), 1005 | end: *const (S, T), 1006 | } 1007 | 1008 | impl RawPQIter { 1009 | unsafe fn new(slice: &[(S, T)]) -> Self { 1010 | RawPQIter { 1011 | start: slice.as_ptr(), 1012 | end: if mem::size_of::<(S, T)>() == 0 { 1013 | ((slice.as_ptr() as usize) + slice.len()) as *const _ 1014 | } else if slice.is_empty() { 1015 | slice.as_ptr() 1016 | } else { 1017 | slice.as_ptr().add(slice.len()) 1018 | } 1019 | } 1020 | } 1021 | } 1022 | 1023 | impl Iterator for RawPQIter { 1024 | type Item = (S, T); 1025 | fn next(&mut self) -> Option { 1026 | if self.start == self.end { 1027 | None 1028 | } else { 1029 | unsafe { 1030 | let res = ptr::read(self.start); 1031 | self.start = match mem::size_of::<(S, T)>() { 1032 | 0 => (self.start as usize + 1) as *const _, 1033 | _ => self.start.offset(1), 1034 | }; 1035 | Some(res) 1036 | } 1037 | } 1038 | } 1039 | 1040 | fn size_hint(&self) -> (usize, Option) { 1041 | let len = self.end as usize - self.start as usize; 1042 | match mem::size_of::<(S, T)>() { 1043 | 0 => (len, Some(len)), 1044 | i => (len / i, Some(len / i)), 1045 | } 1046 | } 1047 | } 1048 | 1049 | pub struct Drain<'a, S: 'a, T: 'a> 1050 | where 1051 | S: PartialOrd, 1052 | { 1053 | pq: PhantomData<&'a mut PriorityQueue>, 1054 | iter: RawPQIter, 1055 | } 1056 | 1057 | impl<'a, S, T> Iterator for Drain<'a, S, T> 1058 | where 1059 | S: PartialOrd, 1060 | { 1061 | type Item = (S, T); 1062 | 1063 | fn next(&mut self) -> Option { 1064 | self.iter.next() 1065 | } 1066 | 1067 | fn size_hint(&self) -> (usize, Option) { 1068 | self.iter.size_hint() 1069 | } 1070 | } 1071 | 1072 | impl<'a, S, T> Drop for Drain<'a, S, T> 1073 | where 1074 | S: PartialOrd, 1075 | { 1076 | fn drop(&mut self) { 1077 | for _ in &mut *self {} 1078 | } 1079 | } 1080 | --------------------------------------------------------------------------------