1use std::ptr;
5
6use num_bigint::BigInt as StdBigInt;
7use num_traits::ToPrimitive;
8use reifydb_type::value::{int::Int, r#type::Type};
9
10use crate::encoded::{row::EncodedRow, schema::RowSchema};
11
12const MODE_INLINE: u128 = 0x00000000000000000000000000000000;
16const MODE_MASK: u128 = 0x80000000000000000000000000000000;
17
18const INLINE_VALUE_MASK: u128 = 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF;
20
21const DYNAMIC_OFFSET_MASK: u128 = 0x0000000000000000FFFFFFFFFFFFFFFF; const DYNAMIC_LENGTH_MASK: u128 = 0x7FFFFFFFFFFFFFFF0000000000000000; impl RowSchema {
26 pub fn set_int(&self, row: &mut EncodedRow, index: usize, value: &Int) {
30 let field = &self.fields()[index];
31 debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Int);
32
33 if let Some(i128_val) = value.0.to_i128() {
35 if i128_val >= -(1i128 << 126) && i128_val < (1i128 << 126) {
37 self.remove_dynamic_data(row, index);
39
40 let packed = MODE_INLINE | ((i128_val as u128) & INLINE_VALUE_MASK);
42 unsafe {
43 ptr::write_unaligned(
44 row.make_mut().as_mut_ptr().add(field.offset as usize) as *mut u128,
45 packed.to_le(),
46 );
47 }
48 row.set_valid(index, true);
49 return;
50 }
51 }
52
53 let bytes = value.0.to_signed_bytes_le();
55 self.replace_dynamic_data(row, index, &bytes);
56 }
57
58 pub fn get_int(&self, row: &EncodedRow, index: usize) -> Int {
60 let field = &self.fields()[index];
61 debug_assert_eq!(*field.constraint.get_type().inner_type(), Type::Int);
62
63 let packed = unsafe { (row.as_ptr().add(field.offset as usize) as *const u128).read_unaligned() };
64 let packed = u128::from_le(packed);
65
66 let mode = packed & MODE_MASK;
67
68 if mode == MODE_INLINE {
69 let value = (packed & INLINE_VALUE_MASK) as i128;
71 let signed = if value & (1i128 << 126) != 0 {
72 value | (1i128 << 127)
74 } else {
75 value
76 };
77 Int::from(signed)
78 } else {
79 let offset = (packed & DYNAMIC_OFFSET_MASK) as usize;
82 let length = ((packed & DYNAMIC_LENGTH_MASK) >> 64) as usize;
83
84 let dynamic_start = self.dynamic_section_start();
85 let bigint_bytes = &row.as_slice()[dynamic_start + offset..dynamic_start + offset + length];
86
87 Int::from(StdBigInt::from_signed_bytes_le(bigint_bytes))
88 }
89 }
90
91 pub fn try_get_int(&self, row: &EncodedRow, index: usize) -> Option<Int> {
93 if row.is_defined(index) && self.fields()[index].constraint.get_type() == Type::Int {
94 Some(self.get_int(row, index))
95 } else {
96 None
97 }
98 }
99}
100
101#[cfg(test)]
102pub mod tests {
103 use num_bigint::BigInt;
104 use reifydb_type::value::{int::Int, r#type::Type};
105
106 use crate::encoded::schema::RowSchema;
107
108 #[test]
109 fn test_i64_inline() {
110 let schema = RowSchema::testing(&[Type::Int]);
111 let mut row = schema.allocate();
112
113 let small = Int::from(42i64);
115 schema.set_int(&mut row, 0, &small);
116 assert!(row.is_defined(0));
117
118 let retrieved = schema.get_int(&row, 0);
119 assert_eq!(retrieved, small);
120
121 let mut row2 = schema.allocate();
123 let negative = Int::from(-999999i64);
124 schema.set_int(&mut row2, 0, &negative);
125 assert_eq!(schema.get_int(&row2, 0), negative);
126 }
127
128 #[test]
129 fn test_i128_boundary() {
130 let schema = RowSchema::testing(&[Type::Int]);
131 let mut row = schema.allocate();
132
133 let large = Int::from(i64::MAX);
135 schema.set_int(&mut row, 0, &large);
136 assert!(row.is_defined(0));
137
138 let retrieved = schema.get_int(&row, 0);
139 assert_eq!(retrieved, large);
140
141 let mut row2 = schema.allocate();
143 let max_i128 = Int::from(i128::MAX);
144 schema.set_int(&mut row2, 0, &max_i128);
145 assert_eq!(schema.get_int(&row2, 0), max_i128);
146
147 let mut row3 = schema.allocate();
149 let min_i128 = Int::from(i128::MIN);
150 schema.set_int(&mut row3, 0, &min_i128);
151 assert_eq!(schema.get_int(&row3, 0), min_i128);
152 }
153
154 #[test]
155 fn test_dynamic_storage() {
156 let schema = RowSchema::testing(&[Type::Int]);
157 let mut row = schema.allocate();
158
159 let huge_str = "999999999999999999999999999999999999999999999999";
161 let huge = Int::from(BigInt::parse_bytes(huge_str.as_bytes(), 10).unwrap());
162
163 schema.set_int(&mut row, 0, &huge);
164 assert!(row.is_defined(0));
165
166 let retrieved = schema.get_int(&row, 0);
167 assert_eq!(retrieved, huge);
168 assert_eq!(retrieved.to_string(), huge_str);
169 }
170
171 #[test]
172 fn test_zero() {
173 let schema = RowSchema::testing(&[Type::Int]);
174 let mut row = schema.allocate();
175
176 let zero = Int::from(0);
177 schema.set_int(&mut row, 0, &zero);
178 assert!(row.is_defined(0));
179
180 let retrieved = schema.get_int(&row, 0);
181 assert_eq!(retrieved, zero);
182 }
183
184 #[test]
185 fn test_try_get() {
186 let schema = RowSchema::testing(&[Type::Int]);
187 let mut row = schema.allocate();
188
189 assert_eq!(schema.try_get_int(&row, 0), None);
191
192 let value = Int::from(12345);
194 schema.set_int(&mut row, 0, &value);
195 assert_eq!(schema.try_get_int(&row, 0), Some(value));
196 }
197
198 #[test]
199 fn test_clone_on_write() {
200 let schema = RowSchema::testing(&[Type::Int]);
201 let row1 = schema.allocate();
202 let mut row2 = row1.clone();
203
204 let value = Int::from(999999999999999i64);
205 schema.set_int(&mut row2, 0, &value);
206
207 assert!(!row1.is_defined(0));
208 assert!(row2.is_defined(0));
209 assert_ne!(row1.as_ptr(), row2.as_ptr());
210 assert_eq!(schema.get_int(&row2, 0), value);
211 }
212
213 #[test]
214 fn test_multiple_fields() {
215 let schema = RowSchema::testing(&[Type::Int4, Type::Int, Type::Utf8, Type::Int]);
216 let mut row = schema.allocate();
217
218 schema.set_i32(&mut row, 0, 42);
219
220 let small = Int::from(100);
221 schema.set_int(&mut row, 1, &small);
222
223 schema.set_utf8(&mut row, 2, "test");
224
225 let large = Int::from(i128::MAX);
226 schema.set_int(&mut row, 3, &large);
227
228 assert_eq!(schema.get_i32(&row, 0), 42);
229 assert_eq!(schema.get_int(&row, 1), small);
230 assert_eq!(schema.get_utf8(&row, 2), "test");
231 assert_eq!(schema.get_int(&row, 3), large);
232 }
233
234 #[test]
235 fn test_negative_values() {
236 let schema = RowSchema::testing(&[Type::Int]);
237
238 let mut row1 = schema.allocate();
240 let small_neg = Int::from(-42);
241 schema.set_int(&mut row1, 0, &small_neg);
242 assert_eq!(schema.get_int(&row1, 0), small_neg);
243
244 let mut row2 = schema.allocate();
246 let large_neg = Int::from(i64::MIN);
247 schema.set_int(&mut row2, 0, &large_neg);
248 assert_eq!(schema.get_int(&row2, 0), large_neg);
249
250 let mut row3 = schema.allocate();
252 let huge_neg_str = "-999999999999999999999999999999999999999999999999";
253 let huge_neg =
254 Int::from(-BigInt::parse_bytes(huge_neg_str.trim_start_matches('-').as_bytes(), 10).unwrap());
255 schema.set_int(&mut row3, 0, &huge_neg);
256 assert_eq!(schema.get_int(&row3, 0), huge_neg);
257 }
258
259 #[test]
260 fn test_try_get_int_wrong_type() {
261 let schema = RowSchema::testing(&[Type::Boolean]);
262 let mut row = schema.allocate();
263
264 schema.set_bool(&mut row, 0, true);
265
266 assert_eq!(schema.try_get_int(&row, 0), None);
267 }
268
269 #[test]
270 fn test_update_int_inline_to_inline() {
271 let schema = RowSchema::testing(&[Type::Int]);
272 let mut row = schema.allocate();
273
274 schema.set_int(&mut row, 0, &Int::from(42));
275 assert_eq!(schema.get_int(&row, 0), Int::from(42));
276
277 schema.set_int(&mut row, 0, &Int::from(-999));
278 assert_eq!(schema.get_int(&row, 0), Int::from(-999));
279 }
280
281 #[test]
282 fn test_update_int_inline_to_dynamic() {
283 let schema = RowSchema::testing(&[Type::Int]);
284 let mut row = schema.allocate();
285
286 schema.set_int(&mut row, 0, &Int::from(42));
287 assert_eq!(schema.get_int(&row, 0), Int::from(42));
288
289 let huge = Int::from(
290 BigInt::parse_bytes(b"999999999999999999999999999999999999999999999999", 10).unwrap(),
291 );
292 schema.set_int(&mut row, 0, &huge);
293 assert_eq!(schema.get_int(&row, 0), huge);
294 }
295
296 #[test]
297 fn test_update_int_dynamic_to_inline() {
298 let schema = RowSchema::testing(&[Type::Int]);
299 let mut row = schema.allocate();
300
301 let huge = Int::from(
302 BigInt::parse_bytes(b"999999999999999999999999999999999999999999999999", 10).unwrap(),
303 );
304 schema.set_int(&mut row, 0, &huge);
305 assert_eq!(schema.get_int(&row, 0), huge);
306
307 schema.set_int(&mut row, 0, &Int::from(42));
309 assert_eq!(schema.get_int(&row, 0), Int::from(42));
310 assert_eq!(row.len(), schema.total_static_size());
312 }
313
314 #[test]
315 fn test_update_int_dynamic_to_dynamic() {
316 let schema = RowSchema::testing(&[Type::Int]);
317 let mut row = schema.allocate();
318
319 let huge1 = Int::from(
320 BigInt::parse_bytes(b"999999999999999999999999999999999999999999999999", 10).unwrap(),
321 );
322 schema.set_int(&mut row, 0, &huge1);
323 assert_eq!(schema.get_int(&row, 0), huge1);
324
325 let huge2 = Int::from(
326 -BigInt::parse_bytes(b"111111111111111111111111111111111111111111111111", 10).unwrap(),
327 );
328 schema.set_int(&mut row, 0, &huge2);
329 assert_eq!(schema.get_int(&row, 0), huge2);
330 }
331
332 #[test]
333 fn test_update_int_with_other_dynamic_fields() {
334 let schema = RowSchema::testing(&[Type::Int, Type::Utf8, Type::Int]);
335 let mut row = schema.allocate();
336
337 let huge1 = Int::from(
338 BigInt::parse_bytes(b"999999999999999999999999999999999999999999999999", 10).unwrap(),
339 );
340 schema.set_int(&mut row, 0, &huge1);
341 schema.set_utf8(&mut row, 1, "hello");
342 let huge2 = Int::from(
343 BigInt::parse_bytes(b"111111111111111111111111111111111111111111111111", 10).unwrap(),
344 );
345 schema.set_int(&mut row, 2, &huge2);
346
347 schema.set_int(&mut row, 0, &Int::from(42));
349
350 assert_eq!(schema.get_int(&row, 0), Int::from(42));
351 assert_eq!(schema.get_utf8(&row, 1), "hello");
352 assert_eq!(schema.get_int(&row, 2), huge2);
353 }
354}