formualizer_eval/engine/arena/
scalar.rs1use std::fmt;
4
5#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
7pub struct ScalarRef {
8 pub raw: u32,
11}
12
13impl ScalarRef {
14 const TYPE_MASK: u32 = 1 << 31;
15 const INDEX_MASK: u32 = !Self::TYPE_MASK;
16
17 fn float(index: u32) -> Self {
18 debug_assert!(index <= Self::INDEX_MASK, "Float index overflow");
19 Self { raw: index }
20 }
21
22 fn integer(index: u32) -> Self {
23 debug_assert!(index <= Self::INDEX_MASK, "Integer index overflow");
24 Self {
25 raw: index | Self::TYPE_MASK,
26 }
27 }
28
29 pub fn from_integer_index(index: u32) -> Self {
30 Self {
31 raw: index | Self::TYPE_MASK,
32 }
33 }
34
35 pub fn from_float_index(index: u32) -> Self {
36 Self { raw: index }
37 }
38
39 pub fn is_float(self) -> bool {
40 self.raw & Self::TYPE_MASK == 0
41 }
42
43 pub fn is_integer(self) -> bool {
44 !self.is_float()
45 }
46
47 fn index(self) -> usize {
48 (self.raw & Self::INDEX_MASK) as usize
49 }
50}
51
52#[derive(Debug)]
54pub struct ScalarArena {
55 floats: Vec<f64>,
56 integers: Vec<i64>,
57}
58
59impl ScalarArena {
60 pub fn new() -> Self {
61 Self {
62 floats: Vec::new(),
63 integers: Vec::new(),
64 }
65 }
66
67 pub fn with_capacity(cap: usize) -> Self {
68 Self {
69 floats: Vec::with_capacity(cap / 2),
70 integers: Vec::with_capacity(cap / 2),
71 }
72 }
73
74 pub fn insert_float(&mut self, value: f64) -> ScalarRef {
76 let index = self.floats.len() as u32;
77 if index > ScalarRef::INDEX_MASK {
78 panic!("Scalar arena float overflow: too many values");
79 }
80 self.floats.push(value);
81 ScalarRef::float(index)
82 }
83
84 pub fn insert_integer(&mut self, value: i64) -> ScalarRef {
86 let index = self.integers.len() as u32;
87 if index > ScalarRef::INDEX_MASK {
88 panic!("Scalar arena integer overflow: too many values");
89 }
90 self.integers.push(value);
91 ScalarRef::integer(index)
92 }
93
94 #[inline]
96 pub fn get_float(&self, r: ScalarRef) -> Option<f64> {
97 if r.is_float() {
98 self.floats.get(r.index()).copied()
99 } else {
100 None
101 }
102 }
103
104 #[inline]
106 pub fn get_integer(&self, r: ScalarRef) -> Option<i64> {
107 if r.is_integer() {
108 self.integers.get(r.index()).copied()
109 } else {
110 None
111 }
112 }
113
114 #[inline]
116 pub fn get_as_float(&self, r: ScalarRef) -> Option<f64> {
117 if r.is_float() {
118 self.floats.get(r.index()).copied()
119 } else {
120 self.integers.get(r.index()).map(|i| *i as f64)
121 }
122 }
123
124 pub fn len(&self) -> usize {
126 self.floats.len() + self.integers.len()
127 }
128
129 pub fn is_empty(&self) -> bool {
131 self.floats.is_empty() && self.integers.is_empty()
132 }
133
134 pub fn memory_usage(&self) -> usize {
136 self.floats.capacity() * std::mem::size_of::<f64>()
137 + self.integers.capacity() * std::mem::size_of::<i64>()
138 }
139
140 pub fn clear(&mut self) {
142 self.floats.clear();
143 self.integers.clear();
144 }
145}
146
147impl Default for ScalarArena {
148 fn default() -> Self {
149 Self::new()
150 }
151}
152
153impl fmt::Display for ScalarRef {
154 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
155 if self.is_float() {
156 write!(f, "Float({})", self.index())
157 } else {
158 write!(f, "Int({})", self.index())
159 }
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use super::*;
166
167 #[test]
168 fn test_scalar_arena_float_alloc() {
169 let mut arena = ScalarArena::new();
170 let ref1 = arena.insert_float(42.0);
171 let ref2 = arena.insert_float(3.14);
172
173 assert_eq!(arena.get_float(ref1), Some(42.0));
174 assert_eq!(arena.get_float(ref2), Some(3.14));
175 assert_eq!(arena.len(), 2);
176 }
177
178 #[test]
179 fn test_scalar_arena_integer_alloc() {
180 let mut arena = ScalarArena::new();
181 let ref1 = arena.insert_integer(42);
182 let ref2 = arena.insert_integer(-100);
183
184 assert_eq!(arena.get_integer(ref1), Some(42));
185 assert_eq!(arena.get_integer(ref2), Some(-100));
186 assert_eq!(arena.len(), 2);
187 }
188
189 #[test]
190 fn test_scalar_arena_mixed_types() {
191 let mut arena = ScalarArena::new();
192 let float_ref = arena.insert_float(3.14);
193 let int_ref = arena.insert_integer(42);
194
195 assert!(float_ref.is_float());
196 assert!(!float_ref.is_integer());
197 assert!(int_ref.is_integer());
198 assert!(!int_ref.is_float());
199
200 assert_eq!(arena.get_float(float_ref), Some(3.14));
201 assert_eq!(arena.get_integer(int_ref), Some(42));
202
203 assert_eq!(arena.get_float(int_ref), None);
205 assert_eq!(arena.get_integer(float_ref), None);
206 }
207
208 #[test]
209 fn test_scalar_arena_capacity() {
210 let mut arena = ScalarArena::with_capacity(1000);
211 let refs: Vec<_> = (0..10_000)
212 .map(|i| {
213 if i % 2 == 0 {
214 arena.insert_float(i as f64)
215 } else {
216 arena.insert_integer(i as i64)
217 }
218 })
219 .collect();
220
221 for (i, r) in refs.iter().enumerate() {
223 if i % 2 == 0 {
224 assert_eq!(arena.get_float(*r), Some(i as f64));
225 } else {
226 assert_eq!(arena.get_integer(*r), Some(i as i64));
227 }
228 }
229
230 assert_eq!(arena.len(), 10_000);
231 }
232
233 #[test]
234 fn test_scalar_arena_get_as_float() {
235 let mut arena = ScalarArena::new();
236 let float_ref = arena.insert_float(3.14);
237 let int_ref = arena.insert_integer(42);
238
239 assert_eq!(arena.get_as_float(float_ref), Some(3.14));
240 assert_eq!(arena.get_as_float(int_ref), Some(42.0));
241 }
242
243 #[test]
244 fn test_scalar_arena_memory_usage() {
245 let mut arena = ScalarArena::new();
246 let initial_memory = arena.memory_usage();
247
248 for i in 0..100 {
249 arena.insert_float(i as f64);
250 arena.insert_integer(i);
251 }
252
253 let final_memory = arena.memory_usage();
254 assert!(final_memory > initial_memory);
255
256 assert!(final_memory >= 1600);
258 }
259
260 #[test]
261 fn test_scalar_ref_display() {
262 let mut arena = ScalarArena::new();
263 let float_ref = arena.insert_float(3.14);
264 let int_ref = arena.insert_integer(42);
265
266 assert_eq!(format!("{float_ref}"), "Float(0)");
267 assert_eq!(format!("{int_ref}"), "Int(0)");
268 }
269
270 #[test]
271 fn test_scalar_arena_clear() {
272 let mut arena = ScalarArena::new();
273 arena.insert_float(3.14);
274 arena.insert_integer(42);
275
276 assert_eq!(arena.len(), 2);
277 arena.clear();
278 assert_eq!(arena.len(), 0);
279 assert!(arena.is_empty());
280 }
281
282 #[test]
283 #[should_panic(expected = "Float index overflow")]
284 fn test_scalar_arena_float_overflow() {
285 let _ = ScalarRef::float(ScalarRef::INDEX_MASK + 1);
288 }
289}