arrow2/compute/arithmetics/basic/add.rs
1//! Definition of basic add operations with primitive arrays
2use std::ops::Add;
3
4use num_traits::{ops::overflowing::OverflowingAdd, CheckedAdd, SaturatingAdd, WrappingAdd};
5
6use crate::{
7 array::PrimitiveArray,
8 bitmap::Bitmap,
9 compute::{
10 arithmetics::{
11 ArrayAdd, ArrayCheckedAdd, ArrayOverflowingAdd, ArraySaturatingAdd, ArrayWrappingAdd,
12 },
13 arity::{
14 binary, binary_checked, binary_with_bitmap, unary, unary_checked, unary_with_bitmap,
15 },
16 },
17};
18
19use super::NativeArithmetics;
20
21/// Adds two primitive arrays with the same type.
22/// Panics if the sum of one pair of values overflows.
23///
24/// # Examples
25/// ```
26/// use arrow2::compute::arithmetics::basic::add;
27/// use arrow2::array::PrimitiveArray;
28///
29/// let a = PrimitiveArray::from([None, Some(6), None, Some(6)]);
30/// let b = PrimitiveArray::from([Some(5), None, None, Some(6)]);
31/// let result = add(&a, &b);
32/// let expected = PrimitiveArray::from([None, None, None, Some(12)]);
33/// assert_eq!(result, expected)
34/// ```
35pub fn add<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
36where
37 T: NativeArithmetics + Add<Output = T>,
38{
39 binary(lhs, rhs, lhs.data_type().clone(), |a, b| a + b)
40}
41
42/// Wrapping addition of two [`PrimitiveArray`]s.
43/// It wraps around at the boundary of the type if the result overflows.
44///
45/// # Examples
46/// ```
47/// use arrow2::compute::arithmetics::basic::wrapping_add;
48/// use arrow2::array::PrimitiveArray;
49///
50/// let a = PrimitiveArray::from([Some(-100i8), Some(100i8), Some(100i8)]);
51/// let b = PrimitiveArray::from([Some(0i8), Some(100i8), Some(0i8)]);
52/// let result = wrapping_add(&a, &b);
53/// let expected = PrimitiveArray::from([Some(-100i8), Some(-56i8), Some(100i8)]);
54/// assert_eq!(result, expected);
55/// ```
56pub fn wrapping_add<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
57where
58 T: NativeArithmetics + WrappingAdd<Output = T>,
59{
60 let op = move |a: T, b: T| a.wrapping_add(&b);
61
62 binary(lhs, rhs, lhs.data_type().clone(), op)
63}
64
65/// Checked addition of two primitive arrays. If the result from the sum
66/// overflows, the validity for that index is changed to None
67///
68/// # Examples
69/// ```
70/// use arrow2::compute::arithmetics::basic::checked_add;
71/// use arrow2::array::PrimitiveArray;
72///
73/// let a = PrimitiveArray::from([Some(100i8), Some(100i8), Some(100i8)]);
74/// let b = PrimitiveArray::from([Some(0i8), Some(100i8), Some(0i8)]);
75/// let result = checked_add(&a, &b);
76/// let expected = PrimitiveArray::from([Some(100i8), None, Some(100i8)]);
77/// assert_eq!(result, expected);
78/// ```
79pub fn checked_add<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
80where
81 T: NativeArithmetics + CheckedAdd<Output = T>,
82{
83 let op = move |a: T, b: T| a.checked_add(&b);
84
85 binary_checked(lhs, rhs, lhs.data_type().clone(), op)
86}
87
88/// Saturating addition of two primitive arrays. If the result from the sum is
89/// larger than the possible number for this type, the result for the operation
90/// will be the saturated value.
91///
92/// # Examples
93/// ```
94/// use arrow2::compute::arithmetics::basic::saturating_add;
95/// use arrow2::array::PrimitiveArray;
96///
97/// let a = PrimitiveArray::from([Some(100i8)]);
98/// let b = PrimitiveArray::from([Some(100i8)]);
99/// let result = saturating_add(&a, &b);
100/// let expected = PrimitiveArray::from([Some(127)]);
101/// assert_eq!(result, expected);
102/// ```
103pub fn saturating_add<T>(lhs: &PrimitiveArray<T>, rhs: &PrimitiveArray<T>) -> PrimitiveArray<T>
104where
105 T: NativeArithmetics + SaturatingAdd<Output = T>,
106{
107 let op = move |a: T, b: T| a.saturating_add(&b);
108
109 binary(lhs, rhs, lhs.data_type().clone(), op)
110}
111
112/// Overflowing addition of two primitive arrays. If the result from the sum is
113/// larger than the possible number for this type, the result for the operation
114/// will be an array with overflowed values and a validity array indicating
115/// the overflowing elements from the array.
116///
117/// # Examples
118/// ```
119/// use arrow2::compute::arithmetics::basic::overflowing_add;
120/// use arrow2::array::PrimitiveArray;
121///
122/// let a = PrimitiveArray::from([Some(1i8), Some(100i8)]);
123/// let b = PrimitiveArray::from([Some(1i8), Some(100i8)]);
124/// let (result, overflow) = overflowing_add(&a, &b);
125/// let expected = PrimitiveArray::from([Some(2i8), Some(-56i8)]);
126/// assert_eq!(result, expected);
127/// ```
128pub fn overflowing_add<T>(
129 lhs: &PrimitiveArray<T>,
130 rhs: &PrimitiveArray<T>,
131) -> (PrimitiveArray<T>, Bitmap)
132where
133 T: NativeArithmetics + OverflowingAdd<Output = T>,
134{
135 let op = move |a: T, b: T| a.overflowing_add(&b);
136
137 binary_with_bitmap(lhs, rhs, lhs.data_type().clone(), op)
138}
139
140// Implementation of ArrayAdd trait for PrimitiveArrays
141impl<T> ArrayAdd<PrimitiveArray<T>> for PrimitiveArray<T>
142where
143 T: NativeArithmetics + Add<Output = T>,
144{
145 fn add(&self, rhs: &PrimitiveArray<T>) -> Self {
146 add(self, rhs)
147 }
148}
149
150impl<T> ArrayWrappingAdd<PrimitiveArray<T>> for PrimitiveArray<T>
151where
152 T: NativeArithmetics + WrappingAdd<Output = T>,
153{
154 fn wrapping_add(&self, rhs: &PrimitiveArray<T>) -> Self {
155 wrapping_add(self, rhs)
156 }
157}
158
159// Implementation of ArrayCheckedAdd trait for PrimitiveArrays
160impl<T> ArrayCheckedAdd<PrimitiveArray<T>> for PrimitiveArray<T>
161where
162 T: NativeArithmetics + CheckedAdd<Output = T>,
163{
164 fn checked_add(&self, rhs: &PrimitiveArray<T>) -> Self {
165 checked_add(self, rhs)
166 }
167}
168
169// Implementation of ArraySaturatingAdd trait for PrimitiveArrays
170impl<T> ArraySaturatingAdd<PrimitiveArray<T>> for PrimitiveArray<T>
171where
172 T: NativeArithmetics + SaturatingAdd<Output = T>,
173{
174 fn saturating_add(&self, rhs: &PrimitiveArray<T>) -> Self {
175 saturating_add(self, rhs)
176 }
177}
178
179// Implementation of ArraySaturatingAdd trait for PrimitiveArrays
180impl<T> ArrayOverflowingAdd<PrimitiveArray<T>> for PrimitiveArray<T>
181where
182 T: NativeArithmetics + OverflowingAdd<Output = T>,
183{
184 fn overflowing_add(&self, rhs: &PrimitiveArray<T>) -> (Self, Bitmap) {
185 overflowing_add(self, rhs)
186 }
187}
188
189/// Adds a scalar T to a primitive array of type T.
190/// Panics if the sum of the values overflows.
191///
192/// # Examples
193/// ```
194/// use arrow2::compute::arithmetics::basic::add_scalar;
195/// use arrow2::array::PrimitiveArray;
196///
197/// let a = PrimitiveArray::from([None, Some(6), None, Some(6)]);
198/// let result = add_scalar(&a, &1i32);
199/// let expected = PrimitiveArray::from([None, Some(7), None, Some(7)]);
200/// assert_eq!(result, expected)
201/// ```
202pub fn add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
203where
204 T: NativeArithmetics + Add<Output = T>,
205{
206 let rhs = *rhs;
207 unary(lhs, |a| a + rhs, lhs.data_type().clone())
208}
209
210/// Wrapping addition of a scalar T to a [`PrimitiveArray`] of type T.
211/// It do nothing if the result overflows.
212///
213/// # Examples
214/// ```
215/// use arrow2::compute::arithmetics::basic::wrapping_add_scalar;
216/// use arrow2::array::Int8Array;
217///
218/// let a = Int8Array::from(&[None, Some(100)]);
219/// let result = wrapping_add_scalar(&a, &100i8);
220/// let expected = Int8Array::from(&[None, Some(-56)]);
221/// assert_eq!(result, expected);
222/// ```
223pub fn wrapping_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
224where
225 T: NativeArithmetics + WrappingAdd<Output = T>,
226{
227 unary(lhs, |a| a.wrapping_add(rhs), lhs.data_type().clone())
228}
229
230/// Checked addition of a scalar T to a primitive array of type T. If the
231/// result from the sum overflows then the validity index for that value is
232/// changed to None
233///
234/// # Examples
235/// ```
236/// use arrow2::compute::arithmetics::basic::checked_add_scalar;
237/// use arrow2::array::Int8Array;
238///
239/// let a = Int8Array::from(&[None, Some(100), None, Some(100)]);
240/// let result = checked_add_scalar(&a, &100i8);
241/// let expected = Int8Array::from(&[None, None, None, None]);
242/// assert_eq!(result, expected);
243/// ```
244pub fn checked_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
245where
246 T: NativeArithmetics + CheckedAdd<Output = T>,
247{
248 let rhs = *rhs;
249 let op = move |a: T| a.checked_add(&rhs);
250
251 unary_checked(lhs, op, lhs.data_type().clone())
252}
253
254/// Saturated addition of a scalar T to a primitive array of type T. If the
255/// result from the sum is larger than the possible number for this type, then
256/// the result will be saturated
257///
258/// # Examples
259/// ```
260/// use arrow2::compute::arithmetics::basic::saturating_add_scalar;
261/// use arrow2::array::PrimitiveArray;
262///
263/// let a = PrimitiveArray::from([Some(100i8)]);
264/// let result = saturating_add_scalar(&a, &100i8);
265/// let expected = PrimitiveArray::from([Some(127)]);
266/// assert_eq!(result, expected);
267/// ```
268pub fn saturating_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> PrimitiveArray<T>
269where
270 T: NativeArithmetics + SaturatingAdd<Output = T>,
271{
272 let rhs = *rhs;
273 let op = move |a: T| a.saturating_add(&rhs);
274
275 unary(lhs, op, lhs.data_type().clone())
276}
277
278/// Overflowing addition of a scalar T to a primitive array of type T. If the
279/// result from the sum is larger than the possible number for this type, then
280/// the result will be an array with overflowed values and a validity array
281/// indicating the overflowing elements from the array
282///
283/// # Examples
284/// ```
285/// use arrow2::compute::arithmetics::basic::overflowing_add_scalar;
286/// use arrow2::array::PrimitiveArray;
287///
288/// let a = PrimitiveArray::from([Some(1i8), Some(100i8)]);
289/// let (result, overflow) = overflowing_add_scalar(&a, &100i8);
290/// let expected = PrimitiveArray::from([Some(101i8), Some(-56i8)]);
291/// assert_eq!(result, expected);
292/// ```
293pub fn overflowing_add_scalar<T>(lhs: &PrimitiveArray<T>, rhs: &T) -> (PrimitiveArray<T>, Bitmap)
294where
295 T: NativeArithmetics + OverflowingAdd<Output = T>,
296{
297 let rhs = *rhs;
298 let op = move |a: T| a.overflowing_add(&rhs);
299
300 unary_with_bitmap(lhs, op, lhs.data_type().clone())
301}
302
303// Implementation of ArrayAdd trait for PrimitiveArrays with a scalar
304impl<T> ArrayAdd<T> for PrimitiveArray<T>
305where
306 T: NativeArithmetics + Add<Output = T>,
307{
308 fn add(&self, rhs: &T) -> Self {
309 add_scalar(self, rhs)
310 }
311}
312
313// Implementation of ArrayCheckedAdd trait for PrimitiveArrays with a scalar
314impl<T> ArrayCheckedAdd<T> for PrimitiveArray<T>
315where
316 T: NativeArithmetics + CheckedAdd<Output = T>,
317{
318 fn checked_add(&self, rhs: &T) -> Self {
319 checked_add_scalar(self, rhs)
320 }
321}
322
323// Implementation of ArraySaturatingAdd trait for PrimitiveArrays with a scalar
324impl<T> ArraySaturatingAdd<T> for PrimitiveArray<T>
325where
326 T: NativeArithmetics + SaturatingAdd<Output = T>,
327{
328 fn saturating_add(&self, rhs: &T) -> Self {
329 saturating_add_scalar(self, rhs)
330 }
331}
332
333// Implementation of ArraySaturatingAdd trait for PrimitiveArrays with a scalar
334impl<T> ArrayOverflowingAdd<T> for PrimitiveArray<T>
335where
336 T: NativeArithmetics + OverflowingAdd<Output = T>,
337{
338 fn overflowing_add(&self, rhs: &T) -> (Self, Bitmap) {
339 overflowing_add_scalar(self, rhs)
340 }
341}