Skip to content

Commit

Permalink
FEAT: Add MathCell, a wrapper for std Cell
Browse files Browse the repository at this point in the history
This will be used so that we can implement arithmetic ops for the views
with cells in them and for cells.
  • Loading branch information
bluss committed Jan 8, 2021
1 parent 551ee28 commit a39fa37
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 7 deletions.
4 changes: 2 additions & 2 deletions src/impl_methods.rs
Expand Up @@ -6,7 +6,6 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cell::Cell;
use std::ptr as std_ptr;
use std::slice;

Expand All @@ -21,6 +20,7 @@ use crate::dimension::{
abs_index, axes_of, do_slice, merge_axes, size_of_shape_checked, stride_offset, Axes,
};
use crate::error::{self, ErrorKind, ShapeError};
use crate::math_cell::MathCell;
use crate::itertools::zip;
use crate::zip::Zip;

Expand Down Expand Up @@ -159,7 +159,7 @@ where
///
/// The view acts "as if" the elements are temporarily in cells, and elements
/// can be changed through shared references using the regular cell methods.
pub fn cell_view(&mut self) -> ArrayView<'_, Cell<A>, D>
pub fn cell_view(&mut self) -> ArrayView<'_, MathCell<A>, D>
where
S: DataMut,
{
Expand Down
10 changes: 5 additions & 5 deletions src/impl_views/conversions.rs
Expand Up @@ -6,14 +6,14 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::cell::Cell;
use std::slice;

use crate::imp_prelude::*;

use crate::{Baseiter, ElementsBase, ElementsBaseMut, Iter, IterMut};

use crate::iter::{self, AxisIter, AxisIterMut};
use crate::math_cell::MathCell;
use crate::IndexLonger;

/// Methods for read-only array views.
Expand Down Expand Up @@ -125,12 +125,12 @@ where
///
/// The view acts "as if" the elements are temporarily in cells, and elements
/// can be changed through shared references using the regular cell methods.
pub fn into_cell_view(self) -> ArrayView<'a, Cell<A>, D> {
pub fn into_cell_view(self) -> ArrayView<'a, MathCell<A>, D> {
// safety: valid because
// A and Cell<A> have the same representation
// &'a mut T is interchangeable with &'a Cell<T> -- see method Cell::from_mut
// A and MathCell<A> have the same representation
// &'a mut T is interchangeable with &'a Cell<T> -- see method Cell::from_mut in std
unsafe {
self.into_raw_view_mut().cast::<Cell<A>>().deref_into_view()
self.into_raw_view_mut().cast::<MathCell<A>>().deref_into_view()
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Expand Up @@ -139,6 +139,7 @@ pub use crate::linalg_traits::LinalgScalar;

pub use crate::stacking::{concatenate, stack, stack_new_axis};

pub use crate::math_cell::MathCell;
pub use crate::impl_views::IndexLonger;
pub use crate::shape_builder::{Shape, ShapeBuilder, StrideShape};

Expand Down Expand Up @@ -180,6 +181,7 @@ mod layout;
mod linalg_traits;
mod linspace;
mod logspace;
mod math_cell;
mod numeric_util;
mod partial;
mod shape_builder;
Expand Down
102 changes: 102 additions & 0 deletions src/math_cell.rs
@@ -0,0 +1,102 @@

use std::cell::Cell;
use std::cmp::Ordering;
use std::fmt;

use std::ops::{Deref, DerefMut};

/// A transparent wrapper of [`Cell<T>`](std::cell::Cell) which is identical in every way, except
/// it will implement arithmetic operators as well.
///
/// The purpose of `MathCell` is to be used from [.cell_view()](crate::ArrayBase::cell_view).
/// The `MathCell` derefs to `Cell`, so all the cell's methods are available.
#[repr(transparent)]
#[derive(Default)]
pub struct MathCell<T>(Cell<T>);

impl<T> MathCell<T> {
/// Create a new cell with the given value
#[inline(always)]
pub const fn new(value: T) -> Self { MathCell(Cell::new(value)) }

/// Return the inner value
pub fn into_inner(self) -> T { Cell::into_inner(self.0) }

/// Swap value with another cell
pub fn swap(&self, other: &Self) {
Cell::swap(&self.0, &other.0)
}
}

impl<T> Deref for MathCell<T> {
type Target = Cell<T>;
#[inline(always)]
fn deref(&self) -> &Self::Target { &self.0 }
}

impl<T> DerefMut for MathCell<T> {
#[inline(always)]
fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 }
}

impl<T> Clone for MathCell<T>
where T: Copy
{
fn clone(&self) -> Self {
MathCell::new(self.get())
}
}

impl<T> PartialEq for MathCell<T>
where T: Copy + PartialEq
{
fn eq(&self, rhs: &Self) -> bool {
self.get() == rhs.get()
}
}

impl<T> Eq for MathCell<T>
where T: Copy + Eq
{ }

impl<T> PartialOrd for MathCell<T>
where T: Copy + PartialOrd
{
fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
self.get().partial_cmp(&rhs.get())
}

fn lt(&self, rhs: &Self) -> bool { self.get().lt(&rhs.get()) }
fn le(&self, rhs: &Self) -> bool { self.get().le(&rhs.get()) }
fn gt(&self, rhs: &Self) -> bool { self.get().gt(&rhs.get()) }
fn ge(&self, rhs: &Self) -> bool { self.get().ge(&rhs.get()) }
}

impl<T> Ord for MathCell<T>
where T: Copy + Ord
{
fn cmp(&self, rhs: &Self) -> Ordering {
self.get().cmp(&rhs.get())
}
}

impl<T> fmt::Debug for MathCell<T>
where T: Copy + fmt::Debug
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.get().fmt(f)
}
}


#[cfg(test)]
mod tests {
use super::MathCell;

#[test]
fn test_basic() {
let c = &MathCell::new(0);
c.set(1);
assert_eq!(c.get(), 1);
}
}

0 comments on commit a39fa37

Please sign in to comment.