Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/rayon-1.10.0/src/split_producer.rs
Line
Count
Source (jump to first uncovered line)
1
//! Common splitter for strings and slices
2
//!
3
//! This module is private, so these items are effectively `pub(super)`
4
5
use crate::iter::plumbing::{Folder, UnindexedProducer};
6
7
/// Common producer for splitting on a predicate.
8
pub(super) struct SplitProducer<'p, P, V, const INCL: bool = false> {
9
    data: V,
10
    separator: &'p P,
11
12
    /// Marks the endpoint beyond which we've already found no separators.
13
    tail: usize,
14
}
15
16
pub(super) type SplitInclusiveProducer<'p, P, V> = SplitProducer<'p, P, V, true>;
17
18
/// Helper trait so `&str`, `&[T]`, and `&mut [T]` can share `SplitProducer`.
19
pub(super) trait Fissile<P>: Sized {
20
    fn length(&self) -> usize;
21
    fn midpoint(&self, end: usize) -> usize;
22
    fn find(&self, separator: &P, start: usize, end: usize) -> Option<usize>;
23
    fn rfind(&self, separator: &P, end: usize) -> Option<usize>;
24
    fn split_once<const INCL: bool>(self, index: usize) -> (Self, Self);
25
    fn fold_splits<F, const INCL: bool>(self, separator: &P, folder: F, skip_last: bool) -> F
26
    where
27
        F: Folder<Self>,
28
        Self: Send;
29
}
30
31
impl<'p, P, V> SplitProducer<'p, P, V>
32
where
33
    V: Fissile<P> + Send,
34
{
35
0
    pub(super) fn new(data: V, separator: &'p P) -> Self {
36
0
        SplitProducer {
37
0
            tail: data.length(),
38
0
            data,
39
0
            separator,
40
0
        }
41
0
    }
42
}
43
44
impl<'p, P, V> SplitInclusiveProducer<'p, P, V>
45
where
46
    V: Fissile<P> + Send,
47
{
48
0
    pub(super) fn new_incl(data: V, separator: &'p P) -> Self {
49
0
        SplitProducer {
50
0
            tail: data.length(),
51
0
            data,
52
0
            separator,
53
0
        }
54
0
    }
55
}
56
57
impl<'p, P, V, const INCL: bool> SplitProducer<'p, P, V, INCL>
58
where
59
    V: Fissile<P> + Send,
60
{
61
    /// Common `fold_with` implementation, integrating `SplitTerminator`'s
62
    /// need to sometimes skip its final empty item.
63
0
    pub(super) fn fold_with<F>(self, folder: F, skip_last: bool) -> F
64
0
    where
65
0
        F: Folder<V>,
66
0
    {
67
0
        let SplitProducer {
68
0
            data,
69
0
            separator,
70
0
            tail,
71
0
        } = self;
72
0
73
0
        if tail == data.length() {
74
            // No tail section, so just let `fold_splits` handle it.
75
0
            data.fold_splits::<F, INCL>(separator, folder, skip_last)
76
0
        } else if let Some(index) = data.rfind(separator, tail) {
77
            // We found the last separator to complete the tail, so
78
            // end with that slice after `fold_splits` finds the rest.
79
0
            let (left, right) = data.split_once::<INCL>(index);
80
0
            let folder = left.fold_splits::<F, INCL>(separator, folder, false);
81
0
            if skip_last || folder.full() {
82
0
                folder
83
            } else {
84
0
                folder.consume(right)
85
            }
86
        } else {
87
            // We know there are no separators at all.  Return our whole data.
88
0
            if skip_last {
89
0
                folder
90
            } else {
91
0
                folder.consume(data)
92
            }
93
        }
94
0
    }
95
}
96
97
impl<'p, P, V, const INCL: bool> UnindexedProducer for SplitProducer<'p, P, V, INCL>
98
where
99
    V: Fissile<P> + Send,
100
    P: Sync,
101
{
102
    type Item = V;
103
104
0
    fn split(self) -> (Self, Option<Self>) {
105
0
        // Look forward for the separator, and failing that look backward.
106
0
        let mid = self.data.midpoint(self.tail);
107
0
        let index = match self.data.find(self.separator, mid, self.tail) {
108
0
            Some(i) => Some(mid + i),
109
0
            None => self.data.rfind(self.separator, mid),
110
        };
111
112
0
        if let Some(index) = index {
113
0
            let len = self.data.length();
114
0
            let (left, right) = self.data.split_once::<INCL>(index);
115
116
0
            let (left_tail, right_tail) = if index < mid {
117
                // If we scanned backwards to find the separator, everything in
118
                // the right side is exhausted, with no separators left to find.
119
0
                (index, 0)
120
            } else {
121
0
                let right_index = len - right.length();
122
0
                (mid, self.tail - right_index)
123
            };
124
125
            // Create the left split before the separator.
126
0
            let left = SplitProducer {
127
0
                data: left,
128
0
                tail: left_tail,
129
0
                ..self
130
0
            };
131
0
132
0
            // Create the right split following the separator.
133
0
            let right = SplitProducer {
134
0
                data: right,
135
0
                tail: right_tail,
136
0
                ..self
137
0
            };
138
0
139
0
            (left, Some(right))
140
        } else {
141
            // The search is exhausted, no more separators...
142
0
            (SplitProducer { tail: 0, ..self }, None)
143
        }
144
0
    }
145
146
0
    fn fold_with<F>(self, folder: F) -> F
147
0
    where
148
0
        F: Folder<Self::Item>,
149
0
    {
150
0
        self.fold_with(folder, false)
151
0
    }
152
}