slice_group_by/binary_group/
binary_group_by_key.rs

1use crate::offset_from;
2use std::cmp::Ordering::{Greater, Less};
3use std::slice::{from_raw_parts, from_raw_parts_mut};
4use std::{fmt, marker};
5
6macro_rules! binary_group_by_key {
7    (struct $name:ident, $elem:ty, $mkslice:ident) => {
8        impl<'a, T: 'a, F> $name<'a, T, F> {
9            #[inline]
10            pub fn is_empty(&self) -> bool {
11                self.ptr == self.end
12            }
13
14            #[inline]
15            pub fn remainder_len(&self) -> usize {
16                unsafe { offset_from(self.end, self.ptr) }
17            }
18        }
19
20        impl<'a, T: 'a, F, K> std::iter::Iterator for $name<'a, T, F>
21        where
22            F: FnMut(&T) -> K,
23            K: PartialEq,
24        {
25            type Item = $elem;
26
27            #[inline]
28            fn next(&mut self) -> Option<Self::Item> {
29                if self.is_empty() {
30                    return None;
31                }
32
33                let first = unsafe { &*self.ptr };
34
35                let len = self.remainder_len();
36                let tail = unsafe { $mkslice(self.ptr.add(1), len - 1) };
37
38                let predicate = |x: &T| {
39                    if (self.func)(first) == (self.func)(x) {
40                        Less
41                    } else {
42                        Greater
43                    }
44                };
45                let index = tail.binary_search_by(predicate).unwrap_err();
46
47                let left = unsafe { $mkslice(self.ptr, index + 1) };
48                self.ptr = unsafe { self.ptr.add(index + 1) };
49
50                Some(left)
51            }
52
53            fn size_hint(&self) -> (usize, Option<usize>) {
54                if self.is_empty() {
55                    return (0, Some(0));
56                }
57
58                let len = self.remainder_len();
59                (1, Some(len))
60            }
61
62            fn last(mut self) -> Option<Self::Item> {
63                self.next_back()
64            }
65        }
66
67        impl<'a, T: 'a, F, K> std::iter::DoubleEndedIterator for $name<'a, T, F>
68        where
69            F: FnMut(&T) -> K,
70            K: PartialEq,
71        {
72            #[inline]
73            fn next_back(&mut self) -> Option<Self::Item> {
74                if self.is_empty() {
75                    return None;
76                }
77
78                let last = unsafe { &*self.end.sub(1) };
79
80                let len = self.remainder_len();
81                let head = unsafe { $mkslice(self.ptr, len - 1) };
82
83                let predicate = |x: &T| {
84                    if (self.func)(last) == (self.func)(x) {
85                        Greater
86                    } else {
87                        Less
88                    }
89                };
90                let index = head.binary_search_by(predicate).unwrap_err();
91
92                let right = unsafe { $mkslice(self.ptr.add(index), len - index) };
93                self.end = unsafe { self.end.sub(len - index) };
94
95                Some(right)
96            }
97        }
98
99        impl<'a, T: 'a, F, K> std::iter::FusedIterator for $name<'a, T, F>
100        where
101            F: FnMut(&T) -> K,
102            K: PartialEq,
103        {
104        }
105    };
106}
107
108/// An iterator that will return non-overlapping groups in the slice using *binary search*.
109///
110/// It will give an element to the given function, producing a key and comparing
111/// the keys to determine groups.
112pub struct BinaryGroupByKey<'a, T, F> {
113    ptr: *const T,
114    end: *const T,
115    func: F,
116    _phantom: marker::PhantomData<&'a T>,
117}
118
119impl<'a, T: 'a, F> BinaryGroupByKey<'a, T, F> {
120    pub fn new(slice: &'a [T], func: F) -> Self {
121        BinaryGroupByKey {
122            ptr: slice.as_ptr(),
123            end: unsafe { slice.as_ptr().add(slice.len()) },
124            func,
125            _phantom: marker::PhantomData,
126        }
127    }
128}
129
130impl<'a, T, F> BinaryGroupByKey<'a, T, F> {
131    /// Returns the remainder of the original slice that is going to be
132    /// returned by the iterator.
133    pub fn remainder(&self) -> &[T] {
134        let len = self.remainder_len();
135        unsafe { from_raw_parts(self.ptr, len) }
136    }
137}
138
139impl<'a, T: 'a + fmt::Debug, F> fmt::Debug for BinaryGroupByKey<'a, T, F> {
140    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
141        f.debug_struct("BinaryGroupByKey")
142            .field("remainder", &self.remainder())
143            .finish()
144    }
145}
146
147binary_group_by_key! { struct BinaryGroupByKey, &'a [T], from_raw_parts }
148
149/// An iterator that will return non-overlapping *mutable* groups
150/// in the slice using *binary search*.
151///
152/// It will give an element to the given function, producing a key and comparing
153/// the keys to determine groups.
154pub struct BinaryGroupByKeyMut<'a, T, F> {
155    ptr: *mut T,
156    end: *mut T,
157    func: F,
158    _phantom: marker::PhantomData<&'a mut T>,
159}
160
161impl<'a, T: 'a, F> BinaryGroupByKeyMut<'a, T, F> {
162    pub fn new(slice: &'a mut [T], func: F) -> Self {
163        let ptr = slice.as_mut_ptr();
164        let end = unsafe { ptr.add(slice.len()) };
165        BinaryGroupByKeyMut {
166            ptr,
167            end,
168            func,
169            _phantom: marker::PhantomData,
170        }
171    }
172}
173
174impl<'a, T, F> BinaryGroupByKeyMut<'a, T, F> {
175    /// Returns the remainder of the original slice that is going to be
176    /// returned by the iterator.
177    pub fn remainder(&self) -> &[T] {
178        let len = self.remainder_len();
179        unsafe { from_raw_parts(self.ptr, len) }
180    }
181}
182
183impl<'a, T: 'a + fmt::Debug, F> fmt::Debug for BinaryGroupByKeyMut<'a, T, F> {
184    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
185        f.debug_struct("BinaryGroupByKeyMut")
186            .field("remainder", &self.remainder())
187            .finish()
188    }
189}
190
191binary_group_by_key! { struct BinaryGroupByKeyMut, &'a mut [T], from_raw_parts_mut }