1use indexmap::IndexMap;
7use std::cell::RefCell;
8use std::collections::VecDeque;
9use std::mem;
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 pub fn allocated_bytes(&self) -> usize {
59 self.chunks.borrow().iter().map(|chunk| chunk.len()).sum()
60 }
61
62 pub fn capacity_bytes(&self) -> usize {
64 self.chunks
65 .borrow()
66 .iter()
67 .map(|chunk| chunk.capacity())
68 .sum()
69 }
70
71 pub fn reset(&self) {
73 let mut chunks = self.chunks.borrow_mut();
74 for chunk in chunks.iter_mut() {
75 chunk.clear();
76 }
77 *self.current_chunk.borrow_mut() = 0;
78 *self.current_offset.borrow_mut() = 0;
79 }
80
81 pub fn clear(&self) {
83 self.chunks.borrow_mut().clear();
84 *self.current_chunk.borrow_mut() = 0;
85 *self.current_offset.borrow_mut() = 0;
86 }
87}
88
89pub struct ObjectPool<T> {
91 objects: RefCell<VecDeque<T>>,
92 factory: Box<dyn Fn() -> T>,
93 max_size: usize,
94}
95
96impl<T> ObjectPool<T> {
97 pub fn new<F>(factory: F, max_size: usize) -> Self
99 where
100 F: Fn() -> T + 'static,
101 {
102 Self {
103 objects: RefCell::new(VecDeque::new()),
104 factory: Box::new(factory),
105 max_size,
106 }
107 }
108
109 pub fn get(&self) -> PooledObject<'_, T> {
111 let obj = self
112 .objects
113 .borrow_mut()
114 .pop_front()
115 .unwrap_or_else(|| (self.factory)());
116
117 PooledObject {
118 object: Some(obj),
119 pool: self,
120 }
121 }
122
123 fn return_object(&self, obj: T) {
125 let mut objects = self.objects.borrow_mut();
126 if objects.len() < self.max_size {
127 objects.push_back(obj);
128 }
129 }
131
132 pub fn size(&self) -> usize {
134 self.objects.borrow().len()
135 }
136
137 pub fn clear(&self) {
139 self.objects.borrow_mut().clear();
140 }
141}
142
143pub struct PooledObject<'a, T> {
145 object: Option<T>,
146 pool: &'a ObjectPool<T>,
147}
148
149impl<'a, T> PooledObject<'a, T> {
150 pub fn get_mut(&mut self) -> &mut T {
152 self.object.as_mut().unwrap()
153 }
154
155 pub fn get(&self) -> &T {
157 self.object.as_ref().unwrap()
158 }
159}
160
161impl<'a, T> Drop for PooledObject<'a, T> {
162 fn drop(&mut self) {
163 if let Some(obj) = self.object.take() {
164 self.pool.return_object(obj);
165 }
166 }
167}
168
169#[derive(Debug, Clone)]
171#[allow(dead_code)]
172pub struct CompactElement {
173 name_idx: u32,
175 namespace_idx: Option<u32>,
177 attributes: CompactAttributes,
179 children: Vec<CompactNodeRef>,
181}
182
183#[derive(Debug, Clone)]
185pub enum NodeType {
186 Element(u32),
188 Text(u32),
190 Comment(u32),
192}
193
194#[derive(Debug, Clone)]
196pub enum CompactNodeRef {
197 Element(u32),
199 Text(u32),
201 Comment(u32),
203}
204
205#[derive(Debug, Clone, Default)]
207pub struct CompactAttributes {
208 data: Vec<(u32, u32)>,
210}
211
212impl CompactAttributes {
213 pub fn insert(&mut self, key_idx: u32, value_idx: u32) {
215 self.data.push((key_idx, value_idx));
216 }
217
218 pub fn len(&self) -> usize {
220 self.data.len()
221 }
222
223 pub fn is_empty(&self) -> bool {
225 self.data.is_empty()
226 }
227
228 pub fn iter(&self) -> impl Iterator<Item = (u32, u32)> + '_ {
230 self.data.iter().copied()
231 }
232}
233
234#[derive(Debug)]
236pub struct CompactAST {
237 strings: Vec<String>,
239 string_map: IndexMap<String, u32>,
241 elements: Vec<CompactElement>,
243 root_idx: u32,
245 namespaces: Vec<(u32, u32)>, schema_location_idx: Option<u32>,
249}
250
251impl CompactAST {
252 pub fn new() -> Self {
254 Self {
255 strings: Vec::new(),
256 string_map: IndexMap::new(),
257 elements: Vec::new(),
258 root_idx: 0,
259 namespaces: Vec::new(),
260 schema_location_idx: None,
261 }
262 }
263
264 pub fn intern_string(&mut self, s: &str) -> u32 {
266 if let Some(&idx) = self.string_map.get(s) {
267 return idx;
268 }
269
270 let idx = self.strings.len() as u32;
271 self.strings.push(s.to_string());
272 self.string_map.insert(s.to_string(), idx);
273 idx
274 }
275
276 pub fn get_string(&self, idx: u32) -> Option<&str> {
278 self.strings.get(idx as usize).map(|s| s.as_str())
279 }
280
281 pub fn add_element(&mut self, element: CompactElement) -> u32 {
283 let idx = self.elements.len() as u32;
284 self.elements.push(element);
285 idx
286 }
287
288 pub fn get_element(&self, idx: u32) -> Option<&CompactElement> {
290 self.elements.get(idx as usize)
291 }
292
293 pub fn memory_footprint(&self) -> usize {
295 let strings_size = self.strings.iter().map(|s| s.len()).sum::<usize>();
296
297 let map_size = self.string_map.len() * (mem::size_of::<String>() + mem::size_of::<u32>());
298
299 let elements_size = self.elements.len() * mem::size_of::<CompactElement>();
300
301 strings_size + map_size + elements_size
302 }
303
304 pub fn from_ast(ast: &crate::ast::AST) -> Self {
306 let mut compact = CompactAST::new();
307
308 for (prefix, uri) in &ast.namespaces {
310 let prefix_idx = compact.intern_string(prefix);
311 let uri_idx = compact.intern_string(uri);
312 compact.namespaces.push((prefix_idx, uri_idx));
313 }
314
315 if let Some(ref location) = ast.schema_location {
317 compact.schema_location_idx = Some(compact.intern_string(location));
318 }
319
320 compact.root_idx = compact.convert_element(&ast.root);
322
323 compact
324 }
325
326 fn convert_element(&mut self, element: &crate::ast::Element) -> u32 {
328 let name_idx = self.intern_string(&element.name);
329 let namespace_idx = element.namespace.as_ref().map(|ns| self.intern_string(ns));
330
331 let mut attributes = CompactAttributes::default();
333 for (key, value) in &element.attributes {
334 let key_idx = self.intern_string(key);
335 let value_idx = self.intern_string(value);
336 attributes.insert(key_idx, value_idx);
337 }
338
339 let children = Vec::new(); let compact_element = CompactElement {
343 name_idx,
344 namespace_idx,
345 attributes,
346 children,
347 };
348
349 self.add_element(compact_element)
350 }
351}
352
353pub struct LazyField<T> {
355 value: RefCell<Option<T>>,
356 loader: Box<dyn Fn() -> T>,
357}
358
359impl<T: std::fmt::Debug> std::fmt::Debug for LazyField<T> {
360 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
361 f.debug_struct("LazyField")
362 .field("value", &self.value)
363 .field("loader", &"<function>")
364 .finish()
365 }
366}
367
368impl<T> LazyField<T> {
369 pub fn new<F>(loader: F) -> Self
371 where
372 F: Fn() -> T + 'static,
373 {
374 Self {
375 value: RefCell::new(None),
376 loader: Box::new(loader),
377 }
378 }
379
380 pub fn get(&self) -> std::cell::Ref<'_, T> {
382 if self.value.borrow().is_none() {
383 *self.value.borrow_mut() = Some((self.loader)());
384 }
385
386 std::cell::Ref::map(self.value.borrow(), |opt| opt.as_ref().unwrap())
387 }
388
389 pub fn is_loaded(&self) -> bool {
391 self.value.borrow().is_some()
392 }
393
394 pub fn clear(&self) {
396 *self.value.borrow_mut() = None;
397 }
398}
399
400pub struct BuildMemoryManager {
402 pub arena: Arena,
404 pub element_pool: ObjectPool<crate::ast::Element>,
406 pub small_string_pool: ObjectPool<String>,
408 pub buffer_pool: ObjectPool<Vec<u8>>,
410}
411
412impl BuildMemoryManager {
413 pub fn new() -> Self {
415 Self {
416 arena: Arena::new(64 * 1024), element_pool: ObjectPool::new(
418 || crate::ast::Element::new(""),
419 100, ),
421 small_string_pool: ObjectPool::new(
422 || String::with_capacity(64),
423 50, ),
425 buffer_pool: ObjectPool::new(
426 || Vec::with_capacity(8192), 10, ),
429 }
430 }
431
432 pub fn memory_usage(&self) -> MemoryStats {
434 MemoryStats {
435 arena_allocated: self.arena.allocated_bytes(),
436 arena_capacity: self.arena.capacity_bytes(),
437 element_pool_size: self.element_pool.size(),
438 string_pool_size: self.small_string_pool.size(),
439 buffer_pool_size: self.buffer_pool.size(),
440 }
441 }
442
443 pub fn reset_for_next_build(&self) {
445 self.arena.reset();
446 }
448
449 pub fn full_reset(&self) {
451 self.arena.clear();
452 self.element_pool.clear();
453 self.small_string_pool.clear();
454 self.buffer_pool.clear();
455 }
456}
457
458impl Default for BuildMemoryManager {
459 fn default() -> Self {
460 Self::new()
461 }
462}
463
464#[derive(Debug, Default)]
466pub struct MemoryStats {
467 pub arena_allocated: usize,
469 pub arena_capacity: usize,
471 pub element_pool_size: usize,
473 pub string_pool_size: usize,
475 pub buffer_pool_size: usize,
477}
478
479impl MemoryStats {
480 pub fn total_bytes(&self) -> usize {
482 self.arena_capacity +
483 (self.element_pool_size * mem::size_of::<crate::ast::Element>()) +
484 (self.string_pool_size * 64) + (self.buffer_pool_size * 8192) }
487}
488
489#[cfg(test)]
490mod tests {
491 use super::*;
492
493 #[test]
494 fn test_arena_allocation() {
495 let arena = Arena::new(1024);
496
497 let val1 = arena.alloc(42u32);
498 let val2 = arena.alloc("hello world".to_string());
499
500 assert_eq!(*val1, 42);
501 assert_eq!(*val2, "hello world");
502
503 assert!(arena.allocated_bytes() > 0);
504 }
505
506 #[test]
507 fn test_object_pool() {
508 let pool = ObjectPool::new(|| String::with_capacity(32), 5);
509
510 {
511 let mut obj1 = pool.get();
512 obj1.get_mut().push_str("test");
513 assert_eq!(obj1.get(), "test");
514
515 {
516 let _obj2 = pool.get();
517 assert_eq!(pool.size(), 0); }
519 }
521 assert_eq!(pool.size(), 2);
524 }
525
526 #[test]
527 fn test_compact_ast() {
528 let mut compact = CompactAST::new();
529
530 let hello_idx = compact.intern_string("hello");
531 let hello_idx2 = compact.intern_string("hello"); let world_idx = compact.intern_string("world");
533
534 assert_eq!(hello_idx, hello_idx2);
535 assert_ne!(hello_idx, world_idx);
536 assert_eq!(compact.get_string(hello_idx), Some("hello"));
537 assert_eq!(compact.get_string(world_idx), Some("world"));
538 }
539
540 #[test]
541 fn test_lazy_field() {
542 let counter = RefCell::new(0);
543 let lazy = LazyField::new(move || {
544 *counter.borrow_mut() += 1;
545 "computed".to_string()
546 });
547
548 assert!(!lazy.is_loaded());
549
550 let val = lazy.get();
551 assert_eq!(*val, "computed");
552
553 let val2 = lazy.get();
555 assert_eq!(*val2, "computed");
556 }
557
558 #[test]
559 fn test_memory_manager() {
560 let manager = BuildMemoryManager::new();
561 let stats = manager.memory_usage();
562
563 assert_eq!(stats.arena_allocated, 0);
565 assert!(stats.arena_capacity > 0);
566 }
567}