qanglang_core/memory/
closure_upvalue_reference.rs1use crate::{arena::Index, memory::ClosureHandle};
2
3pub type UpvalueOverflowHandle = Index;
4
5const INLINE_UPVALUE_CAPACITY: usize = 4;
6
7#[derive(Debug, Clone)]
8pub struct OpenUpvalueTracker {
9 inline_entries: [(ClosureHandle, usize); INLINE_UPVALUE_CAPACITY],
10 count: usize,
11 overflow_handle: Option<UpvalueOverflowHandle>,
12}
13
14impl Default for OpenUpvalueTracker {
15 fn default() -> Self {
16 Self {
17 inline_entries: [(ClosureHandle::default(), 0); INLINE_UPVALUE_CAPACITY],
18 count: 0,
19 overflow_handle: None,
20 }
21 }
22}
23
24impl OpenUpvalueTracker {
25 pub fn new() -> Self {
26 Self::default()
27 }
28
29 pub fn add_closure(
30 &mut self,
31 closure_handle: ClosureHandle,
32 upvalue_index: usize,
33 overflow_arena: &mut crate::memory::UpvalueOverflowArena,
34 ) {
35 if self.count < INLINE_UPVALUE_CAPACITY {
36 self.inline_entries[self.count] = (closure_handle, upvalue_index);
37 self.count += 1;
38 return;
39 }
40
41 if self.overflow_handle.is_none() {
43 let handle = overflow_arena.allocate_chunk();
44 self.overflow_handle = Some(handle);
45 }
46
47 let mut current_handle = self.overflow_handle.unwrap();
49 loop {
50 {
51 let chunk = overflow_arena.get_chunk_mut(current_handle);
52 if chunk.count < crate::memory::upvalue_overflow_arena::OVERFLOW_CHUNK_SIZE {
53 chunk.entries[chunk.count] = (closure_handle, upvalue_index);
54 chunk.count += 1;
55 return;
56 }
57 }
58
59 let next_handle = {
60 let chunk = overflow_arena.get_chunk(current_handle);
61 chunk.next
62 };
63
64 if let Some(next) = next_handle {
65 current_handle = next;
66 } else {
67 let new_handle = overflow_arena.allocate_chunk();
69 overflow_arena.get_chunk_mut(current_handle).next = Some(new_handle);
70 let new_chunk = overflow_arena.get_chunk_mut(new_handle);
71 new_chunk.entries[0] = (closure_handle, upvalue_index);
72 new_chunk.count = 1;
73 return;
74 }
75 }
76 }
77
78 pub fn iter(&self) -> impl Iterator<Item = (ClosureHandle, usize)> + '_ {
79 self.inline_entries[..self.count].iter().copied()
80 }
81
82 pub fn iter_all_entries<'a>(
83 &'a self,
84 overflow_arena: &'a crate::memory::UpvalueOverflowArena,
85 ) -> impl Iterator<Item = (ClosureHandle, usize)> + 'a {
86 UpvalueEntryIterator::new(self, overflow_arena)
87 }
88
89 pub fn overflow_handle(&self) -> Option<UpvalueOverflowHandle> {
90 self.overflow_handle
91 }
92
93 pub fn set_overflow_handle(&mut self, handle: UpvalueOverflowHandle) {
94 self.overflow_handle = Some(handle);
95 }
96
97 pub fn len(&self, overflow_arena: &crate::memory::UpvalueOverflowArena) -> usize {
98 let mut total = self.count;
99
100 if let Some(mut current_handle) = self.overflow_handle {
101 loop {
102 let chunk = overflow_arena.get_chunk(current_handle);
103 total += chunk.count;
104 if let Some(next_handle) = chunk.next {
105 current_handle = next_handle;
106 } else {
107 break;
108 }
109 }
110 }
111
112 total
113 }
114
115 pub fn is_empty(&self) -> bool {
116 self.count == 0
117 }
118
119 pub fn mark_overflow_chunks(&self, overflow_arena: &mut crate::memory::UpvalueOverflowArena) {
120 if let Some(mut current_handle) = self.overflow_handle {
121 loop {
122 overflow_arena.mark_chunk(current_handle);
123 let chunk = overflow_arena.get_chunk(current_handle);
124 if let Some(next_handle) = chunk.next {
125 current_handle = next_handle;
126 } else {
127 break;
128 }
129 }
130 }
131 }
132}
133
134struct UpvalueEntryIterator<'a> {
135 tracker: &'a OpenUpvalueTracker,
136 overflow_arena: &'a crate::memory::UpvalueOverflowArena,
137 inline_index: usize,
138 current_chunk: Option<UpvalueOverflowHandle>,
139 chunk_index: usize,
140}
141
142impl<'a> UpvalueEntryIterator<'a> {
143 fn new(
144 tracker: &'a OpenUpvalueTracker,
145 overflow_arena: &'a crate::memory::UpvalueOverflowArena,
146 ) -> Self {
147 Self {
148 tracker,
149 overflow_arena,
150 inline_index: 0,
151 current_chunk: tracker.overflow_handle,
152 chunk_index: 0,
153 }
154 }
155}
156
157impl<'a> Iterator for UpvalueEntryIterator<'a> {
158 type Item = (ClosureHandle, usize);
159
160 fn next(&mut self) -> Option<Self::Item> {
161 if self.inline_index < self.tracker.count {
163 let entry = self.tracker.inline_entries[self.inline_index];
164 self.inline_index += 1;
165 return Some(entry);
166 }
167
168 while let Some(chunk_handle) = self.current_chunk {
170 let chunk = self.overflow_arena.get_chunk(chunk_handle);
171
172 if self.chunk_index < chunk.count {
173 let entry = chunk.entries[self.chunk_index];
174 self.chunk_index += 1;
175 return Some(entry);
176 }
177
178 self.current_chunk = chunk.next;
180 self.chunk_index = 0;
181 }
182
183 None
184 }
185}