Skip to content

Commit 8ac2f3e

Browse files
authored
Merge pull request #9 from fjall-rs/perf/size-unchecked
perf: rearrange with_size_unchecked
2 parents e1f096d + d4b61a7 commit 8ac2f3e

File tree

1 file changed

+82
-52
lines changed

1 file changed

+82
-52
lines changed

src/byteview.rs

Lines changed: 82 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ impl ByteView {
235235
}
236236
}
237237

238-
/// Returns a mutable reference into the given Byteview, if there are no other pointers to the same allocation.
238+
/// Returns a mutable reference into the given byteview, if there are no other pointers to the same allocation.
239239
pub fn get_mut(&mut self) -> Option<Mutator<'_>> {
240240
if self.ref_count() == 1 {
241241
Some(Mutator(self))
@@ -244,7 +244,7 @@ impl ByteView {
244244
}
245245
}
246246

247-
/// Creates a slice and populates it with `len` bytes
247+
/// Creates a byteview and populates it with `len` bytes
248248
/// from the given reader.
249249
///
250250
/// # Errors
@@ -274,98 +274,128 @@ impl ByteView {
274274
Self::with_size_zeroed(slice_len)
275275
}
276276

277+
/// Creates a new zeroed, fixed-length byteview.
278+
///
279+
/// # Panics
280+
///
281+
/// Panics if the length does not fit in a u32 (4 GiB).
277282
fn with_size_zeroed(slice_len: usize) -> Self {
278-
let Ok(len) = u32::try_from(slice_len) else {
279-
panic!("byte slice too long");
280-
};
281-
282-
let mut builder = Self {
283-
trailer: Trailer {
284-
short: ManuallyDrop::new(ShortRepr {
285-
len,
286-
data: [0; INLINE_SIZE],
287-
}),
288-
},
289-
};
283+
let view = if slice_len <= INLINE_SIZE {
284+
Self {
285+
trailer: Trailer {
286+
short: ManuallyDrop::new(ShortRepr {
287+
// SAFETY: We know slice_len is INLINE_SIZE or less, so it must be
288+
// a valid u32
289+
#[allow(clippy::cast_possible_truncation)]
290+
len: slice_len as u32,
291+
data: [0; INLINE_SIZE],
292+
}),
293+
},
294+
}
295+
} else {
296+
let Ok(len) = u32::try_from(slice_len) else {
297+
panic!("byte slice too long");
298+
};
290299

291-
if !builder.is_inline() {
292300
unsafe {
293-
let header_size = std::mem::size_of::<HeapAllocationHeader>();
294-
let alignment = std::mem::align_of::<HeapAllocationHeader>();
295-
let total_size = header_size + slice_len;
296-
let layout = std::alloc::Layout::from_size_align(total_size, alignment).unwrap();
301+
const HEADER_SIZE: usize = std::mem::size_of::<HeapAllocationHeader>();
302+
const ALIGNMENT: usize = std::mem::align_of::<HeapAllocationHeader>();
303+
304+
let total_size = HEADER_SIZE + slice_len;
305+
let layout = std::alloc::Layout::from_size_align(total_size, ALIGNMENT).unwrap();
297306

298307
// IMPORTANT: Zero-allocate the region
299308
let heap_ptr = std::alloc::alloc_zeroed(layout);
300309
if heap_ptr.is_null() {
301310
std::alloc::handle_alloc_error(layout);
302311
}
303312

304-
// Set pointer to heap allocation address
305-
(*builder.trailer.long).heap = heap_ptr;
306-
(*builder.trailer.long).offset = 0;
307-
(*builder.trailer.long).original_len = slice_len as u32;
308-
309313
// Set ref count
310314
let heap_region = heap_ptr as *const HeapAllocationHeader;
311315
let heap_region = &*heap_region;
312316
heap_region.ref_count.store(1, Ordering::Release);
317+
318+
Self {
319+
trailer: Trailer {
320+
long: ManuallyDrop::new(LongRepr {
321+
len,
322+
prefix: [0; PREFIX_SIZE],
323+
heap: heap_ptr,
324+
original_len: len,
325+
offset: 0,
326+
}),
327+
},
328+
}
313329
}
314-
}
330+
};
315331

316-
debug_assert_eq!(1, builder.ref_count());
332+
debug_assert_eq!(1, view.ref_count());
317333

318-
builder
334+
view
319335
}
320336

