Skip to content

Commit bec29e5

Browse files
committed
Switch from 'typed-arena' to 'bumpalo'
Add a 'as_bumpalo' method to get the underlying bump allocator. Bump version to 0.1.5
1 parent 7378afa commit bec29e5

File tree

2 files changed

+52
-19
lines changed

2 files changed

+52
-19
lines changed

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "dynamic-arena"
3-
version = "0.1.4"
3+
version = "0.1.5"
44
authors = ["Techcable <Techcable@techcable.net>"]
55
description = "Dynamically typed arenas, supporting any `Sized` type."
66
license = "MIT"
@@ -9,7 +9,7 @@ repository = "https://github.com/Techcable/rust-dynamic-arena"
99
edition = "2018"
1010

1111
[dependencies]
12-
typed-arena = "^2"
12+
bumpalo = "3"
1313

1414
[dev-dependencies]
1515
compiletest_rs = "^0.5"

src/lib.rs

Lines changed: 50 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,17 @@
11
//! Implements dynamically typed arenas, where any type of item can be allocated.
2-
extern crate typed_arena;
3-
2+
#![deny(missing_docs)]
43
use std::marker::PhantomData;
54
use std::cell::RefCell;
65
use std::os::raw::c_void;
7-
use std::{mem, ptr};
6+
use std::mem;
7+
use std::ptr::{self, NonNull};
8+
use std::alloc::Layout;
89

9-
use typed_arena::Arena;
10+
use bumpalo::Bump;
1011

