slice_group_by/linear_group/
linear_group_by.rs1use std::iter::FusedIterator;
2use std::{mem, fmt, slice};
3
4unsafe fn split_at_unchecked<T>(slice: &[T], mid: usize) -> (&[T], &[T]) {
5 (slice.get_unchecked(..mid), slice.get_unchecked(mid..))
6}
7
8unsafe fn split_at_mut_unchecked<T>(slice: &mut [T], mid: usize) -> (&mut [T], &mut [T]) {
9 let len = slice.len();
11 let ptr = slice.as_mut_ptr();
12
13 (slice::from_raw_parts_mut(ptr, mid), slice::from_raw_parts_mut(ptr.add(mid), len - mid))
18}
19
20pub struct LinearGroupBy<'a, T: 'a, P> {
21 slice: &'a [T],
22 predicate: P,
23}
24
25impl<'a, T: 'a, P> LinearGroupBy<'a, T, P> {
26 pub(crate) fn new(slice: &'a [T], predicate: P) -> Self {
27 LinearGroupBy { slice, predicate }
28 }
29}
30
31impl<'a, T: 'a, P> Iterator for LinearGroupBy<'a, T, P>
32where
33 P: FnMut(&T, &T) -> bool,
34{
35 type Item = &'a [T];
36
37 #[inline]
38 fn next(&mut self) -> Option<Self::Item> {
39 if self.slice.is_empty() {
40 None
41 } else {
42 let mut len = 1;
43 let mut iter = self.slice.windows(2);
44 while let Some([l, r]) = iter.next() {
45 if (self.predicate)(l, r) { len += 1 } else { break }
46 }
47 let (head, tail) = unsafe { split_at_unchecked(self.slice, len) };
48 self.slice = tail;
49 Some(head)
50 }
51 }
52
53 #[inline]
54 fn size_hint(&self) -> (usize, Option<usize>) {
55 if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) }
56 }
57
58 #[inline]
59 fn last(mut self) -> Option<Self::Item> {
60 self.next_back()
61 }
62}
63
64impl<'a, T: 'a, P> DoubleEndedIterator for LinearGroupBy<'a, T, P>
65where
66 P: FnMut(&T, &T) -> bool,
67{
68 #[inline]
69 fn next_back(&mut self) -> Option<Self::Item> {
70 if self.slice.is_empty() {
71 None
72 } else {
73 let mut len = 1;
74 let mut iter = self.slice.windows(2);
75 while let Some([l, r]) = iter.next_back() {
76 if (self.predicate)(l, r) { len += 1 } else { break }
77 }
78 let (head, tail) = unsafe { split_at_unchecked(self.slice, self.slice.len() - len) };
79 self.slice = head;
80 Some(tail)
81 }
82 }
83}
84
85impl<'a, T: 'a, P> FusedIterator for LinearGroupBy<'a, T, P> where P: FnMut(&T, &T) -> bool {}
86
87impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for LinearGroupBy<'a, T, P> {
88 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89 f.debug_struct("LinearGroupBy").field("slice", &self.slice).finish()
90 }
91}
92
93pub struct LinearGroupByMut<'a, T: 'a, P> {
94 slice: &'a mut [T],
95 predicate: P,
96}
97
98impl<'a, T: 'a, P> LinearGroupByMut<'a, T, P> {
99 pub(crate) fn new(slice: &'a mut [T], predicate: P) -> Self {
100 LinearGroupByMut { slice, predicate }
101 }
102}
103
104impl<'a, T: 'a, P> Iterator for LinearGroupByMut<'a, T, P>
105where
106 P: FnMut(&T, &T) -> bool,
107{
108 type Item = &'a mut [T];
109
110 #[inline]
111 fn next(&mut self) -> Option<Self::Item> {
112 if self.slice.is_empty() {
113 None
114 } else {
115 let mut len = 1;
116 let mut iter = self.slice.windows(2);
117 while let Some([l, r]) = iter.next() {
118 if (self.predicate)(l, r) { len += 1 } else { break }
119 }
120 let slice = mem::take(&mut self.slice);
121 let (head, tail) = unsafe { split_at_mut_unchecked(slice, len) };
122 self.slice = tail;
123 Some(head)
124 }
125 }
126
127 #[inline]
128 fn size_hint(&self) -> (usize, Option<usize>) {
129 if self.slice.is_empty() { (0, Some(0)) } else { (1, Some(self.slice.len())) }
130 }
131
132 #[inline]
133 fn last(mut self) -> Option<Self::Item> {
134 self.next_back()
135 }
136}
137
138impl<'a, T: 'a, P> DoubleEndedIterator for LinearGroupByMut<'a, T, P>
139where
140 P: FnMut(&T, &T) -> bool,
141{
142 #[inline]
143 fn next_back(&mut self) -> Option<Self::Item> {
144 if self.slice.is_empty() {
145 None
146 } else {
147 let mut len = 1;
148 let mut iter = self.slice.windows(2);
149 while let Some([l, r]) = iter.next_back() {
150 if (self.predicate)(l, r) { len += 1 } else { break }
151 }
152 let slice = mem::take(&mut self.slice);
153 let (head, tail) = unsafe { split_at_mut_unchecked(slice, slice.len() - len) };
154 self.slice = head;
155 Some(tail)
156 }
157 }
158}
159
160impl<'a, T: 'a, P> FusedIterator for LinearGroupByMut<'a, T, P> where P: FnMut(&T, &T) -> bool {}
161
162impl<'a, T: 'a + fmt::Debug, P> fmt::Debug for LinearGroupByMut<'a, T, P> {
163 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
164 f.debug_struct("LinearGroupByMut").field("slice", &self.slice).finish()
165 }
166}