reifydb_engine/function/math/scalar/
abs.rs

1// Copyright (c) reifydb.com 2025
2// This file is licensed under the AGPL-3.0-or-later, see license.md file
3
4use reifydb_core::value::column::ColumnData;
5
6use crate::function::{ScalarFunction, ScalarFunctionContext};
7
8pub struct Abs;
9
10impl Abs {
11	pub fn new() -> Self {
12		Self {}
13	}
14}
15
16impl ScalarFunction for Abs {
17	fn scalar(&self, ctx: ScalarFunctionContext) -> crate::Result<ColumnData> {
18		let columns = ctx.columns;
19		let row_count = ctx.row_count;
20
21		let column = columns.get(0).unwrap();
22
23		match &column.data() {
24			ColumnData::Int1(container) => {
25				if container.is_fully_defined() {
26					// Fast path: all values are defined
27					let data: Vec<i8> = container
28						.data()
29						.iter()
30						.take(row_count)
31						.map(|&value| {
32							if value < 0 {
33								value * -1
34							} else {
35								value
36							}
37						})
38						.collect();
39					Ok(ColumnData::int1(data))
40				} else {
41					// Slow path: some values may be
42					// undefined
43					let mut data = Vec::with_capacity(container.len());
44
45					for i in 0..row_count {
46						if let Some(value) = container.get(i) {
47							data.push(if *value < 0 {
48								*value * -1
49							} else {
50								*value
51							});
52						} else {
53							// Push default value
54							// for undefined entries
55							data.push(0);
56						}
57					}
58
59					Ok(ColumnData::int1_with_bitvec(data, container.bitvec().clone()))
60				}
61			}
62			ColumnData::Int2(container) => {
63				if container.is_fully_defined() {
64					// Fast path: all values are defined
65					let data: Vec<i16> = container
66						.data()
67						.iter()
68						.take(row_count)
69						.map(|&value| {
70							if value < 0 {
71								value * -1
72							} else {
73								value
74							}
75						})
76						.collect();
77					Ok(ColumnData::int2(data))
78				} else {
79					// Slow path: some values may be
80					// undefined
81					let mut data = Vec::with_capacity(container.len());
82
83					for i in 0..row_count {
84						if let Some(value) = container.get(i) {
85							data.push(if *value < 0 {
86								*value * -1
87							} else {
88								*value
89							});
90						} else {
91							// Push default value
92							// for undefined entries
93							data.push(0);
94						}
95					}
96
97					Ok(ColumnData::int2_with_bitvec(data, container.bitvec().clone()))
98				}
99			}
100			ColumnData::Int4(container) => {
101				if container.is_fully_defined() {
102					// Fast path: all values are defined
103					let data: Vec<i32> = container
104						.data()
105						.iter()
106						.take(row_count)
107						.map(|&value| {
108							if value < 0 {
109								value * -1
110							} else {
111								value
112							}
113						})
114						.collect();
115					Ok(ColumnData::int4(data))
116				} else {
117					// Slow path: some values may be undefined
118					let mut data = Vec::with_capacity(container.len());
119
120					for i in 0..row_count {
121						if let Some(value) = container.get(i) {
122							data.push(if *value < 0 {
123								*value * -1
124							} else {
125								*value
126							});
127						} else {
128							// Push default value for undefined entries
129							data.push(0);
130						}
131					}
132
133					Ok(ColumnData::int4_with_bitvec(data, container.bitvec().clone()))
134				}
135			}
136			ColumnData::Float4(container) => {
137				if container.is_fully_defined() {
138					// Fast path: all values are defined
139					let data: Vec<f32> = container
140						.data()
141						.iter()
142						.take(row_count)
143						.map(|&value| value.abs())
144						.collect();
145					Ok(ColumnData::float4(data))
146				} else {
147					// Slow path: some values may be undefined
148					let mut data = Vec::with_capacity(container.len());
149
150					for i in 0..row_count {
151						if let Some(value) = container.get(i) {
152							data.push(value.abs());
153						} else {
154							// Push default value for undefined entries
155							data.push(0.0);
156						}
157					}
158
159					Ok(ColumnData::float4_with_bitvec(data, container.bitvec().clone()))
160				}
161			}
162			ColumnData::Float8(container) => {
163				if container.is_fully_defined() {
164					// Fast path: all values are defined
165					let data: Vec<f64> = container
166						.data()
167						.iter()
168						.take(row_count)
169						.map(|&value| value.abs())
170						.collect();
171					Ok(ColumnData::float8(data))
172				} else {
173					// Slow path: some values may be undefined
174					let mut data = Vec::with_capacity(container.len());
175
176					for i in 0..row_count {
177						if let Some(value) = container.get(i) {
178							data.push(value.abs());
179						} else {
180							// Push default value for undefined entries
181							data.push(0.0);
182						}
183					}
184
185					Ok(ColumnData::float8_with_bitvec(data, container.bitvec().clone()))
186				}
187			}
188			_ => unimplemented!(),
189		}
190	}
191}
192
193#[cfg(test)]
194mod tests {
195	use reifydb_core::{
196		BitVec,
197		value::column::{Column, Columns},
198	};
199
200	use super::*;
201
202	#[test]
203	fn test_abs_int1_fully_defined() {
204		let function = Abs::new();
205
206		// Create a column with all values defined
207		let data = vec![-5i8, 3, -2, 0, 7, -1];
208		let column = Column::int1("test", data.clone());
209
210		let columns = Columns::new(vec![column]);
211		let ctx = ScalarFunctionContext {
212			columns: &columns,
213			row_count: 6,
214		};
215
216		let result = function.scalar(ctx).unwrap();
217
218		// Check that result is fully defined
219		if let ColumnData::Int1(container) = result {
220			assert!(container.is_fully_defined());
221			assert_eq!(container.len(), 6);
222
223			// Check values
224			let expected = vec![5i8, 3, 2, 0, 7, 1];
225			for (i, &expected_val) in expected.iter().enumerate() {
226				assert_eq!(container.get(i), Some(&expected_val));
227			}
228		} else {
229			panic!("Expected Int1 result");
230		}
231	}
232
233	#[test]
234	fn test_abs_int1_partially_defined() {
235		let function = Abs::new();
236
237		// Create a column with some undefined values
238		let data = vec![-5i8, 3, -2, 0, 7, -1];
239		let mut bitvec = BitVec::repeat(6, true);
240		bitvec.set(2, false); // Make index 2 undefined
241		bitvec.set(4, false); // Make index 4 undefined
242
243		let column = Column::int1_with_bitvec("test", data.clone(), bitvec.clone());
244
245		let columns = Columns::new(vec![column]);
246		let ctx = ScalarFunctionContext {
247			columns: &columns,
248			row_count: 6,
249		};
250
251		let result = function.scalar(ctx).unwrap();
252
253		// Check that result has same undefined pattern
254		if let ColumnData::Int1(container) = result {
255			assert!(!container.is_fully_defined());
256			assert_eq!(container.bitvec().count_ones(), 4); // Only 4 defined values
257
258			// Check defined values
259			assert_eq!(container.get(0), Some(&5));
260			assert_eq!(container.get(1), Some(&3));
261			assert_eq!(container.get(2), None); // undefined
262			assert_eq!(container.get(3), Some(&0));
263			assert_eq!(container.get(4), None); // undefined
264			assert_eq!(container.get(5), Some(&1));
265		} else {
266			panic!("Expected Int1 result");
267		}
268	}
269
270	#[test]
271	fn test_abs_int2_fully_defined() {
272		let function = Abs::new();
273
274		// Create a column with all values defined
275		let data = vec![-500i16, 300, -200, 0, 700, -100];
276		let column = Column::int2("test", data.clone());
277
278		let columns = Columns::new(vec![column]);
279		let ctx = ScalarFunctionContext {
280			columns: &columns,
281			row_count: 6,
282		};
283
284		let result = function.scalar(ctx).unwrap();
285
286		// Check that result is fully defined
287		if let ColumnData::Int2(container) = result {
288			assert!(container.is_fully_defined());
289			assert_eq!(container.len(), 6);
290
291			// Check values
292			let expected = vec![500i16, 300, 200, 0, 700, 100];
293			for (i, &expected_val) in expected.iter().enumerate() {
294				assert_eq!(container.get(i), Some(&expected_val));
295			}
296		} else {
297			panic!("Expected Int2 result");
298		}
299	}
300}