vec_strings/
strings_no_index.rs

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