1use crate::iter::plumbing::*;
2use crate::iter::*;
3use std::marker::PhantomData;
4use std::{fmt, mem};
5
6trait ChunkBySlice<T>: AsRef<[T]> + Default + Send {
7 fn split(self, index: usize) -> (Self, Self);
8
9 fn find(&self, pred: &impl Fn(&T, &T) -> bool, start: usize, end: usize) -> Option<usize> {
10 self.as_ref()[start..end]
11 .windows(2)
12 .position(move |w| !pred(&w[0], &w[1]))
13 .map(|i| i + 1)
14 }
15
16 fn rfind(&self, pred: &impl Fn(&T, &T) -> bool, end: usize) -> Option<usize> {
17 self.as_ref()[..end]
18 .windows(2)
19 .rposition(move |w| !pred(&w[0], &w[1]))
20 .map(|i| i + 1)
21 }
22}
23
24impl<T: Sync> ChunkBySlice<T> for &[T] {
25 fn split(self, index: usize) -> (Self, Self) {
26 self.split_at(index)
27 }
28}
29
30impl<T: Send> ChunkBySlice<T> for &mut [T] {
31 fn split(self, index: usize) -> (Self, Self) {
32 self.split_at_mut(index)
33 }
34}
35
36struct ChunkByProducer<'p, T, Slice, Pred> {
37 slice: Slice,
38 pred: &'p Pred,
39 tail: usize,
40 marker: PhantomData<fn(&T)>,
41}
42
43impl<T, Slice, Pred> UnindexedProducer for ChunkByProducer<'_, T, Slice, Pred>
45where
46 Slice: ChunkBySlice<T>,
47 Pred: Fn(&T, &T) -> bool + Send + Sync,
48{
49 type Item = Slice;
50
51 fn split(self) -> (Self, Option<Self>) {
52 if self.tail < 2 {
53 return (Self { tail: 0, ..self }, None);
54 }
55
56 let mid = self.tail / 2;
58 let index = match self.slice.find(self.pred, mid, self.tail) {
59 Some(i) => Some(mid + i),
60 None => self.slice.rfind(self.pred, mid + 1),
61 };
62
63 if let Some(index) = index {
64 let (left, right) = self.slice.split(index);
65
66 let (left_tail, right_tail) = if index <= mid {
67 (index, 0)
70 } else {
71 (mid + 1, self.tail - index)
72 };
73
74 let left = Self {
76 slice: left,
77 tail: left_tail,
78 ..self
79 };
80
81 let right = Self {
83 slice: right,
84 tail: right_tail,
85 ..self
86 };
87
88 (left, Some(right))
89 } else {
90 (Self { tail: 0, ..self }, None)
92 }
93 }
94
95 fn fold_with<F>(self, mut folder: F) -> F
96 where
97 F: Folder<Self::Item>,
98 {
99 let Self {
100 slice, pred, tail, ..
101 } = self;
102
103 let (slice, tail) = if tail == slice.as_ref().len() {
104 (Some(slice), None)
106 } else if let Some(index) = slice.rfind(pred, tail) {
107 let (left, right) = slice.split(index);
110 (Some(left), Some(right))
111 } else {
112 (None, Some(slice))
114 };
115
116 if let Some(mut slice) = slice {
117 folder = folder.consume_iter(std::iter::from_fn(move || {
122 let len = slice.as_ref().len();
123 if len > 0 {
124 let i = slice.find(pred, 0, len).unwrap_or(len);
125 let (head, tail) = mem::take(&mut slice).split(i);
126 slice = tail;
127 Some(head)
128 } else {
129 None
130 }
131 }));
132 }
133
134 if let Some(tail) = tail {
135 folder = folder.consume(tail);
136 }
137
138 folder
139 }
140}
141
142pub 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}