slice_group_by/lib.rs
1//! Crate `slice-group-by` is a library for efficiently iterating on a slice by groups defined by
2//! a function that specifies if two elements are in the same group.
3//!
4//! # Example: Linear Searched Immutable Groups
5//!
6//! You will only need to define a function that returns `true` if two elements are in the same group.
7//!
8//! The `LinearGroupBy` iterator will always gives contiguous elements to the predicate function.
9//!
10//! ```rust
11//! use slice_group_by::GroupBy;
12//!
13//! let slice = &[1, 1, 1, 3, 3, 2, 2, 2];
14//!
15//! let mut iter = slice.linear_group_by_key(|x| -x);
16//!
17//! assert_eq!(iter.next(), Some(&[1, 1, 1][..]));
18//! assert_eq!(iter.next(), Some(&[3, 3][..]));
19//! assert_eq!(iter.next(), Some(&[2, 2, 2][..]));
20//! assert_eq!(iter.next(), None);
21//! ```
22//!
23//! # Example: Linear Searched Immutable Str Slices
24//!
25//! You will only need to define a function that returns `true` if two `char` are in the same group.
26//!
27//! The `LinearStrGroupBy` iterator will always gives contiguous `char` to the predicate function.
28//!
29//! ```rust
30//! use slice_group_by::StrGroupBy;
31//!
32//! let string = "aaaabbbbb饰饰cccc";
33//!
34//! let mut iter = string.linear_group_by(|a, b| a == b);
35//!
36//! assert_eq!(iter.next(), Some("aaaa"));
37//! assert_eq!(iter.next(), Some("bbbbb"));
38//! assert_eq!(iter.next(), Some("饰饰"));
39//! assert_eq!(iter.next(), Some("cccc"));
40//! assert_eq!(iter.next(), None);
41//! ```
42//!
43//! # Example: Binary Searched Mutable Groups
44//!
45//! It is also possible to get mutable non overlapping groups of a slice.
46//!
47//! The `BinaryGroupBy/Mut` and `ExponentialGroupBy/Mut` iterators will not necessarily
48//! gives contiguous elements to the predicate function. The predicate function should implement
49//! an order consistent with the sort order of the slice.
50//!
51//! ```rust
52//! use slice_group_by::GroupByMut;
53//!
54//! let slice = &mut [1, 1, 1, 2, 2, 2, 3, 3];
55//!
56//! let mut iter = slice.binary_group_by_mut(|a, b| a == b);
57//!
58//! assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
59//! assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
60//! assert_eq!(iter.next(), Some(&mut [3, 3][..]));
61//! assert_eq!(iter.next(), None);
62//! ```
63//!
64//! # Example: Exponential Searched Mutable Groups starting from the End
65//!
66//! It is also possible to get mutable non overlapping groups of a slice even starting from the end of it.
67//!
68//! ```rust
69//! use slice_group_by::GroupByMut;
70//!
71//! let slice = &mut [1, 1, 1, 2, 2, 2, 3, 3];
72//!
73//! let mut iter = slice.exponential_group_by_mut(|a, b| a == b).rev();
74//!
75//! assert_eq!(iter.next(), Some(&mut [3, 3][..]));
76//! assert_eq!(iter.next(), Some(&mut [2, 2, 2][..]));
77//! assert_eq!(iter.next(), Some(&mut [1, 1, 1][..]));
78//! assert_eq!(iter.next(), None);
79//! ```
80//!
81
82#![cfg_attr(feature = "nightly", feature(ptr_offset_from))]
83#![cfg_attr(feature = "nightly", feature(test))]
84
85#![cfg_attr(all(not(test), not(feature = "std")), no_std)]
86#[cfg(all(not(test), not(feature = "std")))]
87extern crate core as std;
88
89macro_rules! group_by_wrapped {
90 (struct $name:ident, $elem:ty) => {
91 impl<'a, T: 'a> std::iter::Iterator for $name<'a, T>
92 where T: PartialEq,
93 {
94 type Item = $elem;
95
96 fn next(&mut self) -> Option<Self::Item> {
97 self.0.next()
98 }
99
100 fn size_hint(&self) -> (usize, Option<usize>) {
101 self.0.size_hint()
102 }
103
104 fn last(self) -> Option<Self::Item> {
105 self.0.last()
106 }
107 }
108
109 impl<'a, T: 'a> DoubleEndedIterator for $name<'a, T>
110 where T: PartialEq,
111 {
112 fn next_back(&mut self) -> Option<Self::Item> {
113 self.0.next_back()
114 }
115 }
116
117 impl<'a, T: 'a> std::iter::FusedIterator for $name<'a, T>
118 where T: PartialEq,
119 { }
120 }
121}
122
123mod linear_group;
124mod binary_group;
125mod exponential_group;
126mod linear_str_group;
127
128use std::cmp::{self, Ordering};
129
130pub use self::linear_group::{
131 LinearGroupByKey,
132 LinearGroupBy,
133 LinearGroup,
134 LinearGroupByKeyMut,
135 LinearGroupByMut,
136 LinearGroupMut,
137};
138
139pub use self::binary_group::{
140 BinaryGroupByKey,
141 BinaryGroupBy,
142 BinaryGroup,
143 BinaryGroupByKeyMut,
144 BinaryGroupByMut,
145 BinaryGroupMut,
146};
147
148pub use self::exponential_group::{
149 ExponentialGroupByKey,
150 ExponentialGroupBy,
151 ExponentialGroup,
152 ExponentialGroupByKeyMut,
153 ExponentialGroupByMut,
154 ExponentialGroupMut,
155};
156
157pub use self::linear_str_group::{
158 LinearStrGroupByKey,
159 LinearStrGroupBy,
160 LinearStrGroup,
161 LinearStrGroupByKeyMut,
162 LinearStrGroupByMut,
163 LinearStrGroupMut,
164};
165
166#[cfg(feature = "nightly")]
167#[inline]
168unsafe fn offset_from<T>(to: *const T, from: *const T) -> usize {
169 to.offset_from(from) as usize
170}
171
172#[cfg(not(feature = "nightly"))]
173#[inline]
174unsafe fn offset_from<T>(to: *const T, from: *const T) -> usize {
175 use std::mem;
176 (to as usize - from as usize) / mem::size_of::<T>()
177}
178
179/// Exponential searches this sorted slice for a given element.
180///
181/// If the value is found then `Ok` is returned, containing the index of the matching element;
182/// if the value is not found then `Err` is returned, containing the index where a matching element
183/// could be inserted while maintaining sorted order.
184///
185/// # Examples
186///
187/// Looks up a series of four elements. The first is found, with a
188/// uniquely determined position; the second and third are not
189/// found; the fourth could match any position in `[1, 4]`.
190///
191/// ```
192/// use slice_group_by::exponential_search;
193///
194/// let s = &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
195///
196/// assert_eq!(exponential_search(s, &13), Ok(9));
197/// assert_eq!(exponential_search(s, &4), Err(7));
198/// assert_eq!(exponential_search(s, &100), Err(13));
199/// let r = exponential_search(s, &1);
200/// assert!(match r { Ok(1..=4) => true, _ => false, });
201/// ```
202#[inline]
203pub fn exponential_search<T>(slice: &[T], elem: &T) -> Result<usize, usize>
204where T: Ord
205{
206 exponential_search_by(slice, |x| x.cmp(elem))
207}
208
209/// Binary searches this sorted slice with a comparator function.
210///
211/// The comparator function should implement an order consistent with the sort order of
212/// the underlying slice, returning an order code that indicates whether its argument
213/// is `Less`, `Equal` or `Greater` the desired target.
214///
215/// If the value is found then `Ok` is returned, containing the index of the matching element;
216/// if the value is not found then `Err` is returned, containing the index where a matching element
217/// could be inserted while maintaining sorted order.
218///
219/// # Examples
220///
221/// Looks up a series of four elements. The first is found, with a
222/// uniquely determined position; the second and third are not
223/// found; the fourth could match any position in `[1, 4]`.
224///
225/// ```
226/// use slice_group_by::exponential_search_by;
227///
228/// let s = &[0, 1, 1, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55];
229///
230/// let seek = 13;
231/// assert_eq!(exponential_search_by(s, |probe| probe.cmp(&seek)), Ok(9));
232/// let seek = 4;
233/// assert_eq!(exponential_search_by(s, |probe| probe.cmp(&seek)), Err(7));
234/// let seek = 100;
235/// assert_eq!(exponential_search_by(s, |probe| probe.cmp(&seek)), Err(13));
236/// let seek = 1;
237/// let r = exponential_search_by(s, |probe| probe.cmp(&seek));
238/// assert!(match r { Ok(1..=4) => true, _ => false, });
239/// ```
240#[inline]
241pub fn exponential_search_by<T, F>(slice: &[T], mut f: F) -> Result<usize, usize>
242where F: FnMut(&T) -> Ordering,
243{
244 let mut index = 1;
245 while index < slice.len() && f(&slice[index]) == Ordering::Less {
246 index *= 2;
247 }
248
249 let half_bound = index / 2;
250 let bound = cmp::min(index + 1, slice.len());
251
252 match slice[half_bound..bound].binary_search_by(f) {
253 Ok(pos) => Ok(half_bound + pos),
254 Err(pos) => Err(half_bound + pos),
255 }
256}
257
258/// Binary searches this sorted slice with a key extraction function.
259///
260/// Assumes that the slice is sorted by the key.
261///
262/// If the value is found then `Ok` is returned, containing the index of the matching element;
263/// if the value is not found then `Err` is returned, containing the index where a matching element
264/// could be inserted while maintaining sorted order.
265///
266/// # Examples
267///
268/// Looks up a series of four elements. The first is found, with a
269/// uniquely determined position; the second and third are not
270/// found; the fourth could match any position in `[1, 4]`.
271///
272/// ```
273/// use slice_group_by::exponential_search_by_key;
274///
275/// let s = &[(0, 0), (2, 1), (4, 1), (5, 1), (3, 1),
276/// (1, 2), (2, 3), (4, 5), (5, 8), (3, 13),
277/// (1, 21), (2, 34), (4, 55)];
278///
279/// assert_eq!(exponential_search_by_key(s, &13, |&(a,b)| b), Ok(9));
280/// assert_eq!(exponential_search_by_key(s, &4, |&(a,b)| b), Err(7));
281/// assert_eq!(exponential_search_by_key(s, &100, |&(a,b)| b), Err(13));
282/// let r = exponential_search_by_key(s, &1, |&(a,b)| b);
283/// assert!(match r { Ok(1..=4) => true, _ => false, });
284/// ```
285#[inline]
286pub fn exponential_search_by_key<T, B, F>(slice: &[T], b: &B, mut f: F) -> Result<usize, usize>
287where F: FnMut(&T) -> B,
288 B: Ord
289{
290 exponential_search_by(slice, |k| f(k).cmp(b))
291}
292
293/// A convenient trait to construct an iterator returning non-overlapping groups
294/// defined by a predicate.
295pub trait GroupBy<T>
296{
297 /// Returns an iterator on slice groups based that will use the given function to generate keys
298 /// and determine groups based on them. It uses *linear search* to iterate over groups.
299 fn linear_group_by_key<F, K>(&self, func: F) -> LinearGroupByKey<T, F>
300 where F: FnMut(&T) -> K,
301 K: PartialEq;
302
303 /// Returns an iterator on slice groups using the *linear search* method.
304 fn linear_group_by<P>(&self, predicate: P) -> LinearGroupBy<T, P>
305 where P: FnMut(&T, &T) -> bool;
306
307 /// Returns an iterator on slice groups based on the [`PartialEq::eq`] method of `T`,
308 /// it uses *linear search* to iterate over groups.
309 ///
310 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#tymethod.eq
311 fn linear_group(&self) -> LinearGroup<T>
312 where T: PartialEq;
313
314 /// Returns an iterator on slice groups based that will use the given function to generate keys
315 /// and determine groups based on them. It uses *binary search* to iterate over groups.
316 ///
317 /// The predicate function should implement an order consistent with
318 /// the sort order of the slice.
319 fn binary_group_by_key<F, K>(&self, func: F) -> BinaryGroupByKey<T, F>
320 where F: FnMut(&T) -> K,
321 K: PartialEq;
322
323 /// Returns an iterator on slice groups using the *binary search* method.
324 ///
325 /// The predicate function should implement an order consistent with
326 /// the sort order of the slice.
327 fn binary_group_by<P>(&self, predicate: P) -> BinaryGroupBy<T, P>
328 where P: FnMut(&T, &T) -> bool;
329
330 /// Returns an iterator on slice groups based on the [`PartialEq::eq`] method of `T`,
331 /// it uses *binary search* to iterate over groups.
332 ///
333 /// The predicate function should implement an order consistent with
334 /// the sort order of the slice.
335 ///
336 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#tymethod.eq
337 fn binary_group(&self) -> BinaryGroup<T>
338 where T: PartialEq;
339
340 /// Returns an iterator on slice groups based that will use the given function to generate keys
341 /// and determine groups based on them. It uses *exponential search* to iterate over groups.
342 ///
343 /// The predicate function should implement an order consistent with
344 /// the sort order of the slice.
345 fn exponential_group_by_key<F, K>(&self, func: F) -> ExponentialGroupByKey<T, F>
346 where F: Fn(&T) -> K,
347 K: PartialEq;
348
349 /// Returns an iterator on slice groups using the *exponential search* method.
350 ///
351 /// The predicate function should implement an order consistent with
352 /// the sort order of the slice.
353 fn exponential_group_by<P>(&self, predicate: P) -> ExponentialGroupBy<T, P>
354 where P: FnMut(&T, &T) -> bool;
355
356 /// Returns an iterator on slice groups based on the [`PartialEq::eq`] method of `T`,
357 /// it uses *exponential search* to iterate over groups.
358 ///
359 /// The predicate function should implement an order consistent with
360 /// the sort order of the slice.
361 ///
362 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#tymethod.eq
363 fn exponential_group(&self) -> ExponentialGroup<T>
364 where T: PartialEq;
365}
366
367/// A convenient trait to construct an iterator returning non-overlapping *mutable*
368/// groups defined by a predicate.
369pub trait GroupByMut<T>
370{
371 /// Returns an iterator on *mutable* slice groups based that will use the given function
372 /// to generate keys and determine groups based on them. It uses *linear search*
373 /// to iterate over groups.
374 fn linear_group_by_key_mut<F, K>(&mut self, func: F) -> LinearGroupByKeyMut<T, F>
375 where F: FnMut(&T) -> K,
376 K: PartialEq;
377
378 /// Returns an iterator on *mutable* slice groups using the *linear search* method.
379 fn linear_group_by_mut<P>(&mut self, predicate: P) -> LinearGroupByMut<T, P>
380 where P: FnMut(&T, &T) -> bool;
381
382 /// Returns an iterator on *mutable* slice groups based on the [`PartialEq::eq`] method of `T`,
383 /// it uses *linear search* to iterate over groups.
384 ///
385 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#tymethod.eq
386 fn linear_group_mut(&mut self) -> LinearGroupMut<T>
387 where T: PartialEq;
388
389 /// Returns an iterator on *mutable* slice groups based that will use the given function
390 /// to generate keys and determine groups based on them. It uses *binary search*
391 /// to iterate over groups.
392 ///
393 /// The predicate function should implement an order consistent with
394 /// the sort order of the slice.
395 fn binary_group_by_key_mut<F, K>(&mut self, func: F) -> BinaryGroupByKeyMut<T, F>
396 where F: FnMut(&T) -> K,
397 K: PartialEq;
398
399 /// Returns an iterator on *mutable* slice groups using the *binary search* method.
400 ///
401 /// The predicate function should implement an order consistent with
402 /// the sort order of the slice.
403 fn binary_group_by_mut<P>(&mut self, predicate: P) -> BinaryGroupByMut<T, P>
404 where P: FnMut(&T, &T) -> bool;
405
406 /// Returns an iterator on *mutable* slice groups based on the [`PartialEq::eq`] method of `T`,
407 /// it uses *binary search* to iterate over groups.
408 ///
409 /// The predicate function should implement an order consistent with
410 /// the sort order of the slice.
411 ///
412 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#tymethod.eq
413 fn binary_group_mut(&mut self) -> BinaryGroupMut<T>
414 where T: PartialEq;
415
416 /// Returns an iterator on *mutable* slice groups based that will use the given function
417 /// to generate keys and determine groups based on them. It uses *exponential search*
418 /// to iterate over groups.
419 ///
420 /// The predicate function should implement an order consistent with
421 /// the sort order of the slice.
422 fn exponential_group_by_key_mut<F, K>(&mut self, func: F) -> ExponentialGroupByKeyMut<T, F>
423 where F: Fn(&T) -> K,
424 K: PartialEq;
425
426 /// Returns an iterator on *mutable* slice groups using the *exponential search* method.
427 ///
428 /// The predicate function should implement an order consistent with
429 /// the sort order of the slice.
430 fn exponential_group_by_mut<P>(&mut self, predicate: P) -> ExponentialGroupByMut<T, P>
431 where P: FnMut(&T, &T) -> bool;
432
433 /// Returns an iterator on *mutable* slice groups based on the [`PartialEq::eq`] method of `T`,
434 /// it uses *exponential search* to iterate over groups.
435 ///
436 /// The predicate function should implement an order consistent with
437 /// the sort order of the slice.
438 ///
439 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html#tymethod.eq
440 fn exponential_group_mut(&mut self) -> ExponentialGroupMut<T>
441 where T: PartialEq;
442}
443
444impl<T> GroupBy<T> for [T]
445{
446 fn linear_group_by_key<F, K>(&self, func: F) -> LinearGroupByKey<T, F>
447 where F: FnMut(&T) -> K,
448 K: PartialEq
449 {
450 LinearGroupByKey::new(self, func)
451 }
452
453 fn linear_group_by<P>(&self, predicate: P) -> LinearGroupBy<T, P>
454 where P: FnMut(&T, &T) -> bool,
455 {
456 LinearGroupBy::new(self, predicate)
457 }
458
459 fn linear_group(&self) -> LinearGroup<T>
460 where T: PartialEq,
461 {
462 LinearGroup::new(self)
463 }
464
465 fn binary_group_by_key<F, K>(&self, func: F) -> BinaryGroupByKey<T, F>
466 where F: FnMut(&T) -> K,
467 K: PartialEq
468 {
469 BinaryGroupByKey::new(self, func)
470 }
471
472 fn binary_group_by<P>(&self, predicate: P) -> BinaryGroupBy<T, P>
473 where P: FnMut(&T, &T) -> bool,
474 {
475 BinaryGroupBy::new(self, predicate)
476 }
477
478 fn binary_group(&self) -> BinaryGroup<T>
479 where T: PartialEq,
480 {
481 BinaryGroup::new(self)
482 }
483
484 fn exponential_group_by_key<F, K>(&self, func: F) -> ExponentialGroupByKey<T, F>
485 where F: Fn(&T) -> K,
486 K: PartialEq
487 {
488 ExponentialGroupByKey::new(self, func)
489 }
490
491 fn exponential_group_by<P>(&self, predicate: P) -> ExponentialGroupBy<T, P>
492 where P: FnMut(&T, &T) -> bool,
493 {
494 ExponentialGroupBy::new(self, predicate)
495 }
496
497 fn exponential_group(&self) -> ExponentialGroup<T>
498 where T: PartialEq,
499 {
500 ExponentialGroup::new(self)
501 }
502}
503
504impl<T> GroupByMut<T> for [T]
505{
506 fn linear_group_by_key_mut<F, K>(&mut self, func: F) -> LinearGroupByKeyMut<T, F>
507 where F: FnMut(&T) -> K,
508 K: PartialEq
509 {
510 LinearGroupByKeyMut::new(self, func)
511 }
512
513 fn linear_group_by_mut<P>(&mut self, predicate: P) -> LinearGroupByMut<T, P>
514 where P: FnMut(&T, &T) -> bool,
515 {
516 LinearGroupByMut::new(self, predicate)
517 }
518
519 fn linear_group_mut(&mut self) -> LinearGroupMut<T>
520 where T: PartialEq,
521 {
522 LinearGroupMut::new(self)
523 }
524
525 fn binary_group_by_key_mut<F, K>(&mut self, func: F) -> BinaryGroupByKeyMut<T, F>
526 where F: FnMut(&T) -> K,
527 K: PartialEq
528 {
529 BinaryGroupByKeyMut::new(self, func)
530 }
531
532 fn binary_group_by_mut<P>(&mut self, predicate: P) -> BinaryGroupByMut<T, P>
533 where P: FnMut(&T, &T) -> bool,
534 {
535 BinaryGroupByMut::new(self, predicate)
536 }
537
538 fn binary_group_mut(&mut self) -> BinaryGroupMut<T>
539 where T: PartialEq,
540 {
541 BinaryGroupMut::new(self)
542 }
543
544 fn exponential_group_by_key_mut<F, K>(&mut self, func: F) -> ExponentialGroupByKeyMut<T, F>
545 where F: Fn(&T) -> K,
546 K: PartialEq
547 {
548 ExponentialGroupByKeyMut::new(self, func)
549 }
550
551 fn exponential_group_by_mut<P>(&mut self, predicate: P) -> ExponentialGroupByMut<T, P>
552 where P: FnMut(&T, &T) -> bool,
553 {
554 ExponentialGroupByMut::new(self, predicate)
555 }
556
557 fn exponential_group_mut(&mut self) -> ExponentialGroupMut<T>
558 where T: PartialEq,
559 {
560 ExponentialGroupMut::new(self)
561 }
562}
563
564/// A convenient trait to construct an iterator returning non-overlapping `str` slices
565/// defined by a predicate.
566pub trait StrGroupBy
567{
568 /// Returns an iterator on `str` groups based that will use the given function
569 /// to generate keys and determine groups based on them. It uses *linear search*
570 /// to iterate over groups.
571 fn linear_group_by_key<F, K>(&self, func: F) -> LinearStrGroupByKey<F>
572 where F: FnMut(char) -> K,
573 K: PartialEq;
574
575 /// Returns an iterator on `str` groups using the *linear search* method.
576 fn linear_group_by<P>(&self, predicate: P) -> LinearStrGroupBy<P>
577 where P: FnMut(char, char) -> bool;
578
579 /// Returns an iterator on `str` groups based on the [`PartialEq::eq`] method of `char`,
580 /// it uses *linear search* to iterate over groups.
581 ///
582 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/primitive.char.html#impl-PartialEq%3Cchar%3E
583 fn linear_group(&self) -> LinearStrGroup;
584}
585
586/// A convenient trait to construct an iterator returning non-overlapping *mutable* `str` slices
587/// defined by a predicate.
588pub trait StrGroupByMut
589{
590 /// Returns an iterator on *mutable* `str` groups based that will use the given function
591 /// to generate keys and determine groups based on them. It uses *linear search*
592 /// to iterate over groups.
593 fn linear_group_by_key_mut<F, K>(&mut self, func: F) -> LinearStrGroupByKeyMut<F>
594 where F: FnMut(char) -> K,
595 K: PartialEq;
596
597 /// Returns an iterator on *mutable* `str` groups using the *linear search* method.
598 fn linear_group_by_mut<P>(&mut self, predicate: P) -> LinearStrGroupByMut<P>
599 where P: FnMut(char, char) -> bool;
600
601 /// Returns an iterator on *mutable* `str` groups based on the [`PartialEq::eq`] method of `char`,
602 /// it uses *linear search* to iterate over groups.
603 ///
604 /// [`PartialEq::eq`]: https://doc.rust-lang.org/std/primitive.char.html#impl-PartialEq%3Cchar%3E
605 fn linear_group_mut(&mut self) -> LinearStrGroupMut;
606}
607
608impl StrGroupBy for str
609{
610 fn linear_group_by_key<F, K>(&self, func: F) -> LinearStrGroupByKey<F>
611 where F: FnMut(char) -> K,
612 K: PartialEq
613 {
614 LinearStrGroupByKey::new(self, func)
615 }
616
617 fn linear_group_by<P>(&self, predicate: P) -> LinearStrGroupBy<P>
618 where P: FnMut(char, char) -> bool,
619 {
620 LinearStrGroupBy::new(self, predicate)
621 }
622
623 fn linear_group(&self) -> LinearStrGroup {
624 LinearStrGroup::new(self)
625 }
626}
627
628impl StrGroupByMut for str
629{
630 fn linear_group_by_key_mut<F, K>(&mut self, func: F) -> LinearStrGroupByKeyMut<F>
631 where F: FnMut(char) -> K,
632 K: PartialEq
633 {
634 LinearStrGroupByKeyMut::new(self, func)
635 }
636
637 fn linear_group_by_mut<P>(&mut self, predicate: P) -> LinearStrGroupByMut<P>
638 where P: FnMut(char, char) -> bool,
639 {
640 LinearStrGroupByMut::new(self, predicate)
641 }
642
643 fn linear_group_mut(&mut self) -> LinearStrGroupMut {
644 LinearStrGroupMut::new(self)
645 }
646}