Skip to content
This repository has been archived by the owner on Feb 18, 2024. It is now read-only.

Commit

Permalink
Improved API
Browse files Browse the repository at this point in the history
  • Loading branch information
jorgecarleitao committed Jun 8, 2022
1 parent 1b950b9 commit cf2ea2e
Show file tree
Hide file tree
Showing 2 changed files with 22 additions and 61 deletions.
44 changes: 11 additions & 33 deletions examples/cow.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,20 @@
// This example demos how to operate on arrays in-place.
use arrow2::{
array::{Array, PrimitiveArray},
types::NativeType,
};

// this function will clone-on-write the array and apply `f` to its values
fn cow_apply<T: NativeType, F: Fn(&mut [T])>(array: &mut dyn Array, f: F) {
// 1. downcast the array to its concrete type
let array = array
.as_any_mut()
.downcast_mut::<PrimitiveArray<T>>()
.unwrap();

// 2. empty the mut reference and create a new array on the stack with its contents
let new_array = array.take();

// 3. deconstruct the array into its parts
let (dt, values, validity) = new_array.into_inner();

// 4. clone-on-write the values
let mut values = values.make_mut();

// 5. apply the function over the values
f(&mut values);

// 6. assign the new values to the array
array.try_assign(dt, values.into(), validity).unwrap();
}
use arrow2::array::{Array, PrimitiveArray};

fn main() {
// say we have have received an array
let mut array = PrimitiveArray::from_vec(vec![1i32, 2]).boxed();
let mut array: Box<dyn Array> = PrimitiveArray::from_vec(vec![1i32, 2]).boxed();

// we can apply a transformation to its values without allocating a new array as follows:
cow_apply(array.as_mut(), |values: &mut [i32]| {
values.iter_mut().for_each(|x| *x *= 10)
});
// 1. downcast it to the correct type (known via `array.data_type().to_physical_type()`)
let array = array
.as_any_mut()
.downcast_mut::<PrimitiveArray<i32>>()
.unwrap();

// 2. call `apply_values` with the function to apply over the values
array.apply_values(|x| x.iter_mut().for_each(|x| *x *= 10));

// confirm that it gives the right result :)
assert_eq!(array.as_ref(), PrimitiveArray::from_vec(vec![10i32, 20]));
assert_eq!(array, &PrimitiveArray::from_vec(vec![10i32, 20]));
}
39 changes: 11 additions & 28 deletions src/array/primitive/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,35 +253,18 @@ impl<T: NativeType> PrimitiveArray<T> {
arr
}

/// Returns a new [`PrimitiveArray`] by taking everything from this one.
#[must_use]
pub fn take(&mut self) -> Self {
let mut data_type: DataType = T::PRIMITIVE.into();
std::mem::swap(&mut self.data_type, &mut data_type);
Self {
data_type,
values: std::mem::take(&mut self.values),
validity: std::mem::take(&mut self.validity),
}
}

/// Tries to assign the arguments to itself.
/// Applies a function `f` to the values of this array, cloning the values
/// iff they are being shared with others
///
/// This function is semantically similar to [`Self::try_new`] but it can be used to populate an existing
/// Array.
/// # Errors
/// Errors iff the `data_type`'s [`PhysicalType`] is not equal to [`PhysicalType::Primitive(T::PRIMITIVE)`]
pub fn try_assign(
&mut self,
data_type: DataType,
values: Buffer<T>,
validity: Option<Bitmap>,
) -> Result<(), Error> {
check(&data_type, &self.values, &self.validity)?;
self.data_type = data_type;
self.values = values;
self.validity = validity;
Ok(())
/// This is an API to use clone-on-write
/// # Implementation
/// This function is `O(f)` if the data is not being shared, and `O(N) + O(f)`
/// if it is being shared (since it results in a `O(N)` memcopy).
pub fn apply_values<F: Fn(&mut [T])>(&mut self, f: F) {
let values = std::mem::take(&mut self.values);
let mut values = values.make_mut();
f(&mut values);
self.values = values.into();
}

/// Deconstructs this [`PrimitiveArray`] into its internal components
Expand Down

0 comments on commit cf2ea2e

Please sign in to comment.