1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use std::{
alloc::{alloc, dealloc, Layout},
cell::RefCell,
};
pub mod array;
pub use array::Array;
pub mod linked_list;
pub use linked_list::List;
const fn align_to(ptr: usize, align: usize) -> usize {
(ptr + align - 1) & !(align - 1)
}
struct RawMemory {
capacity: usize,
memory: usize,
next: usize,
}
impl RawMemory {
fn with_capacity(capacity: usize) -> Result<Self, String> {
unsafe {
let mem = {
let layout = Layout::array::<u8>(capacity).map_err(|e| e.to_string())?;
alloc(layout)
};
if mem.is_null() {
return Err("Memory allocation failed for the arena.".to_string());
}
Ok(Self {
capacity,
memory: mem as usize,
next: mem as usize,
})
}
}
const fn end(&self) -> usize {
self.memory + self.capacity
}
fn reset(&mut self) {
self.next = self.memory
}
}
impl Drop for RawMemory {
fn drop(&mut self) {
unsafe {
if let Ok(layout) = Layout::array::<u8>(self.capacity) {
dealloc(self.memory as *mut u8, layout)
}
}
}
}
/// A temporary memory arena.
pub struct TempArena {
memory: RefCell<RawMemory>,
}
impl TempArena {
/// Creates a temporary memory arena with a given capacity, returning an error if it is unable
/// to allocate the full amount of memory.
///
/// # Example
/// ```
///# use ngen::arena::TempArena;
/// let arena = TempArena::with_capacity(1024).unwrap();
/// ```
pub fn with_capacity(capacity: usize) -> Result<Self, String> {
let memory = RawMemory::with_capacity(capacity)?;
Ok(Self {
memory: RefCell::new(memory),
})
}
/// Returns the total amount of memory used since the last reset.
///
/// # Example
/// ```
///# use ngen::arena::TempArena;
/// let mut arena = TempArena::with_capacity(1024).unwrap();
/// arena.push(4.0f32);
/// assert_eq!(arena.len(), std::mem::size_of::<f32>());
/// ```
pub fn len(&self) -> usize {
let memory = self.memory.borrow();
memory.next - memory.memory
}
/// Pushes a default value for a given `T` into the temp arena, using the correct alignment for the pushed value.
///
/// # Example
/// ```
///# use ngen::arena::TempArena;
/// let mut arena = TempArena::with_capacity(1024).unwrap();
/// let forty_two = arena.push_default::<i32>();
/// assert_eq!(forty_two, &0);
/// ```
pub fn push_default<'a, T: Default>(&'a self) -> &'a mut T {
self.push(T::default())
}
/// Pushes a new value into the temp arena, using the correct alignment for the pushed value.
///
/// # Example
/// ```
///# use ngen::arena::TempArena;
/// let mut arena = TempArena::with_capacity(1024).unwrap();
/// let forty_two = arena.push(42);
/// assert_eq!(forty_two, &42);
/// ```
pub fn push<'a, T>(&'a self, default: T) -> &'a mut T {
let mut memory = self.memory.borrow_mut();
unsafe {
let layout = Layout::new::<T>();
let start = align_to(memory.next, layout.align());
let end = start + layout.size();
if end > memory.end() {
panic!("Out of memory.");
}
memory.next = end;
let ptr = start as *mut T;
ptr.write(default);
&mut *ptr
}
}
/// Resets the current memory arena, pointing the current location to the start of the
/// allocated memory.
///
/// # Example
/// ```
///# use ngen::arena::TempArena;
/// let mut arena = TempArena::with_capacity(1024).unwrap();
///
/// // Push some items into the arena.
/// for i in 0..42 {
/// arena.push(i);
/// }
///
/// assert_eq!(arena.len(), std::mem::size_of::<i32>() * 42);
/// arena.reset();
/// assert_eq!(arena.len(), 0);
/// ```
pub fn reset(&mut self) {
self.memory.borrow_mut().reset()
}
/// Returns exclusive access to the memory arena to create a contiguous, and growable, array of
/// items.
///
/// # Example
/// ```
///# use ngen::arena::TempArena;
/// let mut arena = TempArena::with_capacity(1024).unwrap();
///
/// let mut array = arena.array();
/// array.push(42);
/// ```
pub fn array<T>(&mut self) -> Array<'_, T> {
Array::new(self)
}
// pub fn list<T>(&self) -> List<'_, T> {
// List::new()
// }
}