slice_group_by/linear_str_group/
linear_str_group_by.rs

1use std::mem;
2use super::{str_as_ptr, str_as_mut_ptr, str_from_raw_parts, str_from_raw_parts_mut};
3
4macro_rules! str_group_by {
5    (struct $name:ident, $elem:ty, $as_ptr:ident, $as_str:ident) => {
6        impl<'a, P> $name<'a, P> {
7            #[inline]
8            pub fn as_str(&self) -> &str {
9                self.inner
10            }
11
12            #[inline]
13            pub fn is_empty(&self) -> bool {
14                self.inner.is_empty()
15            }
16
17            #[inline]
18            pub fn remainder_len(&self) -> usize {
19                self.inner.len()
20            }
21        }
22
23        impl<'a, P> std::iter::Iterator for $name<'a, P>
24        where P: FnMut(char, char) -> bool,
25        {
26            type Item = $elem;
27
28            #[inline]
29            fn next(&mut self) -> Option<Self::Item> {
30                if self.inner.is_empty() { return None }
31
32                let mut iter = self.inner.char_indices().peekable();
33                while let (Some((_, ac)), Some((bi, bc))) = (iter.next(), iter.peek().cloned())
34                {
35                    if !(self.predicate)(ac, bc) {
36                        let len = self.inner.len();
37                        let ptr = $as_ptr(self.inner);
38
39                        let left = unsafe { $as_str(ptr, bi) };
40                        let right = unsafe { $as_str(ptr.add(bi), len - bi) };
41
42                        self.inner = right;
43                        return Some(left);
44                    }
45                }
46
47                let output = mem::replace(&mut self.inner, Default::default());
48                return Some(output);
49            }
50
51            fn last(mut self) -> Option<Self::Item> {
52                self.next_back()
53            }
54        }
55
56        impl<'a, P> std::iter::DoubleEndedIterator for $name<'a, P>
57        where P: FnMut(char, char) -> bool,
58        {
59            #[inline]
60            fn next_back(&mut self) -> Option<Self::Item> {
61                if self.inner.is_empty() { return None }
62
63                let mut iter = self.inner.char_indices().rev().peekable();
64                while let (Some((ai, ac)), Some((_, bc))) = (iter.next(), iter.peek().cloned())
65                {
66                    if !(self.predicate)(ac, bc) {
67                        let len = self.inner.len();
68                        let ptr = $as_ptr(self.inner);
69
70                        let left = unsafe { $as_str(ptr, ai) };
71                        let right = unsafe { $as_str(ptr.add(ai), len - ai) };
72
73                        self.inner = left;
74                        return Some(right);
75                    }
76                }
77
78                let output = mem::replace(&mut self.inner, Default::default());
79                return Some(output);
80            }
81        }
82
83        impl<'a, P> std::iter::FusedIterator for $name<'a, P>
84        where P: FnMut(char, char) -> bool,
85        { }
86    }
87}
88
89/// An iterator that will return non-overlapping groups in the `str`
90/// using *linear/sequential search*.
91///
92/// It will give two contiguous `char` to the predicate function.
93pub struct LinearStrGroupBy<'a, P> {
94    inner: &'a str,
95    predicate: P,
96}
97
98impl<'a, P> LinearStrGroupBy<'a, P> {
99    pub fn new(string: &'a str, predicate: P) -> Self {
100        Self { inner: string, predicate }
101    }
102}
103
104str_group_by!{ struct LinearStrGroupBy, &'a str, str_as_ptr, str_from_raw_parts }
105
106/// An iterator that will return non-overlapping *mutable* groups in the `str`
107/// using *linear/sequential search*.
108///
109/// It will give two contiguous `char` to the predicate function.
110pub struct LinearStrGroupByMut<'a, P> {
111    inner: &'a mut str,
112    predicate: P,
113}
114
115impl<'a, P> LinearStrGroupByMut<'a, P> {
116    pub fn new(string: &'a mut str, predicate: P) -> Self {
117        Self { inner: string, predicate }
118    }
119
120    #[inline]
121    pub fn as_str_mut(&mut self) -> &mut str {
122        &mut self.inner
123    }
124}
125
126str_group_by!{ struct LinearStrGroupByMut, &'a mut str, str_as_mut_ptr, str_from_raw_parts_mut }