1112
/// Marker trait that indicates whether or a `DynamicArena` may be sent across threads
1213
pub trait SendAbility: Sized {
14+
/// Create an arena corresponding to this type of thread-safety
1315
fn create_arena<'a>() -> DynamicArena<'a, Self>;
1416
}
1517
/// Marker type that indicates you expect everything in the `DynamicArena` to be `Send`
@@ -102,7 +104,7 @@ pub type DynamicSendArena<'a> = DynamicArena<'a, Sendable>;
102104
/// before they proceed to allocate the copyable struct.
103105
pub struct DynamicArena<'a, S = NonSend> {
104106
/// The underlying arena, where we request that they allocate arbitrary bytes.
105-
handle: Arena<u8>,
107+
handle: Bump,
106108
/// The list of untyped values we've allocated in the arena,
107109
/// and whose drop functions need to be invoked.
108110
///
@@ -130,10 +132,15 @@ impl DynamicArena<'static, NonSend> {
130132
DynamicArena::new_bounded()
131133
}
132134
}
133-
impl<'a, S> DynamicArena<'a, S> {
135+
impl<'a, S> DynamicArena<'a, S> {
136+
/// Create an arena with pre-allocated capacity for the specified number of items
137+
/// and bytes.
138+
///
139+
/// NOTE: The "item" capacity excludes `Copy` references that
140+
/// don't need to be dropped.
134141
pub fn with_capacity(item_capacity: usize, byte_capacity: usize) -> Self {
135142
DynamicArena {
136-
handle: Arena::with_capacity(byte_capacity),
143+
handle: Bump::with_capacity(byte_capacity),
137144
items: RefCell::new(Vec::with_capacity(item_capacity)),
138145
marker: PhantomData,
139146
send: PhantomData
@@ -145,28 +152,47 @@ impl<'a, S> DynamicArena<'a, S> {
145152
/// The bound on the item requires that `T: Copy`
146153
/// to ensure there's no drop function that needs to be invoked.
147154
#[inline]
155+
#[allow(clippy::mut_from_ref)]
148156
pub fn alloc_copy<T: Copy + Send>(&self, value: T) -> &mut T {
149157
unsafe {
150158
self.alloc_unchecked(value)
151159
}
152160
}
153161
/// Allocate the specified value in this arena,
154-
/// without ensuring that its drop function would be safe to invoke.
162+
/// without calling its `Drop` function.
163+
///
164+
/// Since this doesn't call the 'Drop' impleentation,
165+
/// this function leaks the underlying memory.
155166
///
156-
/// Additionally this function leaks the underlying memory,
157-
/// and never runs the destructor, so its ownership needs to be tracked seperately.
167+
/// ## Safety
168+
/// Technically, this function is safe to use.
169+
/// However, it leaks memory unconditionally (without calling Drop).
158170
#[inline]
171+
#[allow(clippy::mut_from_ref)]
159172
pub unsafe fn alloc_unchecked<T>(&self, value: T) -> &mut T {
160-
let ptr = (*self.handle.alloc_uninitialized(mem::size_of::<T>())).as_ptr() as *mut T;
161-
ptr::write(ptr, value);
173+
let ptr = self.alloc_layout(Layout::new::<T>()).as_ptr().cast::<T>();
174+
ptr.write(value);
162175
&mut *ptr
163176
}
177+
/// Allocate space for an object with the specified layout
178+
///
179+
/// The returned pointer points at uninitialized memory
180+
///
181+
/// ## Safety
182+
/// Technically, only the use of the memory is unsafe.
183+
///
184+
/// It would theoretically be possible to mark this function safe,
185+
/// just like [Bump::alloc_layout].
186+
#[inline]
187+
pub unsafe fn alloc_layout(&self, layout: Layout) -> NonNull<u8> {
188+
self.handle.alloc_layout(layout)
189+
}
164190
/// Dynamically drop the specified value,
165191
/// invoking the drop function when the arena is dropped.
166192
///
167-
/// This is unsafe because the drop function isn't necessarily safe to invoke,
168-
/// and the memory isn't nessicarrily .
169-
/// Not only are you assuming that `ptr::drop_in_place` would be safe,
193+
/// ## Safety
194+
/// This assumes it's safe to drop the value at the same time the arena is dropped.
195+
/// Not only are you assuming that [ptr::drop_in_place] would be safe,
170196
/// you're also assuming that the drop function won't reference any dangling pointers,
171197
/// and that [dropchk](https://doc.rust-lang.org/nomicon/dropck.html) would be successful.
172198
///
@@ -183,6 +209,11 @@ impl<'a, S> DynamicArena<'a, S> {
183209
})
184210
}
185211
}
212+
/// Retrieve the underlying [bump allocator](bumpalo::Bump) for this arena
213+
#[inline]
214+
pub fn as_bumpalo(&self) -> &'_ bumpalo::Bump {
215+
&self.handle
216+
}
186217
}
187218
impl<'a> DynamicArena<'a, Sendable> {
188219
/// Create a new empty arena, bounded by the inferred lifetime for this type `'a`
@@ -191,7 +222,7 @@ impl<'a> DynamicArena<'a, Sendable> {
191222
/// all items in the arena need to implement `Send`.
192223
pub fn new_send() -> Self {
193224
DynamicArena {
194-
handle: Arena::new(),
225+
handle: Bump::new(),
195226
items: RefCell::new(Vec::new()),
196227
marker: PhantomData,
197228
send: PhantomData
@@ -205,6 +236,7 @@ impl<'a> DynamicArena<'a, Sendable> {
205236
/// Additionally, since the arena is `Sendable`,
206237
/// the bound on the item also requires that `T: Send`.
207238
#[inline]
239+
#[allow(clippy::mut_from_ref)]
208240
pub fn alloc<T: Send + 'a>(&self, value: T) -> &mut T {
209241
unsafe {
210242
let target = self.alloc_unchecked(value);
@@ -220,7 +252,7 @@ impl<'a> DynamicArena<'a, NonSend> {
220252
/// the items in the arena don't necessarily need to implement `Send`.
221253
pub fn new_bounded() -> Self {
222254
DynamicArena {
223-
handle: Arena::new(),
255+
handle: Bump::new(),
224256
items: RefCell::new(Vec::new()),
225257
marker: PhantomData,
226258
send: PhantomData
@@ -232,6 +264,7 @@ impl<'a> DynamicArena<'a, NonSend> {
232264
/// The bound on this item requires that `T: 'a`
233265
/// to ensure the drop function is safe to invoke.
234266
#[inline]
267+
#[allow(clippy::mut_from_ref)]
235268
pub fn alloc<T: 'a>(&self, value: T) -> &mut T {
236269
unsafe {
237270
let target = self.alloc_unchecked(value);

0 commit comments

Comments
 (0)