337+
/// Creates a new fixed-length byteview, with uninitialized contents.
338+
///
339+
/// # Panics
340+
///
341+
/// Panics if the length does not fit in a u32 (4 GiB).
321342
fn with_size_unchecked(slice_len: usize) -> Self {
322-
let Ok(len) = u32::try_from(slice_len) else {
323-
panic!("byte slice too long");
324-
};
325-
326-
let mut builder = Self {
327-
trailer: Trailer {
328-
short: ManuallyDrop::new(ShortRepr {
329-
len,
330-
data: [0; INLINE_SIZE],
331-
}),
332-
},
333-
};
343+
let view = if slice_len <= INLINE_SIZE {
344+
Self {
345+
trailer: Trailer {
346+
short: ManuallyDrop::new(ShortRepr {
347+
// SAFETY: We know slice_len is INLINE_SIZE or less, so it must be
348+
// a valid u32
349+
#[allow(clippy::cast_possible_truncation)]
350+
len: slice_len as u32,
351+
data: [0; INLINE_SIZE],
352+
}),
353+
},
354+
}
355+
} else {
356+
let Ok(len) = u32::try_from(slice_len) else {
357+
panic!("byte slice too long");
358+
};
334359

335-
if !builder.is_inline() {
336360
unsafe {
337361
const HEADER_SIZE: usize = std::mem::size_of::<HeapAllocationHeader>();
338362
const ALIGNMENT: usize = std::mem::align_of::<HeapAllocationHeader>();
339363

340364
let total_size = HEADER_SIZE + slice_len;
341365
let layout = std::alloc::Layout::from_size_align(total_size, ALIGNMENT).unwrap();
342366

343-
// IMPORTANT: Zero-allocate the region
344367
let heap_ptr = std::alloc::alloc(layout);
345368
if heap_ptr.is_null() {
346369
std::alloc::handle_alloc_error(layout);
347370
}
348371

349-
// Set pointer to heap allocation address
350-
(*builder.trailer.long).heap = heap_ptr;
351-
(*builder.trailer.long).offset = 0;
352-
(*builder.trailer.long).original_len = slice_len as u32;
353-
354372
// Set ref count
355373
let heap_region = heap_ptr as *const HeapAllocationHeader;
356374
let heap_region = &*heap_region;
357375
heap_region.ref_count.store(1, Ordering::Release);
376+
377+
Self {
378+
trailer: Trailer {
379+
long: ManuallyDrop::new(LongRepr {
380+
len,
381+
prefix: [0; PREFIX_SIZE],
382+
heap: heap_ptr,
383+
original_len: len,
384+
offset: 0,
385+
}),
386+
},
387+
}
358388
}
359-
}
389+
};
360390

361-
debug_assert_eq!(1, builder.ref_count());
391+
debug_assert_eq!(1, view.ref_count());
362392

363-
builder
393+
view
364394
}
365395

366-
/// Creates a new slice from an existing byte slice.
396+
/// Creates a new byteview from an existing byte slice.
367397
///
368-
/// Will heap-allocate the slice if it has at least length 13.
398+
/// Will heap-allocate the slice if it has at least length 21.
369399
///
370400
/// # Panics
371401
///
@@ -455,7 +485,7 @@ impl ByteView {
455485
Self::new(self)
456486
}
457487

458-
/// Clones the given range of the existing slice without heap allocation.
488+
/// Clones the given range of the existing byteview without heap allocation.
459489
///
460490
/// # Examples
461491
///

0 commit comments

Comments
 (0)