1use std::cell::RefCell;
7use std::collections::VecDeque;
8use std::mem;
9use indexmap::IndexMap;
10
11pub struct Arena {
13 chunks: RefCell<Vec<Vec<u8>>>,
14 current_chunk: RefCell<usize>,
15 current_offset: RefCell<usize>,
16 chunk_size: usize,
17}
18
19impl Arena {
20 pub fn new(chunk_size: usize) -> Self {
22 Self {
23 chunks: RefCell::new(vec![Vec::with_capacity(chunk_size)]),
24 current_chunk: RefCell::new(0),
25 current_offset: RefCell::new(0),
26 chunk_size,
27 }
28 }
29
30 pub fn alloc<T>(&self, value: T) -> Box<T> {
32 let size = std::mem::size_of::<T>();
35
36 {
37 let mut chunks = self.chunks.borrow_mut();
38 if chunks.is_empty() || chunks.last().unwrap().len() + size > self.chunk_size {
39 chunks.push(Vec::with_capacity(self.chunk_size));
41 *self.current_chunk.borrow_mut() = chunks.len() - 1;
42 *self.current_offset.borrow_mut() = 0;
43 }
44
45 let current_chunk_idx = *self.current_chunk.borrow();
47 if let Some(chunk) = chunks.get_mut(current_chunk_idx) {
48 chunk.resize(chunk.len() + size, 0);
50 *self.current_offset.borrow_mut() += size;
51 }
52 }
53
54 Box::new(value)
55 }
56
57
58 pub fn allocated_bytes(&self) -> usize {
60 self.chunks.borrow().iter()
61 .map(|chunk| chunk.len())
62 .sum()
63 }
64
65 pub fn capacity_bytes(&self) -> usize {
67 self.chunks.borrow().iter()
68 .map(|chunk| chunk.capacity())
69 .sum()
70 }
71
72 pub fn reset(&self) {
74 let mut chunks = self.chunks.borrow_mut();
75 for chunk in chunks.iter_mut() {
76 chunk.clear();
77 }
78 *self.current_chunk.borrow_mut() = 0;
79 *self.current_offset.borrow_mut() = 0;
80 }
81
82 pub fn clear(&self) {
84 self.chunks.borrow_mut().clear();
85 *self.current_chunk.borrow_mut() = 0;
86 *self.current_offset.borrow_mut() = 0;
87 }
88}
89
90pub struct ObjectPool<T> {
92 objects: RefCell<VecDeque<T>>,
93 factory: Box<dyn Fn() -> T>,
94 max_size: usize,
95}
96
97impl<T> ObjectPool<T> {
98 pub fn new<F>(factory: F, max_size: usize) -> Self
100 where
101 F: Fn() -> T + 'static,
102 {
103 Self {
104 objects: RefCell::new(VecDeque::new()),
105 factory: Box::new(factory),
106 max_size,
107 }
108 }
109
110 pub fn get(&self) -> PooledObject<T> {
112 let obj = self.objects.borrow_mut()
113 .pop_front()
114 .unwrap_or_else(|| (self.factory)());
115
116 PooledObject {
117 object: Some(obj),
118 pool: self,
119 }
120 }
121
122 fn return_object(&self, obj: T) {
124 let mut objects = self.objects.borrow_mut();
125 if objects.len() < self.max_size {
126 objects.push_back(obj);
127 }
128 }
130
131 pub fn size(&self) -> usize {
133 self.objects.borrow().len()
134 }
135
136 pub fn clear(&self) {
138 self.objects.borrow_mut().clear();
139 }
140}
141
142pub struct PooledObject<'a, T> {
144 object: Option<T>,
145 pool: &'a ObjectPool<T>,
146}
147
148impl<'a, T> PooledObject<'a, T> {
149 pub fn get_mut(&mut self) -> &mut T {
151 self.object.as_mut().unwrap()
152 }
153
154 pub fn get(&self) -> &T {
156 self.object.as_ref().unwrap()
157 }
158}
159
160impl<'a, T> Drop for PooledObject<'a, T> {
161 fn drop(&mut self) {
162 if let Some(obj) = self.object.take() {
163 self.pool.return_object(obj);
164 }
165 }
166}
167
168#[derive(Debug, Clone)]
170pub struct CompactElement {
171 name_idx: u32,
173 namespace_idx: Option<u32>,
175 attributes: CompactAttributes,
177 children: Vec<CompactNodeRef>,
179}
180
181#[derive(Debug, Clone)]
183pub enum CompactNodeRef {
184 Element(u32), Text(u32), Comment(u32), }
188
189#[derive(Debug, Clone, Default)]
191pub struct CompactAttributes {
192 data: Vec<(u32, u32)>,
194}
195
196impl CompactAttributes {
197 pub fn insert(&mut self, key_idx: u32, value_idx: u32) {
199 self.data.push((key_idx, value_idx));
200 }
201
202 pub fn len(&self) -> usize {
204 self.data.len()
205 }
206
207 pub fn is_empty(&self) -> bool {
209 self.data.is_empty()
210 }
211
212 pub fn iter(&self) -> impl Iterator<Item = (u32, u32)> + '_ {
214 self.data.iter().copied()
215 }
216}
217
218#[derive(Debug)]
220pub struct CompactAST {
221 strings: Vec<String>,
223 string_map: IndexMap<String, u32>,
225 elements: Vec<CompactElement>,
227 root_idx: u32,
229 namespaces: Vec<(u32, u32)>, schema_location_idx: Option<u32>,
233}
234
235impl CompactAST {
236 pub fn new() -> Self {
238 Self {
239 strings: Vec::new(),
240 string_map: IndexMap::new(),
241 elements: Vec::new(),
242 root_idx: 0,
243 namespaces: Vec::new(),
244 schema_location_idx: None,
245 }
246 }
247
248 pub fn intern_string(&mut self, s: &str) -> u32 {
250 if let Some(&idx) = self.string_map.get(s) {
251 return idx;
252 }
253
254 let idx = self.strings.len() as u32;
255 self.strings.push(s.to_string());
256 self.string_map.insert(s.to_string(), idx);
257 idx
258 }
259
260 pub fn get_string(&self, idx: u32) -> Option<&str> {
262 self.strings.get(idx as usize).map(|s| s.as_str())
263 }
264
265 pub fn add_element(&mut self, element: CompactElement) -> u32 {
267 let idx = self.elements.len() as u32;
268 self.elements.push(element);
269 idx
270 }
271
272 pub fn get_element(&self, idx: u32) -> Option<&CompactElement> {
274 self.elements.get(idx as usize)
275 }
276
277 pub fn memory_footprint(&self) -> usize {
279 let strings_size = self.strings.iter()
280 .map(|s| s.len())
281 .sum::<usize>();
282
283 let map_size = self.string_map.len() *
284 (mem::size_of::<String>() + mem::size_of::<u32>());
285
286 let elements_size = self.elements.len() * mem::size_of::<CompactElement>();
287
288 strings_size + map_size + elements_size
289 }
290
291 pub fn from_ast(ast: &crate::ast::AST) -> Self {
293 let mut compact = CompactAST::new();
294
295 for (prefix, uri) in &ast.namespaces {
297 let prefix_idx = compact.intern_string(prefix);
298 let uri_idx = compact.intern_string(uri);
299 compact.namespaces.push((prefix_idx, uri_idx));
300 }
301
302 if let Some(ref location) = ast.schema_location {
304 compact.schema_location_idx = Some(compact.intern_string(location));
305 }
306
307 compact.root_idx = compact.convert_element(&ast.root);
309
310 compact
311 }
312
313 fn convert_element(&mut self, element: &crate::ast::Element) -> u32 {
315 let name_idx = self.intern_string(&element.name);
316 let namespace_idx = element.namespace.as_ref()
317 .map(|ns| self.intern_string(ns));
318
319 let mut attributes = CompactAttributes::default();
321 for (key, value) in &element.attributes {
322 let key_idx = self.intern_string(key);
323 let value_idx = self.intern_string(value);
324 attributes.insert(key_idx, value_idx);
325 }
326
327 let children = Vec::new(); let compact_element = CompactElement {
331 name_idx,
332 namespace_idx,
333 attributes,
334 children,
335 };
336
337 self.add_element(compact_element)
338 }
339}
340
341pub struct LazyField<T> {
343 value: RefCell<Option<T>>,
344 loader: Box<dyn Fn() -> T>,
345}
346
347impl<T: std::fmt::Debug> std::fmt::Debug for LazyField<T> {
348 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
349 f.debug_struct("LazyField")
350 .field("value", &self.value)
351 .field("loader", &"<function>")
352 .finish()
353 }
354}
355
356impl<T> LazyField<T> {
357 pub fn new<F>(loader: F) -> Self
359 where
360 F: Fn() -> T + 'static,
361 {
362 Self {
363 value: RefCell::new(None),
364 loader: Box::new(loader),
365 }
366 }
367
368 pub fn get(&self) -> std::cell::Ref<T> {
370 if self.value.borrow().is_none() {
371 *self.value.borrow_mut() = Some((self.loader)());
372 }
373
374 std::cell::Ref::map(self.value.borrow(), |opt| opt.as_ref().unwrap())
375 }
376
377 pub fn is_loaded(&self) -> bool {
379 self.value.borrow().is_some()
380 }
381
382 pub fn clear(&self) {
384 *self.value.borrow_mut() = None;
385 }
386}
387
388pub struct BuildMemoryManager {
390 pub arena: Arena,
392 pub element_pool: ObjectPool<crate::ast::Element>,
394 pub small_string_pool: ObjectPool<String>,
396 pub buffer_pool: ObjectPool<Vec<u8>>,
398}
399
400impl BuildMemoryManager {
401 pub fn new() -> Self {
403 Self {
404 arena: Arena::new(64 * 1024), element_pool: ObjectPool::new(
406 || crate::ast::Element::new(""),
407 100 ),
409 small_string_pool: ObjectPool::new(
410 || String::with_capacity(64),
411 50 ),
413 buffer_pool: ObjectPool::new(
414 || Vec::with_capacity(8192), 10 ),
417 }
418 }
419
420 pub fn memory_usage(&self) -> MemoryStats {
422 MemoryStats {
423 arena_allocated: self.arena.allocated_bytes(),
424 arena_capacity: self.arena.capacity_bytes(),
425 element_pool_size: self.element_pool.size(),
426 string_pool_size: self.small_string_pool.size(),
427 buffer_pool_size: self.buffer_pool.size(),
428 }
429 }
430
431 pub fn reset_for_next_build(&self) {
433 self.arena.reset();
434 }
436
437 pub fn full_reset(&self) {
439 self.arena.clear();
440 self.element_pool.clear();
441 self.small_string_pool.clear();
442 self.buffer_pool.clear();
443 }
444}
445
446impl Default for BuildMemoryManager {
447 fn default() -> Self {
448 Self::new()
449 }
450}
451
452#[derive(Debug, Clone)]
454pub struct MemoryStats {
455 pub arena_allocated: usize,
456 pub arena_capacity: usize,
457 pub element_pool_size: usize,
458 pub string_pool_size: usize,
459 pub buffer_pool_size: usize,
460}
461
462impl MemoryStats {
463 pub fn total_bytes(&self) -> usize {
465 self.arena_capacity +
466 (self.element_pool_size * mem::size_of::<crate::ast::Element>()) +
467 (self.string_pool_size * 64) + (self.buffer_pool_size * 8192) }
470}
471
472#[cfg(test)]
473mod tests {
474 use super::*;
475
476 #[test]
477 fn test_arena_allocation() {
478 let arena = Arena::new(1024);
479
480 let val1 = arena.alloc(42u32);
481 let val2 = arena.alloc("hello world".to_string());
482
483 assert_eq!(*val1, 42);
484 assert_eq!(*val2, "hello world");
485
486 assert!(arena.allocated_bytes() > 0);
487 }
488
489 #[test]
490 fn test_object_pool() {
491 let pool = ObjectPool::new(|| String::with_capacity(32), 5);
492
493 {
494 let mut obj1 = pool.get();
495 obj1.get_mut().push_str("test");
496 assert_eq!(obj1.get(), "test");
497
498 {
499 let obj2 = pool.get();
500 assert_eq!(pool.size(), 0); }
502 }
504 assert_eq!(pool.size(), 2);
507 }
508
509 #[test]
510 fn test_compact_ast() {
511 let mut compact = CompactAST::new();
512
513 let hello_idx = compact.intern_string("hello");
514 let hello_idx2 = compact.intern_string("hello"); let world_idx = compact.intern_string("world");
516
517 assert_eq!(hello_idx, hello_idx2);
518 assert_ne!(hello_idx, world_idx);
519 assert_eq!(compact.get_string(hello_idx), Some("hello"));
520 assert_eq!(compact.get_string(world_idx), Some("world"));
521 }
522
523 #[test]
524 fn test_lazy_field() {
525 let counter = RefCell::new(0);
526 let lazy = LazyField::new(move || {
527 *counter.borrow_mut() += 1;
528 "computed".to_string()
529 });
530
531 assert!(!lazy.is_loaded());
532
533 let val = lazy.get();
534 assert_eq!(*val, "computed");
535
536 let val2 = lazy.get();
538 assert_eq!(*val2, "computed");
539 }
540
541 #[test]
542 fn test_memory_manager() {
543 let manager = BuildMemoryManager::new();
544 let stats = manager.memory_usage();
545
546 assert_eq!(stats.arena_allocated, 0);
548 assert!(stats.arena_capacity > 0);
549 }
550}