arrow_buffer/builder/
offset.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::ops::Deref;
19
20use crate::{ArrowNativeType, OffsetBuffer};
21
22/// Builder of [`OffsetBuffer`]
23#[derive(Debug)]
24pub struct OffsetBufferBuilder<O: ArrowNativeType> {
25    offsets: Vec<O>,
26    last_offset: usize,
27}
28
29impl<O: ArrowNativeType> OffsetBufferBuilder<O> {
30    /// Create a new builder with space for `capacity + 1` offsets
31    pub fn new(capacity: usize) -> Self {
32        let mut offsets = Vec::with_capacity(capacity + 1);
33        offsets.push(O::usize_as(0));
34        Self {
35            offsets,
36            last_offset: 0,
37        }
38    }
39
40    /// Push a slice of `length` bytes
41    ///
42    /// # Panics
43    ///
44    /// Panics if adding `length` would overflow `usize`
45    #[inline]
46    pub fn push_length(&mut self, length: usize) {
47        self.last_offset = self.last_offset.checked_add(length).expect("overflow");
48        self.offsets.push(O::usize_as(self.last_offset))
49    }
50
51    /// Reserve space for at least `additional` further offsets
52    #[inline]
53    pub fn reserve(&mut self, additional: usize) {
54        self.offsets.reserve(additional);
55    }
56
57    /// Takes the builder itself and returns an [`OffsetBuffer`]
58    ///
59    /// # Panics
60    ///
61    /// Panics if offsets overflow `O`
62    pub fn finish(self) -> OffsetBuffer<O> {
63        O::from_usize(self.last_offset).expect("overflow");
64        unsafe { OffsetBuffer::new_unchecked(self.offsets.into()) }
65    }
66
67    /// Builds the [OffsetBuffer] without resetting the builder.
68    ///
69    /// # Panics
70    ///
71    /// Panics if offsets overflow `O`
72    pub fn finish_cloned(&self) -> OffsetBuffer<O> {
73        let cloned = Self {
74            offsets: self.offsets.clone(),
75            last_offset: self.last_offset,
76        };
77        cloned.finish()
78    }
79}
80
81impl<O: ArrowNativeType> Deref for OffsetBufferBuilder<O> {
82    type Target = [O];
83
84    fn deref(&self) -> &Self::Target {
85        self.offsets.as_ref()
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use crate::OffsetBufferBuilder;
92
93    #[test]
94    fn test_basic() {
95        let mut builder = OffsetBufferBuilder::<i32>::new(5);
96        assert_eq!(builder.len(), 1);
97        assert_eq!(&*builder, &[0]);
98        let finished = builder.finish_cloned();
99        assert_eq!(finished.len(), 1);
100        assert_eq!(&*finished, &[0]);
101
102        builder.push_length(2);
103        builder.push_length(6);
104        builder.push_length(0);
105        builder.push_length(13);
106
107        let finished = builder.finish();
108        assert_eq!(&*finished, &[0, 2, 8, 8, 21]);
109    }
110
111    #[test]
112    #[should_panic(expected = "overflow")]
113    fn test_usize_overflow() {
114        let mut builder = OffsetBufferBuilder::<i32>::new(5);
115        builder.push_length(1);
116        builder.push_length(usize::MAX);
117        builder.finish();
118    }
119
120    #[test]
121    #[should_panic(expected = "overflow")]
122    fn test_i32_overflow() {
123        let mut builder = OffsetBufferBuilder::<i32>::new(5);
124        builder.push_length(1);
125        builder.push_length(i32::MAX as usize);
126        builder.finish();
127    }
128}