eytzinger_interpolation/
lib.rs

1//! This crate implements the "eytzinger" (aka BFS) array layout where
2//! a binary search tree is stored by layer (instead of as a sorted array).
3//! This can have significant performance benefits
4//! (see [Khuong, Paul-Virak, and Pat Morin. "Array layouts for comparison-based searching."][1]).
5//!
6//! # Usage
7//!
8//! ```
9//! use eytzinger_interpolation::SliceExt;
10//! let mut data = [0, 1, 2, 3, 4, 5, 6];
11//! data.eytzingerize(&mut eytzinger_interpolation::permutation::InplacePermutator);
12//! assert_eq!(data, [3, 1, 5, 0, 2, 4, 6]);
13//! assert_eq!(data.eytzinger_search(&5), Some(2));
14//! assert_eq!(data.eytzinger_search_by(|x| x.cmp(&6)), Some(6));
15//! ```
16//!
17//! [1]: https://arxiv.org/pdf/1509.05053.pdf
18
19#![warn(missing_docs, missing_debug_implementations)]
20
21use permutation::*;
22use std::borrow::Borrow;
23use std::cmp::{Ord, Ordering};
24
25/// The basic building blocks this crate is made of.
26pub mod foundation {
27    /// Given an array size (`n`), tree layer index (`ipk`) and element index (`li`),
28    /// this function computes the index of this value in a sorted array.
29    ///
30    /// This is basically the core of this crate, everything else is trivial.
31    /// Also, you usually want to use `PermutationGenerator` instead for convenience.
32    ///
33    /// # How it works
34    ///
35    /// This computes the magic function:
36    ///
37    /// ```text
38    /// f(n, k) = 2^floor(log2(n+1)) * 2k  -  max(0, (1+k) * 2^floor(log2(n+1)) - (n + 1))  -  1
39    /// (where n ∈ ℕ, k ∈ [0, 1])
40    /// ```
41    ///
42    /// Because this is integer math: `k = zk * 2^-ipk`
43    /// And because we only care about certain values of zk: `zk = li * 2 + 1`
44    ///
45    /// Even though I discovered this on my own and am quite certain that it's correct,
46    /// I only have a very vague feeling about **why** it works. If you want to understand this
47    /// (you really don't!), have a look at this sequence:
48    ///
49    /// ```text
50    /// a_n = (2n - 2^floor(log2(2n)) + 1) / 2^floor(log2(2n))
51    /// (1/2, 1/4, 3/4, 1/8, 3/8, 5/8, 7/8, 1/16, 3/16, 5/16, 7/16, 9/16, 11/16, 13/16, 15/16, ...)
52    /// ```
53    ///
54    /// The basic idea is that this sequence basically establishes a mapping between a sorted array
55    /// and an eytzinger array: If you look at the plot sideways (literally), you can see the tree
56    /// with all its layers. The only secret sauce here is `2^floor(log2(x))` which is elementary to
57    /// get exponentially growing windows (to build tree layers).
58    #[inline]
59    pub fn get_permutation_element_by_node(n: usize, ipk: usize, li: usize) -> usize {
60        let zk = li * 2 + 1;
61        // k = zk * 2^-ipk
62
63        let last_power_of_two = (n + 2).next_power_of_two() / 2;
64
65        let y = (last_power_of_two >> (ipk - 1)) * zk;
66        let kp = y >> 1;
67        let x = kp + last_power_of_two; // (1+k) * last_power_of_two
68        let x = x.saturating_sub(n + 1);
69
70        //println!("n={} x={} y={} z={} kp={} lpot={}", n, x,y,z, kp, last_power_of_two);
71        y - x - 1
72    }
73
74    /// Converts an index in an eytzinger array to the corresponding tree coordinates `(ipk, li)`.
75    #[inline]
76    pub fn index_to_node(i: usize) -> (usize, usize) {
77        let ipk = (i + 2).next_power_of_two().trailing_zeros() as usize;
78        let li = i + 1 - (1 << (ipk - 1));
79        (ipk, li)
80    }
81
82    /// Given an array size (`n`) and an index into the eytzinger array (`ì`),
83    /// this function computes the index of this value in a sorted array.
84    ///
85    /// This is simply `index_to_node` + `get_permutation_element_by_node`.
86    #[inline]
87    pub fn get_permutation_element(n: usize, i: usize) -> usize {
88        let (ipk, li) = index_to_node(i);
89        get_permutation_element_by_node(n, ipk, li)
90    }
91}
92
93/// Abstractions around applying generic permutations using generic implementations.
94///
95/// You should pick one that matches your use case.
96pub mod permutation {
97    use std::iter::{Cloned, Enumerate};
98    use std::slice::Iter;
99
100    /// A generic permutation.
101    pub trait Permutation {
102        /// An iterator through the permutation.
103        /// This may be more efficient than indexing a counter.
104        type Iter: Iterator<Item = usize>;
105
106        /// Get an iterator.
107        fn iterable(&self) -> Self::Iter;
108        /// Index into this permutation.
109        fn index(&self, i: usize) -> usize;
110    }
111
112    impl<'a> Permutation for &'a [usize] {
113        type Iter = Cloned<Iter<'a, usize>>;
114
115        #[inline]
116        fn iterable(&self) -> Self::Iter {
117            self.iter().cloned()
118        }
119
120        #[inline]
121        fn index(&self, i: usize) -> usize {
122            self[i]
123        }
124    }
125
126    /// A generic permutator.
127    pub trait Permutator<T, P: ?Sized + Permutation> {
128        /// Applies the given permutation to the given array.
129        fn permute(&mut self, data: &mut [T], permutation: &P);
130    }
131
132    /// Simple permutator that does not allocate.
133    ///
134    /// Worst-case runtime is in `O(n^2)`, so you should only use this for small permutations.
135    #[derive(Clone, Copy, Debug, Default)]
136    pub struct InplacePermutator;
137
138    impl<T, P: ?Sized + Permutation> Permutator<T, P> for InplacePermutator {
139        #[inline]
140        fn permute(&mut self, data: &mut [T], permutation: &P) {
141            for (i, mut p) in permutation.iterable().enumerate() {
142                while p < i {
143                    p = permutation.index(p);
144                }
145
146                if p > i {
147                    data.swap(i, p);
148                }
149            }
150        }
151    }
152
153    /// Simple permutator that stack-allocates a copy of the data (using recursion).
154    ///
155    /// Worst-case runtime is `O(n)`, but this takes `O(n)` stack space so it WILL NOT work for large permutations.
156    #[derive(Clone, Copy, Debug, Default)]
157    pub struct StackCopyPermutator;
158
159    fn recursive_permute<T: Clone, P: ?Sized + Permutation>(
160        data: &mut [T],
161        permutation: &mut Enumerate<P::Iter>,
162    ) {
163        if let Some((i, p)) = permutation.next() {
164            let item = data[p].clone();
165            recursive_permute::<T, P>(data, permutation);
166            data[i] = item;
167        }
168    }
169
170    impl<T: Clone, P: ?Sized + Permutation> Permutator<T, P> for StackCopyPermutator {
171        #[inline]
172        fn permute(&mut self, data: &mut [T], permutation: &P) {
173            let mut iter = permutation.iterable().enumerate();
174            recursive_permute::<T, P>(data, &mut iter);
175        }
176    }
177
178    /// Simple permutator that heap-allocates a copy of the data.
179    ///
180    /// Worst-case runtime is `O(n)`, taking `O(n)` heap space in a reusable buffer.
181    /// This is an acceptable permutator for large permutations, provided that the data
182    /// is (efficiently) cloneable.
183    #[derive(Debug, Default)]
184    pub struct HeapCopyPermutator<T> {
185        buffer: Vec<T>,
186    }
187
188    impl<T: Clone, P: ?Sized + Permutation> Permutator<T, P> for HeapCopyPermutator<T> {
189        #[inline]
190        fn permute(&mut self, data: &mut [T], permutation: &P) {
191            self.buffer.clear();
192            self.buffer
193                .extend(permutation.iterable().map(|i| data[i].clone()));
194            for (i, t) in self.buffer.drain(..).enumerate() {
195                data[i] = t;
196            }
197        }
198    }
199
200    /// Permutator that uses an auxiliary heap buffer to ensure linear runtime.
201    ///
202    /// Worst-case runtime is `O(n)`, taking `O(n)` heap space in a reusable buffer.
203    /// The buffer we allocate uses exactly `sizeof(usize) * data.len()` bytes.
204    /// This is a decent permutator for large permutations.
205    #[derive(Debug, Default)]
206    #[cfg(feature = "heap-permutator")]
207    pub struct HeapPermutator {
208        buffer: Vec<Option<nonmax::NonMaxUsize>>,
209    }
210
211    #[cfg(feature = "heap-permutator")]
212    impl<T, P: ?Sized + Permutation> Permutator<T, P> for HeapPermutator {
213        #[inline]
214        fn permute(&mut self, data: &mut [T], permutation: &P) {
215            use std::convert::TryInto;
216            self.buffer.clear();
217            self.buffer.resize(data.len(), None);
218            for mut i in 0..data.len() {
219                let mut j = permutation.index(i);
220                if j < i {
221                    j = self.buffer[j].take().unwrap().get();
222                }
223                data.swap(i, j);
224                if let Some(x) = self.buffer[i].take() {
225                    i = x.get();
226                }
227
228                if j != i {
229                    self.buffer[j] = Some(i.try_into().unwrap());
230                    self.buffer[i] = Some(j.try_into().unwrap());
231                }
232            }
233        }
234    }
235
236    /// Permutator that uses an auxiliary heap buffer to ensure linear runtime.
237    ///
238    /// Worst-case runtime is `O(n)`, worst-case memory usage is also `O(n)`.
239    /// The difference to `HeapPermutator` is that this implementation uses a `HashMap`
240    /// instead of a `Vec` for storage. Hence, the exact the memory usage can no longer be
241    /// predicted - but in return, it should be lower in most cases.
242    /// This is a decent permutator for large permutations.
243    #[derive(Debug, Default)]
244    #[cfg(feature = "heap-permutator-sparse")]
245    pub struct SparseHeapPermutator {
246        buffer: std::collections::HashMap<usize, usize, nohash_hasher::BuildNoHashHasher<usize>>,
247    }
248
249    #[cfg(feature = "heap-permutator-sparse")]
250    impl<T, P: ?Sized + Permutation> Permutator<T, P> for SparseHeapPermutator {
251        #[inline]
252        fn permute(&mut self, data: &mut [T], permutation: &P) {
253            self.buffer.clear();
254            for mut i in 0..data.len() {
255                let mut j = permutation.index(i);
256                if j < i {
257                    j = self.buffer.remove(&j).unwrap();
258                }
259                data.swap(i, j);
260                if let Some(x) = self.buffer.remove(&i) {
261                    i = x;
262                }
263
264                if j != i {
265                    self.buffer.insert(j, i);
266                    self.buffer.insert(i, j);
267                }
268            }
269        }
270    }
271}
272
273/// Generates a permutation that transforms a sorted array into an eytzinger array.
274///
275/// This is an iterator which yields a permutation (indexes into the sorted array)
276/// in the order of an eytzinger array.
277#[derive(Clone, Debug)]
278pub struct PermutationGenerator {
279    size: usize,
280    ipk: usize,
281    li: usize,
282}
283
284impl PermutationGenerator {
285    /// Generate a new permutation for a sorted array of a given size.
286    #[inline]
287    pub fn new(size: usize) -> PermutationGenerator {
288        PermutationGenerator {
289            size,
290            ipk: 1,
291            li: 0,
292        }
293    }
294}
295
296impl Iterator for PermutationGenerator {
297    type Item = usize;
298
299    #[inline]
300    fn next(&mut self) -> Option<usize> {
301        let k2 = 1 << (self.ipk - 1);
302
303        if k2 + self.li - 1 >= self.size {
304            return None;
305        }
306
307        if self.li >= k2 {
308            self.li = 0;
309            self.ipk += 1;
310        }
311
312        let li = self.li;
313        self.li += 1;
314        Some(foundation::get_permutation_element_by_node(
315            self.size, self.ipk, li,
316        ))
317    }
318
319    #[inline]
320    fn size_hint(&self) -> (usize, Option<usize>) {
321        let k2 = 1 << (self.ipk - 1);
322        let size = self.size - (k2 + self.li - 1);
323        (size, Some(size))
324    }
325}
326impl ExactSizeIterator for PermutationGenerator {}
327
328impl Permutation for PermutationGenerator {
329    type Iter = PermutationGenerator;
330
331    #[inline]
332    fn iterable(&self) -> PermutationGenerator {
333        self.clone()
334    }
335    #[inline]
336    fn index(&self, i: usize) -> usize {
337        foundation::get_permutation_element(self.size, i)
338    }
339}
340
341/// Converts a sorted array to its eytzinger representation.
342///
343/// # Example
344///
345/// ```rust
346/// let mut data = [0, 1, 2, 3, 4, 5, 6];
347/// eytzinger_interpolation::eytzingerize(&mut data, &mut eytzinger_interpolation::permutation::InplacePermutator);
348/// assert_eq!(data, [3, 1, 5, 0, 2, 4, 6]);
349/// ```
350#[inline]
351pub fn eytzingerize<T, P: Permutator<T, PermutationGenerator>>(data: &mut [T], permutator: &mut P) {
352    let len = data.len();
353    permutator.permute(data, &PermutationGenerator::new(len))
354}
355
356/// Eytzinger extension methods for slices.
357pub trait SliceExt<T> {
358    /// Converts an already sorted array to its eytzinger representation.
359    ///
360    /// # Example
361    ///
362    /// ```rust
363    /// use eytzinger_interpolation::SliceExt;
364    /// let mut data = [0, 1, 2, 3, 4, 5, 6];
365    /// data.eytzingerize(&mut eytzinger_interpolation::permutation::InplacePermutator);
366    /// assert_eq!(data, [3, 1, 5, 0, 2, 4, 6]);
367    /// ```
368    fn eytzingerize<P: Permutator<T, PermutationGenerator>>(&mut self, permutator: &mut P);
369
370    /// Binary searches this eytzinger slice for a given element.
371    ///
372    /// If the value is found then `Some` is returned, containing the index of the matching element;
373    /// if the value is not found then `None` is returned.
374    ///
375    /// # Example
376    ///
377    /// ```rust
378    /// use eytzinger_interpolation::SliceExt;
379    /// let s = [3, 1, 5, 0, 2, 4, 6];
380    /// assert_eq!(s.eytzinger_search(&5), Some(2));
381    /// assert_eq!(s.eytzinger_search(&6), Some(6));
382    /// assert_eq!(s.eytzinger_search(&7), None);
383    /// ```
384    fn eytzinger_search<Q: ?Sized>(&self, x: &Q) -> Option<usize>
385    where
386        Q: Ord,
387        T: Borrow<Q>;
388
389    /// Binary searches this eytzinger slice with a comparator function.
390    ///
391    /// The comparator function should implement an order consistent with the sort order
392    /// of the underlying eytzinger slice, returning an order code that indicates whether
393    /// its argument is `Less`, `Equal` or `Greater` than the desired target.
394    ///
395    /// If a matching value is found then `Some` is returned, containing the index of the
396    /// matching element; if no match is found then `None` is returned.
397    ///
398    /// # Examples
399    ///
400    /// ```rust
401    /// use eytzinger_interpolation::SliceExt;
402    /// let s = [3, 1, 5, 0, 2, 4, 6];
403    /// assert_eq!(s.eytzinger_search_by(|x| x.cmp(&5)), Some(2));
404    /// assert_eq!(s.eytzinger_search_by(|x| x.cmp(&6)), Some(6));
405    /// assert_eq!(s.eytzinger_search_by(|x| x.cmp(&7)), None);
406    /// ```
407    fn eytzinger_search_by<'a, F>(&'a self, f: F) -> Option<usize>
408    where
409        F: FnMut(&'a T) -> Ordering,
410        T: 'a;
411
412    /// Binary searches this sorted slice with a key extraction function.
413    ///
414    /// Assumes that the slice is eytzinger-sorted by the key, for instance with
415    /// `slice::sort_by_key` combined with `eytzinger::eytzingerize` using the
416    /// same key extraction function.
417    ///
418    /// If a matching value is found then `Some` is returned, containing the index of the
419    /// matching element; if no match is found then `None` is returned.
420    ///
421    /// # Examples
422    ///
423    /// ```rust
424    /// use eytzinger_interpolation::SliceExt;
425    /// let s = [(3, 'd'), (1, 'b'), (5, 'f'), (0, 'a'), (2, 'c'), (4, 'e'), (6, 'g')];
426    /// assert_eq!(s.eytzinger_search_by_key(&'f', |&(_, b)| b), Some(2));
427    /// assert_eq!(s.eytzinger_search_by_key(&'g', |&(_, b)| b), Some(6));
428    /// assert_eq!(s.eytzinger_search_by_key(&'x', |&(_, b)| b), None);
429    /// ```
430    fn eytzinger_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, f: F) -> Option<usize>
431    where
432        B: Borrow<Q>,
433        F: FnMut(&'a T) -> B,
434        Q: Ord,
435        T: 'a;
436
437    /// Binary searches this eytzinger slice with a comparator function for interpolation.
438    ///
439    /// Called "interpolative" search because it's useful for when you need to interpolate to a value between two values in the array.
440    ///
441    /// The comparator function should implement an order consistent with the sort order
442    /// of the underlying eytzinger slice, returning an order code that indicates whether
443    /// its argument is `Less`, `Equal` or `Greater` than the desired target.
444    ///
445    /// The first return value is the index of the highest value that's less than or equal to the target value.
446    /// The second return value is the index of the lowest value that's greater than to the target value.
447    ///
448    /// # Examples
449    ///
450    /// ```rust
451    /// use eytzinger_interpolation::SliceExt;
452    /// let s = [3, 1, 5, 0, 2, 4, 6];
453    /// assert_eq!(s.eytzinger_interpolative_search_by(|x| x.cmp(&3)),  (Some(0_usize), Some(5_usize)));
454    /// assert_eq!(s.eytzinger_interpolative_search_by(|x| x.cmp(&5)),  (Some(2_usize), Some(6_usize)));
455    /// assert_eq!(s.eytzinger_interpolative_search_by(|x| x.cmp(&6)),  (Some(6_usize), None));
456    /// assert_eq!(s.eytzinger_interpolative_search_by(|x| x.cmp(&7)),  (Some(6_usize), None));
457    /// assert_eq!(s.eytzinger_interpolative_search_by(|x| x.cmp(&0)),  (Some(3_usize), Some(1_usize)));
458    /// assert_eq!(s.eytzinger_interpolative_search_by(|x| x.cmp(&-1)), (None, Some(3_usize)));
459    /// assert_eq!(s.eytzinger_interpolative_search_by(|x| (*x as f32).partial_cmp(&3.5).unwrap()), (Some(0_usize), Some(5_usize)));
460    /// ```
461    fn eytzinger_interpolative_search_by<'a, F>(&'a self, f: F) -> (Option<usize>, Option<usize>)
462    where
463        F: FnMut(&'a T) -> Ordering,
464        T: 'a;
465
466    /// Binary searches this eytzinger slice for interpolation.
467    ///
468    /// The first return value is the index of the highest value that's less than or equal to the target value.
469    /// The second return value is the index of the lowest value that's greater than to the target value.
470    ///
471    /// # Examples
472    ///
473    /// ```rust
474    /// use eytzinger_interpolation::SliceExt;
475    /// let s = [3, 1, 5, 0, 2, 4, 6];
476    /// assert_eq!(s.eytzinger_interpolative_search(&3),  (Some(0_usize), Some(5_usize)));
477    /// assert_eq!(s.eytzinger_interpolative_search(&5),  (Some(2_usize), Some(6_usize)));
478    /// assert_eq!(s.eytzinger_interpolative_search(&6),  (Some(6_usize), None));
479    /// assert_eq!(s.eytzinger_interpolative_search(&7),  (Some(6_usize), None));
480    /// assert_eq!(s.eytzinger_interpolative_search(&0),  (Some(3_usize), Some(1_usize)));
481    /// assert_eq!(s.eytzinger_interpolative_search(&-1), (None, Some(3_usize)));
482    /// ```
483    fn eytzinger_interpolative_search<Q: ?Sized>(&self, x: &Q) -> (Option<usize>, Option<usize>)
484    where
485        Q: Ord,
486        T: Borrow<Q>;
487
488    /// Binary searches this sorted slice with a key extraction function for interpolation.
489    ///
490    /// Assumes that the slice is eytzinger-sorted by the key, for instance with
491    /// `slice::sort_by_key` combined with `eytzinger::eytzingerize` using the
492    /// same key extraction function.
493    ///
494    /// The first return value is the index of the highest value that's less than or equal to the target value.
495    /// The second return value is the index of the lowest value that's greater than to the target value.
496    ///
497    /// # Examples
498    ///
499    /// ```rust
500    /// use eytzinger_interpolation::SliceExt;
501    /// let s = [(3, 'd'), (1, 'b'), (5, 'f'), (0, 'a'), (2, 'c'), (4, 'e'), (6, 'g')];
502    /// assert_eq!(s.eytzinger_interpolative_search_by_key(&'d', |&(_, b)| b), (Some(0), Some(5)));
503    /// assert_eq!(s.eytzinger_interpolative_search_by_key(&'f', |&(_, b)| b), (Some(2), Some(6)));
504    /// assert_eq!(s.eytzinger_interpolative_search_by_key(&'g', |&(_, b)| b), (Some(6), None));
505    /// assert_eq!(s.eytzinger_interpolative_search_by_key(&'x', |&(_, b)| b), (Some(6), None));
506    /// ```
507    fn eytzinger_interpolative_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, f: F) -> (Option<usize>, Option<usize>)
508    where
509        B: Borrow<Q>,
510        F: FnMut(&'a T) -> B,
511        Q: Ord,
512        T: 'a;
513
514}
515
516/// Binary searches this eytzinger slice with a comparator function.
517///
518/// Called "interpolative" search because it's useful for when you need to interpolate to a value between two values in the array.
519///
520/// The comparator function should implement an order consistent with the sort order
521/// of the underlying eytzinger slice, returning an order code that indicates whether
522/// its argument is `Less`, `Equal` or `Greater` than the desired target.
523///
524/// The first return value is the index of the highest value that's less than or equal to the target value.
525/// The second return value is the index of the lowest value that's greater than to the target value.
526///
527/// # Examples
528///
529/// ```rust
530/// use eytzinger_interpolation::eytzinger_interpolative_search_by;
531/// let s = [3, 1, 5, 0, 2, 4, 6];
532/// assert_eq!(eytzinger_interpolative_search_by(&s, |x| x.cmp(&3)),  (Some(0_usize), Some(5_usize)));
533/// assert_eq!(eytzinger_interpolative_search_by(&s, |x| x.cmp(&5)),  (Some(2_usize), Some(6_usize)));
534/// assert_eq!(eytzinger_interpolative_search_by(&s, |x| x.cmp(&6)),  (Some(6_usize), None));
535/// assert_eq!(eytzinger_interpolative_search_by(&s, |x| x.cmp(&7)),  (Some(6_usize), None));
536/// assert_eq!(eytzinger_interpolative_search_by(&s, |x| x.cmp(&0)),  (Some(3_usize), Some(1_usize)));
537/// assert_eq!(eytzinger_interpolative_search_by(&s, |x| x.cmp(&-1)), (None, Some(3_usize)));
538/// assert_eq!(eytzinger_interpolative_search_by(&s, |x| (*x as f32).partial_cmp(&3.5).unwrap()), (Some(0_usize), Some(5_usize)));
539/// ```
540#[inline]
541pub fn eytzinger_interpolative_search_by<'a, T: 'a, F>(
542    data: &'a [T],
543    mut f: F,
544) -> (Option<usize>, Option<usize>)
545where
546    F: FnMut(&'a T) -> Ordering,
547{
548    let mut lte: Option<usize> = None; // Index of highest value <= target
549    let mut gt: Option<usize> = None; // Index of lowest value > target
550    let mut i = 0;
551
552    while i < data.len() {
553        let v = &data[i];
554        match f(v) {
555            Ordering::Less | Ordering::Equal => {
556                // Current value <= target
557                lte = Some(i);
558                // Go right to find larger values (potentially better lte or gt)
559                i = 2 * i + 2;
560            }
561            Ordering::Greater => {
562                // Current value > target
563                // This is a candidate for gt (lowest value > target)
564                gt = Some(i);
565                // Go left to find smaller values (potentially lte or better gt)
566                i = 2 * i + 1;
567            }
568        }
569    }
570
571    (lte, gt)
572}
573
574/// Binary searches this eytzinger slice with a comparator function.
575///
576/// The comparator function should implement an order consistent with the sort order
577/// of the underlying eytzinger slice, returning an order code that indicates whether
578/// its argument is `Less`, `Equal` or `Greater` than the desired target.
579///
580/// If a matching value is found then `Some` is returned, containing the index of the
581/// matching element; if no match is found then `None` is returned.
582///
583/// # Examples
584///
585/// ```rust
586/// use eytzinger_interpolation::eytzinger_search_by;
587/// let s = [3, 1, 5, 0, 2, 4, 6];
588/// assert_eq!(eytzinger_search_by(&s, |x| x.cmp(&3)), Some(0));
589/// assert_eq!(eytzinger_search_by(&s, |x| x.cmp(&5)), Some(2));
590/// assert_eq!(eytzinger_search_by(&s, |x| x.cmp(&6)), Some(6));
591/// assert_eq!(eytzinger_search_by(&s, |x| x.cmp(&7)), None);
592/// ```
593#[inline]
594pub fn eytzinger_search_by<'a, T: 'a, F>(data: &'a [T], f: F) -> Option<usize>
595where
596    F: FnMut(&'a T) -> Ordering,
597{
598    eytzinger_search_by_impl(data, f)
599}
600
601#[inline]
602#[cfg(not(feature = "branchless"))]
603fn eytzinger_search_by_impl<'a, T: 'a, F>(data: &'a [T], mut f: F) -> Option<usize>
604where
605    F: FnMut(&'a T) -> Ordering,
606{
607    let mut i = 0;
608    loop {
609        match data.get(i) {
610            Some(ref v) => {
611                match f(v) {
612                    Ordering::Equal => return Some(i),
613                    o => {
614                        // I was hoping the optimizer could handle this but it can't
615                        // So here goes the evil hack: Ordering is -1/0/1
616                        // So we use this dirty trick to map this to +2/X/+1
617                        let o = o as usize;
618                        let o = (o >> 1) & 1;
619                        i = 2 * i + 1 + o;
620                    }
621                };
622            }
623            None => return None,
624        }
625    }
626}
627
628#[inline]
629#[cfg(feature = "branchless")]
630fn eytzinger_search_by_impl<'a, T: 'a, F>(data: &'a [T], mut f: F) -> Option<usize>
631where
632    F: FnMut(&'a T) -> Ordering,
633{
634    let mut i = 0;
635    while i < data.len() {
636        let v = &data[i]; // this range check is optimized out :D
637        i = match f(v) {
638            Ordering::Greater | Ordering::Equal => 2 * i + 1,
639            Ordering::Less => 2 * i + 2,
640        };
641    }
642
643    // magic from the paper to fix up the (incomplete) final tree layer
644    // (only difference is that we recheck f() because this is exact search)
645    let p = i + 1;
646    let j = p >> (1 + (!p).trailing_zeros());
647    if j != 0 && (f(&data[j - 1]) == Ordering::Equal) {
648        Some(j - 1)
649    } else {
650        None
651    }
652}
653
654impl<T> SliceExt<T> for [T] {
655    #[inline]
656    fn eytzingerize<P: Permutator<T, PermutationGenerator>>(&mut self, permutator: &mut P) {
657        eytzingerize(self, permutator)
658    }
659
660    #[inline]
661    fn eytzinger_search<Q: ?Sized>(&self, x: &Q) -> Option<usize>
662    where
663        Q: Ord,
664        T: Borrow<Q>,
665    {
666        self.eytzinger_search_by(|e| e.borrow().cmp(x))
667    }
668
669    #[inline]
670    fn eytzinger_search_by<'a, F>(&'a self, f: F) -> Option<usize>
671    where
672        F: FnMut(&'a T) -> Ordering,
673        T: 'a,
674    {
675        eytzinger_search_by(self, f)
676    }
677
678    #[inline]
679    fn eytzinger_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, mut f: F) -> Option<usize>
680    where
681        B: Borrow<Q>,
682        F: FnMut(&'a T) -> B,
683        Q: Ord,
684        T: 'a,
685    {
686        self.eytzinger_search_by(|k| f(k).borrow().cmp(b))
687    }
688
689    #[inline]
690    fn eytzinger_interpolative_search_by<'a, F>(&'a self, f: F) -> (Option<usize>, Option<usize>)
691    where
692        F: FnMut(&'a T) -> Ordering,
693        T: 'a,
694    {
695        eytzinger_interpolative_search_by(self, f)
696    }
697
698    #[inline]
699    fn eytzinger_interpolative_search<Q: ?Sized>(&self, x: &Q) -> (Option<usize>, Option<usize>)
700    where
701        Q: Ord,
702        T: Borrow<Q>,
703    {
704        self.eytzinger_interpolative_search_by(|e| e.borrow().cmp(x))
705    }
706
707    #[inline]
708    fn eytzinger_interpolative_search_by_key<'a, B, F, Q: ?Sized>(&'a self, b: &Q, mut f: F) -> (Option<usize>, Option<usize>)
709    where
710        B: Borrow<Q>,
711        F: FnMut(&'a T) -> B,
712        Q: Ord,
713        T: 'a,
714    {
715        self.eytzinger_interpolative_search_by(|k| f(k).borrow().cmp(b))
716    }
717}
718
719#[cfg(test)]
720#[macro_use]
721extern crate quickcheck;
722#[cfg(test)]
723mod tests {
724    use super::foundation::*;
725    use super::*;
726
727    #[test]
728    fn magic() {
729        for (i, &v) in [0, 1, 1, 2, 3, 3, 3, 4, 5, 6, 7, 7, 7, 7, 7, 8]
730            .iter()
731            .enumerate()
732        {
733            assert_eq!(get_permutation_element_by_node(i + 1, 1, 0), v);
734        }
735        for (i, &v) in [0, 0, 1, 1, 1, 1, 2, 3, 3].iter().enumerate() {
736            assert_eq!(get_permutation_element_by_node(i + 2, 2, 0), v);
737        }
738        for (i, &v) in [2, 3, 4, 5, 5, 6, 7, 8].iter().enumerate() {
739            assert_eq!(get_permutation_element_by_node(i + 3, 2, 1), v);
740        }
741        for (i, &v) in [0, 0, 0, 0, 1, 1, 1].iter().enumerate() {
742            assert_eq!(get_permutation_element_by_node(i + 4, 3, 0), v);
743        }
744    }
745
746    const REF_PERMUTATIONS: &[&'static [usize]] = &[
747        &[],
748        &[0],
749        &[1, 0],
750        &[1, 0, 2],
751        &[2, 1, 3, 0],
752        &[3, 1, 4, 0, 2],
753        &[3, 1, 5, 0, 2, 4],
754        &[3, 1, 5, 0, 2, 4, 6],
755        &[4, 2, 6, 1, 3, 5, 7, 0],
756        &[5, 3, 7, 1, 4, 6, 8, 0, 2],
757        &[6, 3, 8, 1, 5, 7, 9, 0, 2, 4],
758        &[7, 3, 0xb, 1, 5, 9, 0xd, 0, 2, 4, 6, 8, 0xa, 0xc, 0xe],
759    ];
760
761    #[test]
762    fn reference_permutations() {
763        for &array in REF_PERMUTATIONS {
764            let permut: Vec<_> = PermutationGenerator::new(array.len()).collect();
765            assert_eq!(array, permut.as_slice());
766        }
767    }
768
769    #[test]
770    fn eytzingerize_simple() {
771        let mut permutator = InplacePermutator;
772        for &array in REF_PERMUTATIONS {
773            let mut payload: Vec<_> = (0..array.len()).collect();
774            eytzingerize(payload.as_mut_slice(), &mut permutator);
775            assert_eq!(payload, array);
776        }
777    }
778
779    const NODE_INDEXES: &[(usize, usize)] = &[
780        (1, 0),
781        (2, 0),
782        (2, 1),
783        (3, 0),
784        (3, 1),
785        (3, 2),
786        (3, 3),
787        (4, 0),
788        (4, 1),
789        (4, 2),
790        (4, 3),
791        (4, 4),
792        (4, 5),
793        (4, 6),
794        (4, 7),
795    ];
796
797    #[test]
798    fn calc_index() {
799        for (i, &x) in NODE_INDEXES.iter().enumerate() {
800            assert_eq!(x, index_to_node(i));
801        }
802    }
803
804    #[test]
805    fn simple_inplace_permutation() {
806        let permutation: &[usize] = &[4, 2, 3, 0, 1];
807        let mut data = [1, 2, 3, 4, 5];
808        InplacePermutator.permute(&mut data, &permutation);
809        assert_eq!(data, [5, 3, 4, 1, 2]);
810    }
811
812    #[test]
813    #[cfg(feature = "heap-permutator")]
814    fn simple_heap_permutation() {
815        let permutation: &[usize] = &[4, 2, 3, 0, 1];
816        let mut data = [1, 2, 3, 4, 5];
817        HeapPermutator::default().permute(&mut data, &permutation);
818        assert_eq!(data, [5, 3, 4, 1, 2]);
819    }
820
821    #[test]
822    #[cfg(feature = "heap-permutator-sparse")]
823    fn simple_heap_permutation_sparse() {
824        let permutation: &[usize] = &[4, 2, 3, 0, 1];
825        let mut data = [1, 2, 3, 4, 5];
826        SparseHeapPermutator::default().permute(&mut data, &permutation);
827        assert_eq!(data, [5, 3, 4, 1, 2]);
828    }
829
830    #[test]
831    fn simple_heap_copy_permutation() {
832        let permutation: &[usize] = &[4, 2, 3, 0, 1];
833        let mut data = [1, 2, 3, 4, 5];
834        HeapCopyPermutator::default().permute(&mut data, &permutation);
835        assert_eq!(data, [5, 3, 4, 1, 2]);
836    }
837
838    #[test]
839    fn search_negative() {
840        let data: &[i32] = &[6, 2, 10, 0, 4, 8, 12];
841        for i in -10..20 {
842            let expected = data.iter().position(|&x| x == i);
843            assert_eq!(expected, data.eytzinger_search(&i));
844        }
845    }
846
847    fn test_permutation<P: Default>(junk: Vec<usize>) -> bool
848    where
849        for<'a> P: Permutator<usize, &'a [usize]>,
850    {
851        // first create a permutation from the random array
852        let mut perm: Vec<_> = (0..junk.len()).collect();
853        perm.sort_by_key(|&i| junk[i]);
854
855        // now test
856        let mut data: Vec<_> = (0..perm.len()).collect();
857        P::default().permute(data.as_mut_slice(), &perm.as_slice());
858        data == perm
859    }
860
861    quickcheck! {
862        fn inplace_permutation(junk: Vec<usize>) -> bool {
863            test_permutation::<InplacePermutator>(junk)
864        }
865
866        fn stack_permutation(junk: Vec<usize>) -> bool {
867            test_permutation::<StackCopyPermutator>(junk)
868        }
869
870        #[cfg(feature = "heap-permutator")]
871        fn heap_permutation(junk: Vec<usize>) -> bool {
872            test_permutation::<HeapPermutator>(junk)
873        }
874
875        #[cfg(feature = "heap-permutator-sparse")]
876        fn heap_permutation_sparse(junk: Vec<usize>) -> bool {
877            test_permutation::<SparseHeapPermutator>(junk)
878        }
879
880        fn heap_copy_permutation(junk: Vec<usize>) -> bool {
881            test_permutation::<HeapCopyPermutator<_>>(junk)
882        }
883
884        fn eytzinger_tree_invariants(length: usize) -> bool {
885            let perm: Vec<_> = PermutationGenerator::new(length).collect();
886
887            let mut todo = Vec::new();
888            todo.push((0, 0..length));
889            let mut checked = 0;
890            while let Some((i, range)) = todo.pop() {
891                match perm.get(i) {
892                    Some(&v) => {
893                        if !(range.start <= v && v < range.end) { return false; }
894                        todo.push((2 * (i + 1) - 1, range.start..v));
895                        todo.push((2 * (i + 1), v..range.end));
896                        checked += 1;
897                    }
898                    None => continue,
899                }
900            }
901
902            checked == length
903        }
904
905        fn search_works(data: Vec<usize>) -> bool {
906            let mut data = data;
907            data.sort();
908            data.dedup();
909            data.eytzingerize(&mut InplacePermutator);
910
911            data.iter().enumerate().all(|(i, v)| data.eytzinger_search(v) == Some(i))
912        }
913
914        fn interpolative_search_bounds_correct(data: Vec<i32>) -> bool {
915            let mut data = data;
916            data.sort();
917            data.dedup();
918            if data.is_empty() { return true; }
919
920            let sorted = data.clone();
921            data.eytzingerize(&mut InplacePermutator);
922
923            // Test every value in the array
924            for &target in &sorted {
925                let (lte, gt) = data.eytzinger_interpolative_search(&target);
926
927                // lte should be <= target
928                if let Some(idx) = lte {
929                    if data[idx] > target { return false; }
930                }
931
932                // gt should be > target
933                if let Some(idx) = gt {
934                    if data[idx] <= target { return false; }
935                }
936
937                // At least one should be Some
938                if lte.is_none() && gt.is_none() { return false; }
939            }
940
941            // Test values between elements
942            for window in sorted.windows(2) {
943                let between = (window[0] + window[1]) / 2;
944                if between != window[0] && between != window[1] {
945                    let (lte, gt) = data.eytzinger_interpolative_search(&between);
946
947                    if let Some(idx) = lte {
948                        if data[idx] > between { return false; }
949                    }
950
951                    if let Some(idx) = gt {
952                        if data[idx] <= between { return false; }
953                    }
954                }
955            }
956
957            true
958        }
959    }
960
961    #[test]
962    fn interpolative_search_empty() {
963        let data: &[i32] = &[];
964        assert_eq!(data.eytzinger_interpolative_search(&0), (None, None));
965    }
966
967    #[test]
968    fn interpolative_search_single() {
969        let data = [42];
970        assert_eq!(data.eytzinger_interpolative_search(&42), (Some(0), None));
971        assert_eq!(data.eytzinger_interpolative_search(&41), (None, Some(0)));
972        assert_eq!(data.eytzinger_interpolative_search(&43), (Some(0), None));
973    }
974
975    #[test]
976    fn interpolative_search_all_equal() {
977        let mut data = [5, 5, 5, 5];
978        data.eytzingerize(&mut InplacePermutator);
979        let (lte, _gt) = data.eytzinger_interpolative_search(&5);
980        // Should find at least one value equal to 5
981        assert!(lte.is_some());
982        if let Some(idx) = lte {
983            assert_eq!(data[idx], 5);
984        }
985    }
986
987    #[test]
988    fn interpolative_search_below_min() {
989        let mut data = [10, 20, 30, 40, 50];
990        data.eytzingerize(&mut InplacePermutator);
991        let (lte, gt) = data.eytzinger_interpolative_search(&5);
992        assert_eq!(lte, None);
993        assert!(gt.is_some());
994        if let Some(idx) = gt {
995            assert!(data[idx] >= 10);
996        }
997    }
998
999    #[test]
1000    fn interpolative_search_above_max() {
1001        let mut data = [10, 20, 30, 40, 50];
1002        data.eytzingerize(&mut InplacePermutator);
1003        let (lte, gt) = data.eytzinger_interpolative_search(&100);
1004        assert!(lte.is_some());
1005        assert_eq!(gt, None);
1006        if let Some(idx) = lte {
1007            assert!(data[idx] <= 50);
1008        }
1009    }
1010
1011    #[test]
1012    fn interpolative_search_between_values() {
1013        let mut data = [10, 20, 30, 40, 50];
1014        data.eytzingerize(&mut InplacePermutator);
1015        let (lte, gt) = data.eytzinger_interpolative_search(&25);
1016
1017        assert!(lte.is_some());
1018        assert!(gt.is_some());
1019
1020        if let (Some(lte_idx), Some(gt_idx)) = (lte, gt) {
1021            assert!(data[lte_idx] <= 25);
1022            assert!(data[gt_idx] > 25);
1023        }
1024    }
1025}