Skip to content

Commit

Permalink
Merge pull request #47 from magnusuMET/values_strided_to
Browse files Browse the repository at this point in the history
add values_strided_to
  • Loading branch information
magnusuMET committed Dec 30, 2019
2 parents fdbb569 + e038054 commit 5839d36
Show file tree
Hide file tree
Showing 3 changed files with 237 additions and 12 deletions.
2 changes: 1 addition & 1 deletion src/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ impl std::ops::Deref for ReadOnlyFile {
impl ReadOnlyFile {
pub(crate) fn open(path: &path::Path) -> error::Result<Self> {
Ok(Self {
file: File::open(path)?
file: File::open(path)?,
})
}
}
Expand Down
169 changes: 158 additions & 11 deletions src/variable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,26 @@ where
slice_len: &[usize],
values: &[Self],
) -> error::Result<()>;

/// get a SLICE of values into the variable, with the source
/// strided by `strides`
unsafe fn get_values_strided(
variable: &Variable,
indices: &[usize],
slice_len: &[usize],
strides: &[isize],
values: *mut Self,
) -> error::Result<()>;

/// put a SLICE of values into the variable, with the destination
/// strided by `strides`
unsafe fn put_values_strided(
variable: &mut Variable,
indices: &[usize],
slice_len: &[usize],
strides: &[isize],
values: *const Self,
) -> error::Result<()>;
}

#[allow(clippy::doc_markdown)]
Expand All @@ -353,7 +373,10 @@ macro_rules! impl_numeric {
$nc_get_vara_type: ident,
$nc_get_var1_type: ident,
$nc_put_var1_type: ident,
$nc_put_vara_type: ident) => {
$nc_put_vara_type: ident,
$nc_get_vars_type: ident,
$nc_put_vars_type: ident,
) => {
#[allow(clippy::use_self)] // False positives
unsafe impl Numeric for $sized_type {
const NCTYPE: nc_type = $nc_type;
Expand Down Expand Up @@ -425,6 +448,42 @@ macro_rules! impl_numeric {
values.as_ptr(),
))
}

unsafe fn get_values_strided(
variable: &Variable,
indices: &[usize],
slice_len: &[usize],
strides: &[isize],
values: *mut Self,
) -> error::Result<()> {
let _l = LOCK.lock().unwrap();
error::checked($nc_get_vars_type(
variable.ncid,
variable.varid,
indices.as_ptr(),
slice_len.as_ptr(),
strides.as_ptr(),
values,
))
}

unsafe fn put_values_strided(
variable: &mut Variable,
indices: &[usize],
slice_len: &[usize],
strides: &[isize],
values: *const Self,
) -> error::Result<()> {
let _l = LOCK.lock().unwrap();
error::checked($nc_put_vars_type(
variable.ncid,
variable.varid,
indices.as_ptr(),
slice_len.as_ptr(),
strides.as_ptr(),
values,
))
}
}
};
}
Expand All @@ -435,7 +494,9 @@ impl_numeric!(
nc_get_vara_uchar,
nc_get_var1_uchar,
nc_put_var1_uchar,
nc_put_vara_uchar
nc_put_vara_uchar,
nc_get_vars_uchar,
nc_put_vars_uchar,
);

