vec_strings/
strings.rs

1use std::convert::TryInto;
2use std::hint::unreachable_unchecked;
3use std::iter::{ExactSizeIterator, IntoIterator, Iterator};
4use std::slice;
5use std::str;
6
7use thin_vec::ThinVec;
8
9/// Store any string efficiently in an immutable way.
10///
11/// Can store at most `u32::MAX` strings, the accumulated length
12/// of these strings can be at most `u32::MAX`.
13#[derive(Debug, Default, Eq, PartialEq, Clone, Hash)]
14pub struct Strings {
15    strs: ThinVec<u8>,
16    ends: ThinVec<u32>,
17}
18
19impl Strings {
20    #[inline(always)]
21    pub fn new() -> Self {
22        Self::default()
23    }
24
25    /// * `len` - number of strings
26    pub fn with_capacity(len: u32) -> Self {
27        let mut strings = Self::default();
28        strings.reserve(len);
29        strings
30    }
31
32    /// **Strings can contain at most `u32::MAX` strings**
33    pub fn push(&mut self, s: &str) {
34        self.strs.extend_from_slice(s.as_bytes());
35        self.ends.push(
36            self.strs
37                .len()
38                .try_into()
39                .expect("Strings cannot contain more than u32::MAX strings"),
40        );
41    }
42
43    /// Accumulate length of all strings.
44    #[inline(always)]
45    pub fn strs_len(&self) -> u32 {
46        match self.strs.len().try_into() {
47            Ok(len) => len,
48            Err(_err) => unsafe { unreachable_unchecked() },
49        }
50    }
51
52    #[inline(always)]
53    pub fn len(&self) -> u32 {
54        match self.ends.len().try_into() {
55            Ok(len) => len,
56            Err(_err) => unsafe { unreachable_unchecked() },
57        }
58    }
59
60    #[inline(always)]
61    pub fn is_empty(&self) -> bool {
62        self.len() == 0
63    }
64
65    #[inline(always)]
66    pub fn reserve(&mut self, strs_cnt: u32) {
67        self.ends.reserve(strs_cnt as usize);
68    }
69
70    #[inline(always)]
71    pub fn reserve_strs(&mut self, cnt: usize) {
72        self.strs.reserve(cnt);
73    }
74
75    pub fn shrink_to_fit(&mut self) {
76        self.strs.shrink_to_fit();
77        self.ends.shrink_to_fit();
78    }
79
80    #[inline(always)]
81    pub fn iter(&self) -> StringsIter<'_> {
82        StringsIter {
83            strings: self,
84            ends_iter: self.ends.iter(),
85            start: 0,
86        }
87    }
88
89    pub fn get(&self, index: u32) -> Option<&str> {
90        let end = *self.ends.get(index as usize)?;
91        let start = if index == 0 {
92            0
93        } else {
94            self.ends[(index - 1) as usize]
95        };
96
97        Some(self.get_str_impl(start, end))
98    }
99
100    #[inline(always)]
101    fn get_str_impl(&self, start: u32, end: u32) -> &str {
102        unsafe { str::from_utf8_unchecked(&self.strs[(start as usize)..(end as usize)]) }
103    }
104
105    pub fn as_str(&self) -> &str {
106        self.get_str_impl(0, self.strs_len())
107    }
108
109    pub fn into_str(self) -> String {
110        let mut vec = Vec::with_capacity(self.strs.len());
111        vec.extend_from_slice(&self.strs);
112        unsafe { String::from_utf8_unchecked(vec) }
113    }
114}
115impl<'a> IntoIterator for &'a Strings {
116    type Item = &'a str;
117    type IntoIter = StringsIter<'a>;
118
119    #[inline(always)]
120    fn into_iter(self) -> Self::IntoIter {
121        self.iter()
122    }
123}
124
125#[derive(Clone, Debug)]
126pub struct StringsIter<'a> {
127    strings: &'a Strings,
128    ends_iter: slice::Iter<'a, u32>,
129    start: u32,
130}
131
132impl<'a> Iterator for StringsIter<'a> {
133    type Item = &'a str;
134
135    fn next(&mut self) -> Option<Self::Item> {
136        let start = self.start;
137        let end = *self.ends_iter.next()?;
138
139        self.start = end;
140
141        Some(self.strings.get_str_impl(start, end))
142    }
143
144    fn size_hint(&self) -> (usize, Option<usize>) {
145        let len = self.ends_iter.len();
146        (len, Some(len))
147    }
148}
149
150impl ExactSizeIterator for StringsIter<'_> {}
151
152#[cfg(test)]
153mod tests {
154    use super::Strings;
155    use std::convert::TryInto;
156
157    fn assert_strs_in(strs: &Strings, input_strs: &Vec<String>) {
158        for (string, input_str) in strs.iter().zip(input_strs) {
159            assert_eq!(string, input_str);
160        }
161    }
162
163    #[test]
164    fn test() {
165        let mut strs = Strings::new();
166        let input_strs: Vec<String> = (0..256).map(|n| n.to_string()).collect();
167
168        assert!(strs.is_empty());
169
170        for (i, input_str) in input_strs.iter().enumerate() {
171            strs.push(input_str);
172            assert_eq!(strs.len() as usize, i + 1);
173
174            assert_strs_in(&strs, &input_strs);
175        }
176
177        assert!(input_strs.iter().eq(strs.iter()));
178
179        for (i, input_str) in input_strs.iter().enumerate() {
180            assert_eq!(strs.get(i.try_into().unwrap()).unwrap(), input_str);
181        }
182
183        let input_str = input_strs.concat();
184
185        assert_eq!(strs.as_str(), input_str);
186        assert_eq!(strs.into_str(), input_str);
187    }
188}