1use crate::iter::plumbing::*;
2use crate::iter::*;
3use std::fmt;
4use std::marker::PhantomData;
5
6trait ChunkBySlice<T>: AsRef<[T]> + Default + Send {
7 fn split(self, index: usize) -> (Self, Self);
8 fn chunk_by(self, pred: &impl Fn(&T, &T) -> bool) -> impl Iterator<Item = Self>;
9
10 fn find(&self, pred: &impl Fn(&T, &T) -> bool, start: usize, end: usize) -> Option<usize> {
11 self.as_ref()[start..end]
12 .windows(2)
13 .position(move |w| !pred(&w[0], &w[1]))
14 .map(|i| i + 1)
15 }
16
17 fn rfind(&self, pred: &impl Fn(&T, &T) -> bool, end: usize) -> Option<usize> {
18 self.as_ref()[..end]
19 .windows(2)
20 .rposition(move |w| !pred(&w[0], &w[1]))
21 .map(|i| i + 1)
22 }
23}
24
25impl<T: Sync> ChunkBySlice<T> for &[T] {
26 fn split(self, index: usize) -> (Self, Self) {
27 self.split_at(index)
28 }
29
30 fn chunk_by(self, pred: &impl Fn(&T, &T) -> bool) -> impl Iterator<Item = Self> {
31 self.chunk_by(pred)
32 }
33}
34
35impl<T: Send> ChunkBySlice<T> for &mut [T] {
36 fn split(self, index: usize) -> (Self, Self) {
37 self.split_at_mut(index)
38 }
39
40 fn chunk_by(self, pred: &impl Fn(&T, &T) -> bool) -> impl Iterator<Item = Self> {
41 self.chunk_by_mut(pred)
42 }
43}
44
45struct ChunkByProducer<'p, T, Slice, Pred> {
46 slice: Slice,
47 pred: &'p Pred,
48 tail: usize,
49 marker: PhantomData<fn(&T)>,
50}
51
52impl<T, Slice, Pred> UnindexedProducer for ChunkByProducer<'_, T, Slice, Pred>
54where
55 Slice: ChunkBySlice<T>,
56 Pred: Fn(&T, &T) -> bool + Send + Sync,
57{
58 type Item = Slice;
59
60 fn split(self) -> (Self, Option<Self>) {
61 if self.tail < 2 {
62 return (Self { tail: 0, ..self }, None);
63 }
64
65 let mid = self.tail / 2;
67 let index = match self.slice.find(self.pred, mid, self.tail) {
68 Some(i) => Some(mid + i),
69 None => self.slice.rfind(self.pred, mid + 1),
70 };
71
72 if let Some(index) = index {
73 let (left, right) = self.slice.split(index);
74
75 let (left_tail, right_tail) = if index <= mid {
76 (index, 0)
79 } else {
80 (mid + 1, self.tail - index)
81 };
82
83 let left = Self {
85 slice: left,
86 tail: left_tail,
87 ..self
88 };
89
90 let right = Self {
92 slice: right,
93 tail: right_tail,
94 ..self
95 };
96
97 (left, Some(right))
98 } else {
99 (Self { tail: 0, ..self }, None)
101 }
102 }
103
104 fn fold_with<F>(self, mut folder: F) -> F
105 where
106 F: Folder<Self::Item>,
107 {
108 let Self {
109 slice, pred, tail, ..
110 } = self;
111
112 let (slice, tail) = if tail == slice.as_ref().len() {
113 (Some(slice), None)
115 } else if let Some(index) = slice.rfind(pred, tail) {
116 let (left, right) = slice.split(index);
119 (Some(left), Some(right))
120 } else {
121 (None, Some(slice))
123 };
124
125 if let Some(slice) = slice {
126 folder = folder.consume_iter(slice.chunk_by(pred));
127 }
128
129 if let Some(tail) = tail {
130 folder = folder.consume(tail);
131 }
132
133 folder
134 }
135}
136
137pub struct ChunkBy<'data, T, P> {
143 pred: P,
144 slice: &'data [T],
145}
146
147impl<T, P: Clone> Clone for ChunkBy<'_, T, P> {
148 fn clone(&self) -> Self {
149 ChunkBy {
150 pred: self.pred.clone(),
151 slice: self.slice,
152 }
153 }
154}
155
156impl<T: fmt::Debug, P> fmt::Debug for ChunkBy<'_, T, P> {
157 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
158 f.debug_struct("ChunkBy")
159 .field("slice", &self.slice)
160 .finish()
161 }
162}
163
164impl<'data, T, P> ChunkBy<'data, T, P> {
165 pub(super) fn new(slice: &'data [T], pred: P) -> Self {
166 Self { pred, slice }
167 }
168}
169
170impl<'data, T, P> ParallelIterator for ChunkBy<'data, T, P>
171where
172 T: Sync,
173 P: Fn(&T, &T) -> bool + Send + Sync,
174{
175 type Item = &'data [T];
176
177 fn drive_unindexed<C>(self, consumer: C) -> C::Result
178 where
179 C: UnindexedConsumer<Self::Item>,
180 {
181 bridge_unindexed(
182 ChunkByProducer {
183 tail: self.slice.len(),
184 slice: self.slice,
185 pred: &self.pred,
186 marker: PhantomData,
187 },
188 consumer,
189 )
190 }
191}
192
193pub struct ChunkByMut<'data, T, P> {
200 pred: P,
201 slice: &'data mut [T],
202}
203
204impl<T: fmt::Debug, P> fmt::Debug for ChunkByMut<'_, T, P> {
205 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
206 f.debug_struct("ChunkByMut")
207 .field("slice", &self.slice)
208 .finish()
209 }
210}
211
212impl<'data, T, P> ChunkByMut<'data, T, P> {
213 pub(super) fn new(slice: &'data mut [T], pred: P) -> Self {
214 Self { pred, slice }
215 }
216}
217
218impl<'data, T, P> ParallelIterator for ChunkByMut<'data, T, P>
219where
220 T: Send,
221 P: Fn(&T, &T) -> bool + Send + Sync,
222{
223 type Item = &'data mut [T];
224
225 fn drive_unindexed<C>(self, consumer: C) -> C::Result
226 where
227 C: UnindexedConsumer<Self::Item>,
228 {
229 bridge_unindexed(
230 ChunkByProducer {
231 tail: self.slice.len(),
232 slice: self.slice,
233 pred: &self.pred,
234 marker: PhantomData,
235 },
236 consumer,
237 )
238 }
239}