impl_numeric!(
Expand All @@ -445,7 +506,9 @@ impl_numeric!(
nc_get_vara_schar,
nc_get_var1_schar,
nc_put_var1_schar,
nc_put_vara_schar
nc_put_vara_schar,
nc_get_vars_schar,
nc_put_vars_schar,
);

impl_numeric!(
Expand All @@ -455,7 +518,9 @@ impl_numeric!(
nc_get_vara_short,
nc_get_var1_short,
nc_put_var1_short,
nc_put_vara_short
nc_put_vara_short,
nc_get_vars_short,
nc_put_vars_short,
);

impl_numeric!(
Expand All @@ -465,7 +530,9 @@ impl_numeric!(
nc_get_vara_ushort,
nc_get_var1_ushort,
nc_put_var1_ushort,
nc_put_vara_ushort
nc_put_vara_ushort,
nc_get_vars_ushort,
nc_put_vars_ushort,
);

impl_numeric!(
Expand All @@ -475,7 +542,9 @@ impl_numeric!(
nc_get_vara_int,
nc_get_var1_int,
nc_put_var1_int,
nc_put_vara_int
nc_put_vara_int,
nc_get_vars_int,
nc_put_vars_int,
);

impl_numeric!(
Expand All @@ -485,7 +554,9 @@ impl_numeric!(
nc_get_vara_uint,
nc_get_var1_uint,
nc_put_var1_uint,
nc_put_vara_uint
nc_put_vara_uint,
nc_get_vars_uint,
nc_put_vars_uint,
);

impl_numeric!(
Expand All @@ -495,7 +566,9 @@ impl_numeric!(
nc_get_vara_longlong,
nc_get_var1_longlong,
nc_put_var1_longlong,
nc_put_vara_longlong
nc_put_vara_longlong,
nc_get_vars_longlong,
nc_put_vars_longlong,
);

impl_numeric!(
Expand All @@ -505,7 +578,9 @@ impl_numeric!(
nc_get_vara_ulonglong,
nc_get_var1_ulonglong,
nc_put_var1_ulonglong,
nc_put_vara_ulonglong
nc_put_vara_ulonglong,
nc_get_vars_ulonglong,
nc_put_vars_ulonglong,
);

impl_numeric!(
Expand All @@ -515,7 +590,9 @@ impl_numeric!(
nc_get_vara_float,
nc_get_var1_float,
nc_put_var1_float,
nc_put_vara_float
nc_put_vara_float,
nc_get_vars_float,
nc_put_vars_float,
);

impl_numeric!(
Expand All @@ -525,7 +602,9 @@ impl_numeric!(
nc_get_vara_double,
nc_get_var1_double,
nc_put_var1_double,
nc_put_vara_double
nc_put_vara_double,
nc_get_vars_double,
nc_put_vars_double,
);

/// Holds the contents of a netcdf string. Use deref to get a `CStr`
Expand Down Expand Up @@ -708,6 +787,74 @@ impl Variable {
unsafe { T::variable_to_ptr(self, indices, slice_len, buffer.as_mut_ptr()) }
}

/// Fetches variable into slice
/// buffer must be able to hold all the requested elements
pub fn values_strided_to<T: Numeric>(
&self,
buffer: &mut [T],
indices: Option<&[usize]>,
slice_len: Option<&[usize]>,
strides: &[isize],
) -> error::Result<usize> {
if strides.len() != self.dimensions.len() {
return Err("stride_mismatch".into());
}
let indices_: Vec<usize>;
let indices = if let Some(x) = indices {
self.check_indices(x, false)?;
x
} else {
indices_ = self.default_indices(false)?;
&indices_
};

let slice_len_: Vec<usize>;
let slice_len = if let Some(slice_len) = slice_len {
if slice_len.len() != self.dimensions.len() {
return Err("slice mismatch".into());
}
for (((d, &start), &count), &stride) in self
.dimensions
.iter()
.zip(indices)
.zip(slice_len)
.zip(strides)
{
if start as isize + (count as isize - 1) * stride > d.len() as isize {
return Err(error::Error::IndexMismatch);
}
if start as isize + count as isize * stride < 0 {
return Err(error::Error::IndexMismatch);
}
}
slice_len
} else {
slice_len_ = self
.dimensions
.iter()
.zip(indices)
.zip(strides)
.map(|((d, &start), &stride)| {
if stride == 0 {
1
} else if stride < 0 {
start / stride.abs() as usize
} else {
let dlen = d.len();
let round_up = stride.abs() as usize - 1;
(dlen - start + round_up) / stride.abs() as usize
}
})
.collect::<Vec<_>>();
&slice_len_
};
if buffer.len() < slice_len.iter().product() {
return Err("buffer too small".into());
}
unsafe { T::get_values_strided(self, indices, &slice_len, strides, buffer.as_mut_ptr())? };
Ok(slice_len.iter().product())
}

/// Put a single value at `indices`
pub fn put_value<T: Numeric>(
&mut self,
Expand Down
78 changes: 78 additions & 0 deletions tests/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1598,3 +1598,81 @@ fn set_get_endian() {
}
}
}

mod strided {
#[test]
fn get_to_buffer() {
let d = tempfile::tempdir().unwrap();
let name = d.path().join("strided_buffer.nc");
{
let mut file = netcdf::create(&name).unwrap();
file.add_dimension("z", 3).unwrap();
file.add_dimension("y", 5).unwrap();
file.add_dimension("x", 9).unwrap();
let var = file.add_variable::<i32>("data", &["z", "y", "x"]).unwrap();
let buffer = (0..3 * 5 * 9).collect::<Vec<_>>();
var.put_values(&buffer, None, None).unwrap();
}
let file = netcdf::open(name).unwrap();
let var = file.variable("data").unwrap();

let mut buffer = vec![0; 3 * 5 * 9];
var.values_strided_to(&mut buffer, None, None, &[1, 1, 1])
.unwrap();
assert_eq!(&buffer, &(0..3 * 5 * 9).collect::<Vec<_>>());
// Negative and zero strides seems not to be supported
// var.values_strided_to(&mut buffer, None, None, &[0, 0, 0]).unwrap();
// var.values_strided_to(&mut buffer, None, None, &[-1, -1, -1]).unwrap();
let mut buffer = vec![0; 3 * 5 * 2];
var.values_strided_to(&mut buffer, None, None, &[2, 1, 3])
.unwrap();
assert_eq!(
buffer,
&[
0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 90, 93, 96, 99, 102, 105,
108, 111, 114, 117, 120, 123, 126, 129, 132
]
);

let mut buffer = vec![0; 3 * 5 * 2];
var.values_strided_to(&mut buffer, Some(&[0, 0, 0]), None, &[2, 1, 3])
.unwrap();
assert_eq!(
buffer,
&[
0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 90, 93, 96, 99, 102, 105,
108, 111, 114, 117, 120, 123, 126, 129, 132
]
);

let mut buffer = vec![0; 3 * 5 * 2];
var.values_strided_to(&mut buffer, None, Some(&[2, 5, 3]), &[2, 1, 3])
.unwrap();
assert_eq!(
buffer,
&[
0, 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 90, 93, 96, 99, 102, 105,
108, 111, 114, 117, 120, 123, 126, 129, 132
]
);

let mut buffer = vec![0; 3 * 5 * 2];
var.values_strided_to(&mut buffer, None, Some(&[2, 5, 4]), &[2, 1, 3])
.unwrap_err();

let mut buffer = vec![0; 3 * 5 * 2];
let l = var
.values_strided_to(&mut buffer, Some(&[2, 0, 4]), None, &[2, 1, 3])
.unwrap();
assert_eq!(
&buffer[..l],
&[94, 97, 103, 106, 112, 115, 121, 124, 130, 133]
);

let mut buffer = vec![0; 3 * 5 * 2];
let l = var
.values_strided_to(&mut buffer, Some(&[2, 0, 4]), Some(&[1, 2, 2]), &[2, 1, 3])
.unwrap();
assert_eq!(&buffer[..l], &[94, 97, 103, 106]);
}
}

0 comments on commit 5839d36

Please sign in to comment.