Skip to content

Commit 7115b6e

Browse files
committed
experimental/scene: remove bumpalo dependency
1 parent 7efc7d5 commit 7115b6e

File tree

3 files changed

+107
-12
lines changed

3 files changed

+107
-12
lines changed

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ glam = {version = "0.27", features = ["scalar-math"] }
3333
image = { version = "0.24", default-features = false, features = ["png", "tga"] }
3434
macroquad_macro = { version = "0.1.8", path = "macroquad_macro" }
3535
fontdue = "0.7"
36-
bumpalo = "3.4"
3736
backtrace = { version = "0.3.60", optional = true, default-features = false, features = [ "std", "libbacktrace" ] }
3837
log = { version = "0.4", optional = true }
3938
quad-snd = { version = "0.2", optional = true }

src/experimental/scene.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ use crate::camera::Camera2D;
44

55
pub use macroquad_macro::CapabilityTrait;
66

7+
mod arena;
8+
79
#[rustfmt::skip]
810
pub trait Node {
911
fn ready(_node: RefMut<Self>) where Self: Sized {}
@@ -12,10 +14,6 @@ pub trait Node {
1214
fn draw(_node: RefMut<Self>) where Self: Sized {}
1315
}
1416

15-
trait NodeTyped<T> {
16-
fn self_node(&self) -> &T;
17-
}
18-
1917
trait NodeAny: Any + Node {
2018
fn as_any(&self) -> &dyn Any;
2119
fn as_any_mut(&mut self) -> &mut dyn Any;
@@ -345,7 +343,7 @@ struct Scene {
345343
dense: Vec<Id>,
346344
dense_ongoing: Vec<Result<Id, Id>>,
347345
nodes: Vec<Option<Cell>>,
348-
arena: bumpalo::Bump,
346+
arena: arena::Arena,
349347
camera: [Option<Camera2D>; 4],
350348
camera_pos: crate::Vec2,
351349

@@ -363,7 +361,7 @@ impl Scene {
363361
dense: vec![],
364362
dense_ongoing: vec![],
365363
nodes: Vec::new(),
366-
arena: bumpalo::Bump::new(),
364+
arena: arena::Arena::new(),
367365
free_nodes: Vec::new(),
368366
camera: [Some(Camera2D::default()), None, None, None],
369367
camera_pos: crate::vec2(0., 0.),
@@ -461,15 +459,22 @@ impl Scene {
461459
let trait_obj = &data as &dyn NodeAny;
462460
let (_, vtable) = unsafe { std::mem::transmute::<_, (*mut (), *mut ())>(trait_obj) };
463461

464-
let data = self.arena.alloc(data) as *mut _ as *mut _;
465-
let used = self.arena.alloc(false) as *mut _ as *mut _;
462+
let ptr = self.arena.alloc(std::mem::size_of::<T>()) as *mut _ as *mut T;
463+
unsafe {
464+
std::ptr::write(ptr, data);
465+
}
466+
let ptr = ptr as *mut ();
467+
let used = self.arena.alloc(1) as *mut _ as *mut bool;
468+
unsafe {
469+
std::ptr::write(used, false);
470+
}
471+
let used = used as *mut _ as *mut bool;
466472

467473
id = Id {
468474
id: self.nodes.len(),
469475
generation: 0,
470476
};
471-
self.nodes
472-
.push(Some(Cell::new::<T>(id, data, vtable, used)));
477+
self.nodes.push(Some(Cell::new::<T>(id, ptr, vtable, used)));
473478
}
474479

475480
self.dense.push(id);
@@ -616,7 +621,7 @@ unsafe fn get_scene() -> &'static mut Scene {
616621
}
617622

618623
pub(crate) fn allocated_memory() -> usize {
619-
unsafe { get_scene() }.arena.allocated_bytes()
624+
unsafe { get_scene().arena.offset() }
620625
}
621626

622627
pub fn clear() {

src/experimental/scene/arena.rs

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
//! Gleaned from https://github.com/ratel-rust/toolshed/blob/master/src/arena.rs
2+
//! and than modified a lot.
3+
//!
4+
//! Module containing the `Arena` and `Uninitialized` structs. For convenience the
5+
//! `Arena` is exported at the root of the crate.
6+
7+
use std::cell::Cell;
8+
use std::mem::size_of;
9+
10+
const ARENA_BLOCK: usize = 64 * 1024;
11+
12+
/// An arena implementation that uses preallocated 64KiB pages for all allocations.
13+
/// If a new allocation were to be pushed over the the boundaries of the page, a
14+
/// new page is internally allocated first, thus this version of the arena can never
15+
/// run out of memory unless the process runs out of heap altogether.
16+
///
17+
/// Allocating a type larger than the page size will result in a new heap allocation
18+
/// just for that type separate from the page mechanism.
19+
pub struct Arena {
20+
store: Cell<Vec<Vec<u8>>>,
21+
ptr: Cell<*mut u8>,
22+
offset: Cell<usize>,
23+
}
24+
25+
impl Arena {
26+
/// Create a new arena with a single preallocated 64KiB page.
27+
pub fn new() -> Self {
28+
let mut store = vec![Vec::with_capacity(ARENA_BLOCK)];
29+
let ptr = store[0].as_mut_ptr();
30+
31+
Arena {
32+
store: Cell::new(store),
33+
ptr: Cell::new(ptr),
34+
offset: Cell::new(0),
35+
}
36+
}
37+
38+
pub fn alloc(&self, size: usize) -> *mut u8 {
39+
// This should be optimized away for size known at compile time.
40+
if size > ARENA_BLOCK {
41+
return self.alloc_bytes(size);
42+
}
43+
44+
let size = match size % size_of::<usize>() {
45+
0 => size,
46+
n => size + (size_of::<usize>() - n),
47+
};
48+
49+
let offset = self.offset.get();
50+
let cap = offset + size;
51+
52+
if cap > ARENA_BLOCK {
53+
self.grow();
54+
55+
self.offset.set(size);
56+
self.ptr.get()
57+
} else {
58+
self.offset.set(cap);
59+
unsafe { self.ptr.get().add(offset) }
60+
}
61+
}
62+
63+
#[inline]
64+
fn alloc_byte_vec(&self, mut val: Vec<u8>) -> *mut u8 {
65+
let ptr = val.as_mut_ptr();
66+
67+
let mut temp = self.store.replace(Vec::new());
68+
temp.push(val);
69+
self.store.replace(temp);
70+
71+
ptr
72+
}
73+
74+
pub fn grow(&self) {
75+
let ptr = self.alloc_byte_vec(Vec::with_capacity(ARENA_BLOCK));
76+
self.ptr.set(ptr);
77+
}
78+
79+
fn alloc_bytes(&self, size: usize) -> *mut u8 {
80+
self.alloc_byte_vec(Vec::with_capacity(size))
81+
}
82+
83+
#[doc(hidden)]
84+
#[inline]
85+
pub unsafe fn offset(&self) -> usize {
86+
self.offset.get()
87+
}
88+
}
89+
90+
/// Akin to `CopyCell`: `Sync` is unsafe but `Send` is totally fine!
91+
unsafe impl Send for Arena {}

0 commit comments

Comments
 (0)