iter_merge/
internal.rs

1//! Internal implementation details of this library.
2//!
3//! Typically you shouldn't need to touch these types, unless you're implementing another
4//! storage backend for iter-merge.
5//!
6//! [`PeekIter`] holds an iterator and the eagerly peeked item from it. The iterator with the
7//! smallest (according to the [`comparator`](crate::comparators)) [`item`](PeekIter::item)
8//! will be advanced.
9//!
10//! [`PeekIter`]s are stored within some contiguous allocation of `MaybeUninit<PeekIter>` type in
11//! order of insertion (to make [`tie breakers`](crate::comparators::tie_breaker) work by comparing
12//! `&PeekIter::item` by numeric pointer value).
13//!
14//! The heap is a contiguous allocation of `*mut PeekIter` type. Pointers in the heap represent
15//! all currently live `PeekIter`s. This library only works with the heap via [`BaseStorage`] trait.
16//!
17//! Heap is constructed to store `*mut PeekIter`s in the following order:
18//! ```custom
19//! [
20//!     smallest,
21//!     second_smallest (also the root of the binary min-heap),
22//!     second_smallest_child_1, second_smallest_child_2,
23//!     ...
24//! ]
25//! ```
26mod heap;
27use core::mem;
28pub(crate) mod nums;
29pub(crate) mod pointers;
30
31pub(crate) use heap::Heap;
32mod hole;
33pub(crate) use hole::Hole;
34
35/// Holds within itself one peeked item from the iterator and the iterator itself.
36/// It's like [`iter::Peekable`](core::iter::Peekable), except eager.
37#[derive(Debug)]
38pub struct PeekIter<IT: Iterator> {
39    /// Item peeked from the iter
40    pub item: IT::Item,
41    /// Iterator, containing the rest of the items
42    pub iter: IT,
43}
44
45impl<IT> Clone for PeekIter<IT>
46where
47    IT: Iterator + Clone,
48    IT::Item: Clone,
49{
50    fn clone(&self) -> Self {
51        Self {
52            item: self.item.clone(),
53            iter: self.iter.clone(),
54        }
55    }
56}
57
58impl<IT: Iterator> PeekIter<IT> {
59    const _CHECK: () = assert!(
60        mem::size_of::<Self>() > 0,
61        "iter-merge doesn't work when both iterator and item are ZST",
62    );
63
64    /// Create a new [`PeekIter`] from a `peeked_item` and `iter`
65    #[inline]
66    pub const fn new(peeked_item: IT::Item, iter: IT) -> Self {
67        Self {
68            item: peeked_item,
69            iter,
70        }
71    }
72
73    /// Advances the iterator, returning current peeked [`item`](Self::item) and replacing it
74    /// with new item from the [`iter`](Self::iter). If `iter` is out of items - returns None,
75    /// with [`item`](Self::item) being the last item of the iterator.
76    pub fn advance(&mut self) -> Option<IT::Item> {
77        let Self { item, iter } = self;
78        iter.next().map(|new_item| mem::replace(item, new_item))
79    }
80
81    /// Create a new [`PeekIter`] from an `iter`
82    ///
83    /// If the iterator is empty - returns None.
84    pub fn new_from_iter<Iter>(iter: Iter) -> Option<Self>
85    where
86        Iter: IntoIterator<IntoIter = IT>,
87    {
88        let mut iter = iter.into_iter();
89        iter.next()
90            .map(move |peeked_item| Self::new(peeked_item, iter))
91    }
92}
93
94/// Trait implemented by all storage backends.
95///
96/// # Invariant
97/// Assuming no external mutation of pointers or length, after any call to this library first
98/// [`len`](BaseStorage::len) elements of [`heap`](BaseStorage::heap) are valid unique pointers to
99/// valid [`PeekIter`] items.
100///
101/// In other words, [`heap`](BaseStorage::heap) upholds all of the properties to be treated as a
102/// slice `&[&mut PeekIter]` with length [`len`](BaseStorage::len)
103///
104/// # Safety
105/// Storage (conceptually) represents an owned array of [`PeekIter<IT: Iterator>`] with length
106/// `len()`, that could be accessed indirectly via heap of `*mut PeekIter` with length
107/// [`len`](BaseStorage::len).
108///
109/// Simple way to satisfy all these contracts:
110/// * allocate and fill `[PeekIter; CAP]`, do not access or create references until `drop()`;
111///   make sure that this allocation could not move (pinned) until the `drop()`
112/// * allocate `[*mut PeekIter; CAP]` and fill it with pointers to previous
113///   allocation, do not access or create references until drop, make sure that this allocation
114///   could not move (pinned) until the `drop()`
115/// * Provide access to the second allocation as [`BaseStorage::heap`], and to its length as
116///   [`BaseStorage::len`], initially equal to `CAP`
117/// * In `Drop`:
118///   * deallocate the remaining live [`PeekIter`]s via call to
119///     [`StorageOps::clear()`](crate::internal::StorageOps::clear)
120///   * deallocate heap and storage, assuming that they are uninitialized, with the same initial
121///     capacity
122///     (`[MaybeUninit<*mut PeekIter>; CAP]` and `[MaybeUninit<PeekIter>; CAP]`)
123#[allow(clippy::len_without_is_empty)]
124pub unsafe trait BaseStorage {
125    /// Iterator contained in this storage
126    type IT: Iterator;
127
128    /// Pointer to the heap of pointers
129    fn heap(&self) -> *mut *mut PeekIter<Self::IT>;
130
131    /// Length of the heap of pointers
132    fn len(&self) -> usize;
133
134    /// Set the length of the storage
135    /// # Safety
136    /// Caller guarantees that heap elements in `self.len()..new_len` are initialized
137    unsafe fn set_len(&mut self, new_len: usize);
138
139    /// Returns true if [`Self::len`](crate::internal::BaseStorage::len) == 0
140    #[inline]
141    fn is_empty(&self) -> bool {
142        self.len() == 0
143    }
144}
145
146/// Provides access to the iterator type within the storage
147pub type Iter<S> = <S as BaseStorage>::IT;
148/// Provides access to the iterator's item type within the storage
149pub type Item<S> = <Iter<S> as Iterator>::Item;
150
151/// Extra methods for working with [`BaseStorage`] for this library
152///
153/// It is implemented automatically for all implementors of [`BaseStorage`]
154pub trait StorageOps: BaseStorage {
155    /// Decrements length by 1 and returns the new length.
156    /// Does nothing to the last item, so
157    /// `self.heap().add(self.dec_len())` is still a valid pointer to a live item,
158    /// but you are guaranteed that this trait will never return it again (if safety contracts
159    /// are not broken)
160    /// # Safety
161    /// Caller guarantees that `self.len()` > 0
162    #[inline]
163    unsafe fn dec_len(&mut self) -> usize {
164        let mut len = self.len();
165        debug_assert!(len != 0);
166        len = len.wrapping_sub(1);
167        // SAFETY: decreasing length is safe, caller guaranteed that len != 0
168        unsafe {
169            self.set_len(len);
170        }
171        len
172    }
173
174    /// Produces pointer to the first (smallest) item
175    /// Pointers are valid, initialized and unique
176    /// It's valid to treat them as mut refs if no other
177    /// mut refs to the `first()` exist.
178    /// # Safety
179    /// Caller guarantees that `len()` >= 1
180    #[inline]
181    unsafe fn first(&self) -> *mut *mut PeekIter<Self::IT> {
182        debug_assert!(self.len() >= 1);
183        self.heap()
184    }
185
186    /// Produces pointer to the second (second-smallest) item
187    /// which is also the root of the binary heap.
188    /// Pointers are valid, initialized and unique
189    /// It's valid to treat them as mut refs if no other
190    /// mut refs to the `second()` exist.
191    /// # Safety
192    /// Caller guarantees that `len()` >= 2
193    #[inline]
194    unsafe fn second(&self) -> *mut *mut PeekIter<Self::IT> {
195        debug_assert!(self.len() >= 2);
196        // SAFETY: caller guarantees it's safe
197        unsafe { self.heap().add(1) }
198    }
199
200    /// Produces pointer to the last item in the heap and decrements its length
201    /// by 1.
202    /// Pointers are valid, initialized and unique
203    /// It's valid to treat them as mut refs.
204    /// # Safety
205    /// Caller guarantees that `len()` != 0.
206    /// The operation will produce the same pointer as
207    /// `first()` or `second()` if `len()` is 1 or 2.
208    #[inline]
209    unsafe fn pop_last(&mut self) -> *mut PeekIter<Self::IT> {
210        debug_assert!(self.len() != 0);
211        // SAFETY: caller guarantees it's safe
212        unsafe { self.heap().add(self.dec_len()).read() }
213    }
214
215    /// Drops all remaining items in the storage and sets its length to 0.
216    /// It's safe to call multiple times (repeated calls are no-ops)
217    fn clear(&mut self) {
218        let len = self.len();
219        // SAFETY: decreasing length is safe
220        unsafe {
221            self.set_len(0);
222        }
223        for i in 0..len {
224            // SAFETY: this operations are valid for `len` heap items
225            unsafe {
226                self.heap().add(i).read().drop_in_place();
227            };
228        }
229    }
230
231    /// Iterates over all items in the heap and calls `func` for each
232    /// Only the first two items are in order, order of the rest is *unspecified*.
233    #[inline]
234    fn map_items(&self, mut func: impl FnMut(&PeekIter<Self::IT>)) {
235        for i in 0..self.len() {
236            func(
237                // SAFETY: pointers up to self.len() are valid
238                unsafe { &**self.heap().add(i) },
239            );
240        }
241    }
242
243    /// Peeks the first item of the heap
244    #[inline]
245    fn peek(&self) -> Option<&Item<Self>> {
246        if self.is_empty() {
247            return None;
248        }
249        // SAFETY: len >= 1
250        Some(unsafe { &(**self.first()).item })
251    }
252
253    /// Pops the last item+iterator tuple in the heap (no order guaranteed, heap structure is preserved)
254    #[inline]
255    fn pop_last_item(&mut self) -> Option<(Item<Self>, Self::IT)> {
256        if self.is_empty() {
257            return None;
258        }
259        // SAFETY: self.len() != 0, heap items are valid
260        let PeekIter { item, iter } = unsafe { self.heap().add(self.dec_len()).read().read() };
261        Some((item, iter))
262    }
263}
264
265impl<S: BaseStorage> StorageOps for S {}