Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add values_strided_to #47

Merged
merged 1 commit into from
Dec 30, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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]);
}
}