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