Skip to content

Commit 719ac2e

Browse files
committed
perf(buffer): avoid empty data allocations
Signed-off-by: Nicholas Gates <nick@nickgates.com>
1 parent 6331364 commit 719ac2e

2 files changed

Lines changed: 44 additions & 11 deletions

File tree

vortex-buffer/src/allocation.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,4 +441,21 @@ mod tests {
441441
drop(buffer);
442442
assert_eq!(state.deallocations.load(Ordering::Relaxed), 1);
443443
}
444+
445+
#[test]
446+
fn zero_capacity_does_not_allocate() {
447+
let allocator = TrackingAllocator::default();
448+
let state = Arc::clone(&allocator.state);
449+
let mut buffer = BufferAllocatorRef::new(allocator).with_capacity::<u32>(0);
450+
451+
assert_eq!(buffer.capacity(), 0);
452+
assert!(Alignment::DEFAULT_ALIGNMENT.is_offset_aligned(buffer.as_ptr().addr()));
453+
assert_eq!(state.allocations.load(Ordering::Relaxed), 0);
454+
455+
buffer.push(42);
456+
457+
assert_eq!(buffer.as_slice(), [42]);
458+
assert_eq!(state.allocations.load(Ordering::Relaxed), 1);
459+
assert_eq!(state.grows.load(Ordering::Relaxed), 0);
460+
}
444461
}

vortex-buffer/src/buffer_mut.rs

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,17 @@ impl<T> BufferMut<T> {
115115
let size = capacity
116116
.checked_mul(size_of::<T>())
117117
.vortex_expect("buffer capacity overflow");
118-
let allocation_size = size
119-
.checked_add(actual.as_usize())
120-
.vortex_expect("buffer capacity overflow");
121-
let layout = Layout::from_size_align(allocation_size, 1)
122-
.unwrap_or_else(|_| vortex_panic!("buffer capacity exceeds maximum allocation size"));
118+
let layout = if size == 0 {
119+
Layout::from_size_align(0, actual.as_usize())
120+
.unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
121+
} else {
122+
let allocation_size = size
123+
.checked_add(actual.as_usize())
124+
.vortex_expect("buffer capacity overflow");
125+
Layout::from_size_align(allocation_size, 1).unwrap_or_else(|_| {
126+
vortex_panic!("buffer capacity exceeds maximum allocation size")
127+
})
128+
};
123129
let allocation = Allocation::allocate(layout, allocator);
124130
let offset = allocation.ptr().as_ptr().align_offset(actual.as_usize());
125131
Self {
@@ -195,11 +201,16 @@ impl<T> BufferMut<T> {
195201
let size = len
196202
.checked_mul(size_of::<T>())
197203
.vortex_expect("buffer length overflow");
198-
let allocation_size = size
199-
.checked_add(actual_alignment.as_usize())
200-
.vortex_expect("buffer length overflow");
201-
let layout = Layout::from_size_align(allocation_size, 1)
202-
.unwrap_or_else(|_| vortex_panic!("buffer length exceeds maximum allocation size"));
204+
let layout = if size == 0 {
205+
Layout::from_size_align(0, actual_alignment.as_usize())
206+
.unwrap_or_else(|_| vortex_panic!("invalid empty buffer alignment"))
207+
} else {
208+
let allocation_size = size
209+
.checked_add(actual_alignment.as_usize())
210+
.vortex_expect("buffer length overflow");
211+
Layout::from_size_align(allocation_size, 1)
212+
.unwrap_or_else(|_| vortex_panic!("buffer length exceeds maximum allocation size"))
213+
};
203214
let allocation = Allocation::allocate_zeroed(layout, allocator);
204215
let offset = allocation
205216
.ptr()
@@ -455,7 +466,12 @@ impl<T> BufferMut<T> {
455466
.vortex_expect("buffer capacity overflow");
456467
let current_size = self.allocation.size() - self.offset;
457468
let allocation_size = required_size.max(current_size.saturating_mul(2));
458-
let layout = Layout::from_size_align(allocation_size, self.allocation.alignment())
469+
let allocation_alignment = if self.allocation.size() == 0 {
470+
1
471+
} else {
472+
self.allocation.alignment()
473+
};
474+
let layout = Layout::from_size_align(allocation_size, allocation_alignment)
459475
.unwrap_or_else(|_| vortex_panic!("buffer capacity exceeds maximum allocation size"));
460476

461477
let old_offset = self.offset;

0 commit comments

Comments
 (0)