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