1use std::fmt;
12
13use crate::buffer::Buffer;
14
15#[derive(Clone)]
17pub struct StrBuffer {
18 offsets: Buffer<i64>,
26 data: Buffer<u8>,
28}
29
30impl StrBuffer {
31 #[inline]
33 pub fn from_vec(v: Vec<String>) -> Self {
34 v.into_iter().collect()
35 }
36
37 #[inline]
39 pub fn from_buffers(offsets: Buffer<i64>, data: Buffer<u8>) -> Self {
40 StrBuffer { offsets, data }
41 }
42
43 #[inline]
45 pub fn buffers(&self) -> (&Buffer<i64>, &Buffer<u8>) {
46 (&self.offsets, &self.data)
47 }
48
49 #[inline]
50 pub fn len(&self) -> usize {
51 self.offsets.len().saturating_sub(1)
52 }
53
54 #[inline]
55 pub fn is_empty(&self) -> bool {
56 self.len() == 0
57 }
58
59 #[inline]
61 pub fn get(&self, i: usize) -> &str {
62 let off = self.offsets.as_slice();
63 let (s, e) = (off[i] as usize, off[i + 1] as usize);
64 unsafe { std::str::from_utf8_unchecked(&self.data.as_slice()[s..e]) }
67 }
68
69 #[inline]
78 pub unsafe fn get_unchecked(&self, i: usize) -> &str {
79 let off = self.offsets.as_slice();
80 let (s, e) = (*off.get_unchecked(i) as usize, *off.get_unchecked(i + 1) as usize);
81 std::str::from_utf8_unchecked(self.data.as_slice().get_unchecked(s..e))
82 }
83
84 #[inline]
89 pub fn iter(&self) -> impl Iterator<Item = &str> + '_ {
90 let off = self.offsets.as_slice();
91 let data = self.data.as_slice();
92 (0..self.len()).map(move |i| {
93 unsafe {
96 let s = *off.get_unchecked(i) as usize;
97 let e = *off.get_unchecked(i + 1) as usize;
98 std::str::from_utf8_unchecked(data.get_unchecked(s..e))
99 }
100 })
101 }
102
103 pub fn to_vec(&self) -> Vec<String> {
105 self.iter().map(String::from).collect()
106 }
107
108 pub fn slice(&self, start: usize, end: usize) -> StrBuffer {
111 (start..end).map(|i| self.get(i)).collect()
112 }
113
114 pub fn extend<S: AsRef<str>>(&mut self, items: impl IntoIterator<Item = S>) {
119 let data = self.data.make_mut();
120 let offsets = self.offsets.make_mut();
121 for s in items {
122 data.extend_from_slice(s.as_ref().as_bytes());
123 offsets.push(data.len() as i64);
124 }
125 }
126}
127
128#[derive(Default)]
130pub struct StrBufferBuilder {
131 offsets: Vec<i64>,
132 data: Vec<u8>,
133}
134
135impl StrBufferBuilder {
136 pub fn with_capacity(n: usize) -> Self {
137 let mut offsets = Vec::with_capacity(n + 1);
138 offsets.push(0);
139 StrBufferBuilder { offsets, data: Vec::new() }
140 }
141 #[inline]
142 pub fn push(&mut self, s: &str) {
143 self.data.extend_from_slice(s.as_bytes());
144 self.offsets.push(self.data.len() as i64);
145 }
146 pub fn finish(mut self) -> StrBuffer {
147 if self.offsets.is_empty() {
148 self.offsets.push(0);
149 }
150 StrBuffer {
151 offsets: Buffer::from_vec(self.offsets),
152 data: Buffer::from_vec(self.data),
153 }
154 }
155}
156
157impl PartialEq for StrBuffer {
158 fn eq(&self, other: &Self) -> bool {
159 self.len() == other.len() && self.iter().zip(other.iter()).all(|(a, b)| a == b)
160 }
161}
162
163impl fmt::Debug for StrBuffer {
164 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
165 f.debug_list().entries(self.iter()).finish()
166 }
167}
168
169impl<S: AsRef<str>> FromIterator<S> for StrBuffer {
170 fn from_iter<I: IntoIterator<Item = S>>(it: I) -> Self {
173 let mut offsets = vec![0i64];
174 let mut data = Vec::new();
175 for s in it {
176 data.extend_from_slice(s.as_ref().as_bytes());
177 offsets.push(data.len() as i64);
178 }
179 StrBuffer {
180 offsets: Buffer::from_vec(offsets),
181 data: Buffer::from_vec(data),
182 }
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn build_access_and_emptiness() {
192 let sb = StrBuffer::from_vec(vec!["a".into(), "".into(), "cd".into()]);
193 assert_eq!(sb.len(), 3);
194 assert!(!sb.is_empty());
195 assert_eq!(sb.get(2), "cd");
196 assert_eq!(unsafe { sb.get_unchecked(1) }, "");
198 assert_eq!(sb.iter().collect::<Vec<_>>(), ["a", "", "cd"]);
199 assert_eq!(sb.to_vec(), vec!["a".to_string(), "".into(), "cd".into()]);
200 assert!(StrBuffer::from_vec(vec![]).is_empty());
201 }
202
203 #[test]
204 fn buffers_round_trip_zero_copy() {
205 let sb = StrBuffer::from_vec(vec!["xy".into(), "z".into()]);
207 let (offsets, data) = sb.buffers();
208 let rebuilt = StrBuffer::from_buffers(offsets.clone(), data.clone());
209 assert_eq!(rebuilt, sb);
210 assert_eq!(rebuilt.slice(1, 2), StrBuffer::from_vec(vec!["z".into()]));
211 }
212
213 #[test]
214 fn builder_default_finishes_empty() {
215 let empty = StrBufferBuilder::default().finish();
217 assert!(empty.is_empty());
218 let mut b = StrBufferBuilder::with_capacity(2);
219 b.push("p");
220 b.push("qr");
221 assert_eq!(b.finish(), StrBuffer::from_vec(vec!["p".into(), "qr".into()]));
222 }
223
224 #[test]
225 fn debug_lists_cells() {
226 let sb = StrBuffer::from_vec(vec!["a".into(), "b".into()]);
227 assert_eq!(format!("{sb:?}"), r#"["a", "b"]"#);
228 }
229}