Skip to content

Commit 2b51221

Browse files
committed
Maximize code reuse in constructors
1 parent 44a37f3 commit 2b51221

File tree

1 file changed

+41
-45
lines changed

1 file changed

+41
-45
lines changed

src/lib.rs

Lines changed: 41 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -114,26 +114,16 @@ impl<T: ?Sized> AlignedBox<T> {
114114
}
115115

116116
impl<T> AlignedBox<T> {
117-
/// Store `value` of type `T` on the heap, making sure that it is aligned to a multiple of
118-
/// `alignment`. It is also checked if `alignment` is a valid alignment for type `T` or
119-
/// increased to a valid alignment otherwise.
120-
///
121-
/// # Example
122-
/// Place value 17 of type `i32` on the heap, aligned to 64 bytes:
123-
/// ```
124-
/// use aligned_box::AlignedBox;
125-
///
126-
/// let b = AlignedBox::<i32>::new(64, 17);
127-
/// ```
128-
pub fn new(
117+
fn allocate(
129118
mut alignment: usize,
130-
value: T,
131-
) -> std::result::Result<AlignedBox<T>, std::boxed::Box<dyn std::error::Error>> {
119+
nelems: usize,
120+
) -> std::result::Result<(*mut T, std::alloc::Layout), std::boxed::Box<dyn std::error::Error>>
121+
{
132122
if alignment < std::mem::align_of::<T>() {
133123
alignment = std::mem::align_of::<T>();
134124
}
135125

136-
let memsize: usize = std::mem::size_of::<T>();
126+
let memsize: usize = std::mem::size_of::<T>() * nelems;
137127
if memsize == 0 {
138128
return Err(AlignedBoxError::ZeroAlloc.into());
139129
}
@@ -146,48 +136,25 @@ impl<T> AlignedBox<T> {
146136
return Err(AlignedBoxError::OutOfMemory.into());
147137
}
148138

149-
// SAFETY: The pointer is non-null, refers to properly sized and aligned memory and it is
150-
// consumed such that it cannot be used from anywhere outside the Box.
151-
let mut b = unsafe { AlignedBox::<T>::from_raw_parts(ptr, layout) };
152-
153-
// *b is not a valid instance of T but uninitialized memory. We have to write to it without
154-
// dropping the old (invalid) value. Also the original value must not be dropped.
155-
// SAFETY: Both value and *b point to valid and properly aligned memory.
156-
unsafe { std::ptr::write(&mut *b, value) };
157-
158-
Ok(b)
139+
Ok((ptr, layout))
159140
}
160141

161142
fn new_uninitialized_sliced(
162-
mut alignment: usize,
143+
alignment: usize,
163144
nelems: usize,
164145
) -> std::result::Result<AlignedBox<[T]>, std::boxed::Box<dyn std::error::Error>> {
165-
if alignment < std::mem::align_of::<T>() {
166-
alignment = std::mem::align_of::<T>();
167-
}
168-
169146
// Make sure the requested amount of Ts will fit into a slice.
170147
let maxelems = (isize::MAX as usize) / std::mem::size_of::<T>();
171148
if nelems > maxelems {
172149
return Err(AlignedBoxError::TooManyElements.into());
173150
}
174151

175-
let memsize: usize = std::mem::size_of::<T>() * nelems;
176-
if memsize == 0 {
177-
return Err(AlignedBoxError::ZeroAlloc.into());
178-
}
179-
180-
let layout = std::alloc::Layout::from_size_align(memsize, alignment)?;
152+
let (ptr, layout) = AlignedBox::<T>::allocate(alignment, nelems)?;
181153

182-
// SAFETY: Requirements on layout are enforced by using from_size_align().
183-
let ptr = unsafe { std::alloc::alloc(layout) as *mut T };
184-
if ptr.is_null() {
185-
return Err(AlignedBoxError::OutOfMemory.into());
186-
}
187-
188-
// SAFETY: Requirements on ptr and nelems have been verified: ptr is non-null, nelems does
189-
// not exceed the maximum size. The referenced memory is not accessed as long as slice
190-
// exists.
154+
// SAFETY: Requirements on ptr and nelems have been verified here and by
155+
// AlignedBox::alocate():
156+
// ptr is non-null, nelems does not exceed the maximum size.
157+
// The referenced memory is not accessed as long as slice exists.
191158
let slice = unsafe { std::slice::from_raw_parts_mut(ptr, nelems) };
192159

193160
// SAFETY: We only create a single Box from the given slice. The slice itself is consumed
@@ -196,6 +163,35 @@ impl<T> AlignedBox<T> {
196163

197164
Ok(b)
198165
}
166+
167+
/// Store `value` of type `T` on the heap, making sure that it is aligned to a multiple of
168+
/// `alignment`. It is also checked if `alignment` is a valid alignment for type `T` or
169+
/// increased to a valid alignment otherwise.
170+
///
171+
/// # Example
172+
/// Place value 17 of type `i32` on the heap, aligned to 64 bytes:
173+
/// ```
174+
/// use aligned_box::AlignedBox;
175+
///
176+
/// let b = AlignedBox::<i32>::new(64, 17);
177+
/// ```
178+
pub fn new(
179+
alignment: usize,
180+
value: T,
181+
) -> std::result::Result<AlignedBox<T>, std::boxed::Box<dyn std::error::Error>> {
182+
let (ptr, layout) = AlignedBox::<T>::allocate(alignment, 1)?;
183+
184+
// SAFETY: The pointer is non-null, refers to properly sized and aligned memory and it is
185+
// consumed such that it cannot be used from anywhere outside the Box.
186+
let mut b = unsafe { AlignedBox::<T>::from_raw_parts(ptr, layout) };
187+
188+
// *b is not a valid instance of T but uninitialized memory. We have to write to it without
189+
// dropping the old (invalid) value. Also the original value must not be dropped.
190+
// SAFETY: Both value and *b point to valid and properly aligned memory.
191+
unsafe { std::ptr::write(&mut *b, value) };
192+
193+
Ok(b)
194+
}
199195
}
200196

201197
impl<T: Default> AlignedBox<[T]> {

0 commit comments

Comments
 (0)