-
Notifications
You must be signed in to change notification settings - Fork 172
Feature: Add vortex-vector
#5010
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e43f4c5
eef7c49
87543f7
a94cabd
39d85da
ba7b413
8ce17ce
6a978d3
7c8c719
b7ce53f
9d1415c
65448e5
912cb78
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,9 @@ | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
| // SPDX-FileCopyrightText: Copyright the Vortex contributors | ||
|
|
||
| // TODO(connor): The API of `BitBufferMut` should probably share more methods with `BitBuffer`. | ||
|
|
||
| use arrow_buffer::bit_chunk_iterator::BitChunks; | ||
| use bitvec::view::BitView; | ||
|
|
||
| use crate::bit::{get_bit_unchecked, set_bit_unchecked, unset_bit_unchecked}; | ||
|
|
@@ -25,12 +28,26 @@ use crate::{BitBuffer, BufferMut, ByteBufferMut, buffer_mut}; | |
| /// ``` | ||
| /// | ||
| /// See also: [`BitBuffer`]. | ||
| #[derive(Debug, Clone, Eq)] | ||
| pub struct BitBufferMut { | ||
| buffer: ByteBufferMut, | ||
| offset: usize, | ||
| len: usize, | ||
| } | ||
|
|
||
| impl PartialEq for BitBufferMut { | ||
| fn eq(&self, other: &Self) -> bool { | ||
| if self.len != other.len { | ||
| return false; | ||
| } | ||
|
|
||
| self.chunks() | ||
| .iter_padded() | ||
| .zip(other.chunks().iter_padded()) | ||
| .all(|(a, b)| a == b) | ||
| } | ||
| } | ||
|
|
||
| impl BitBufferMut { | ||
| /// Create new bit buffer from given byte buffer and logical bit length | ||
| pub fn from_buffer(buffer: ByteBufferMut, offset: usize, len: usize) -> Self { | ||
|
|
@@ -118,6 +135,13 @@ impl BitBufferMut { | |
| unsafe { get_bit_unchecked(self.buffer.as_ptr(), self.offset + index) } | ||
| } | ||
|
|
||
| /// Access chunks of the underlying buffer as 8 byte chunks with a final trailer | ||
| /// | ||
| /// If you're performing operations on a single buffer, prefer [BitBuffer::unaligned_chunks] | ||
| pub fn chunks(&self) -> BitChunks<'_> { | ||
| BitChunks::new(self.buffer.as_slice(), self.offset, self.len) | ||
| } | ||
|
|
||
| /// Get the bit capacity of the buffer. | ||
| #[inline(always)] | ||
| pub fn capacity(&self) -> usize { | ||
|
|
@@ -362,6 +386,63 @@ impl BitBufferMut { | |
| self.len += bit_len; | ||
| } | ||
|
|
||
| /// Splits the bit buffer into two at the given index. | ||
| /// | ||
| /// Afterward, self contains elements `[0, at)`, and the returned buffer contains elements | ||
| /// `[at, capacity)`. | ||
| /// | ||
| /// Unlike bytes, if the split position is not on a byte-boundary this operation will copy | ||
| /// data into the result type, and mutate self. | ||
| pub fn split_off(&mut self, at: usize) -> Self { | ||
| assert!(at <= self.len, "index {at} exceeds len {}", self.len); | ||
|
|
||
| let new_offset = self.offset; | ||
| let new_len = self.len - at; | ||
|
|
||
| // If we are splitting on a byte boundary, we can just slice the buffer | ||
| if (self.offset + at) % 8 == 0 { | ||
| let byte_pos = (self.offset + at) / 8; | ||
| let new_buffer = self.buffer.split_off(byte_pos); | ||
| self.len = at; | ||
| return Self { | ||
| buffer: new_buffer, | ||
| offset: new_offset, | ||
| len: new_len, | ||
| }; | ||
| } | ||
|
|
||
| // Otherwise, we need to copy bits into a new buffer | ||
| let mut new_buffer = BitBufferMut::with_capacity(new_len); | ||
| for i in 0..new_len { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we slice and build the other one from iter?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure that would be cleaner? To be honest I didn't actually look through any of this code
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's not about cleaner, the performance of this won't be great |
||
| let value = self.value(at + i); | ||
| new_buffer.append(value); | ||
| } | ||
|
|
||
| // Truncate self to the split position | ||
| self.truncate(at); | ||
|
|
||
| new_buffer | ||
| } | ||
|
|
||
| /// Absorbs a mutable buffer that was previously split off. | ||
| /// | ||
| /// If the two buffers were previously contiguous and not mutated in a way that causes | ||
| /// re-allocation i.e., if other was created by calling split_off on this buffer, then this is | ||
| /// an O(1) operation that just decreases a reference count and sets a few indices. | ||
| /// | ||
| /// Otherwise, this method degenerates to self.append_buffer(&other). | ||
| pub fn unsplit(&mut self, other: Self) { | ||
| if (self.offset + self.len) % 8 == 0 && other.offset == 0 { | ||
| // We are aligned and can just append the buffers | ||
| self.buffer.unsplit(other.buffer); | ||
| self.len += other.len; | ||
| return; | ||
| } | ||
|
|
||
| // Otherwise, we need to append the bits one by one | ||
| self.append_buffer(&other.freeze()) | ||
| } | ||
|
|
||
| /// Freeze the buffer in its current state into an immutable `BoolBuffer`. | ||
| pub fn freeze(self) -> BitBuffer { | ||
| BitBuffer::new_with_offset(self.buffer.freeze(), self.len, self.offset) | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.