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