Skip to content

Commit 5ae9920

Browse files
committed
Moves towards a reference-based implementation.
Provides a new `core` module that lays out a new internal design, and create aliases of the original `ndarray` types using that module. The module can eventually be moved into its own crate.
1 parent 5dc62e6 commit 5ae9920

File tree

5 files changed

+422
-0
lines changed

5 files changed

+422
-0
lines changed

src/core.rs

Lines changed: 133 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
//! The core types of `ndarray`, redefined in terms of the new infrastructure.
2+
//!
3+
//! The idea is partially that the `core` module / folder could be extracted
4+
//! into its own crate, but these types and implementations would remain here.
5+
6+
mod backend;
7+
mod array;
8+
mod arrayref;
9+
10+
use core::{mem, ptr::NonNull};
11+
use std::sync::Arc;
12+
13+
pub use array::*;
14+
pub use arrayref::*;
15+
pub use backend::*;
16+
17+
use crate::Dimension;
18+
19+
/// Type alias for a dynamically-allocated, unique backend.
20+
pub type VecBackend<T> = (VecOwner<T>, NonNull<T>);
21+
22+
/// This type should act almost entirely equivalently to the existing `Array`
23+
pub type Array<A, D> = OwnedBase<D, VecBackend<A>>;
24+
25+
/// Completely equivalent to [`crate::OwnedRepr`]!
26+
pub struct VecOwner<T>
27+
{
28+
ptr: NonNull<T>,
29+
len: usize,
30+
cap: usize,
31+
}
32+
33+
/// The glue implementation for this backend.
34+
unsafe impl<E> Backend for VecBackend<E>
35+
{
36+
type Elem = E;
37+
38+
type Ref = NonNull<E>;
39+
40+
type Owned = VecOwner<E>;
41+
42+
fn ref_from_owner_offset(owner: &Self::Owned, offset: isize) -> Self::Ref
43+
{
44+
todo!("unsafe {{ owner.ptr.offset(offset) }}")
45+
}
46+
}
47+
48+
/// A very simple Uniqueable, since this type is always unique.
49+
unsafe impl<A, D> Uniqueable for Array<A, D>
50+
{
51+
fn try_ensure_unique(&mut self) {}
52+
53+
fn try_is_unique(&self) -> Option<bool>
54+
{
55+
Some(true)
56+
}
57+
}
58+
59+
/// A blanket NdArray implementation for any backend whose reference type is `NonNull<A>`.
60+
///
61+
/// As described in the `arrayref` module of `core`, this kind of reference-focused `impl`
62+
/// is very ergonomic and makes sense, since most behavior relies on the reference type,
63+
/// not the owned type.
64+
unsafe impl<L, B, A> NdArray<B> for OwnedBase<L, B>
65+
where B: Backend<Ref = NonNull<A>, Elem = A>
66+
{
67+
fn as_ptr(&self) -> *mut <B as Backend>::Elem
68+
{
69+
self.aref.storage.as_ptr()
70+
}
71+
}
72+
73+
/// And now our Arc-based backend
74+
pub type ArcBackend<T> = (Arc<VecOwner<T>>, NonNull<T>);
75+
76+
/// Again, should be almost entirely equivalent to the existing `ArcArray`
77+
pub type ArcArray<A, D> = OwnedBase<D, ArcBackend<A>>;
78+
79+
/// A simple backend implementation
80+
unsafe impl<E> Backend for ArcBackend<E>
81+
{
82+
type Elem = E;
83+
84+
type Ref = NonNull<E>;
85+
86+
type Owned = Arc<VecOwner<E>>;
87+
88+
fn ref_from_owner_offset(owner: &Self::Owned, offset: isize) -> Self::Ref
89+
{
90+
todo!("unsafe {{ owner.as_ref().ptr.offset(isize) }}")
91+
}
92+
}
93+
94+
/// Uniqueable implementation, with the uniqueness logic stolen from what already exists
95+
unsafe impl<A, D: Dimension> Uniqueable for ArcArray<A, D>
96+
{
97+
fn try_ensure_unique(&mut self)
98+
{
99+
if Arc::get_mut(&mut self.own).is_some() {
100+
return;
101+
}
102+
if self.layout.size() <= self.own.len / 2 {
103+
todo!(".to_owned().to_shared()");
104+
}
105+
let ptr = self.as_ptr();
106+
let rcvec = &mut self.own;
107+
let a_size = mem::size_of::<A>() as isize;
108+
let our_off = if a_size != 0 {
109+
(ptr as isize - Arc::as_ptr(&rcvec) as isize) / a_size
110+
} else {
111+
0
112+
};
113+
self.storage = ArcBackend::<A>::ref_from_owner_offset(&mut self.own, our_off);
114+
}
115+
116+
/// We're using strong count here so that we don't need &mut self.
117+
/// This is not as strong as the original `try_is_unique`, but it doesn't matter.
118+
/// The original does not hold on to the mutable reference provided by [`Arc::get_mut`],
119+
/// so the moment the call is over the uniqueness guarantee does not hold.
120+
/// This is a weaker guarantee of instantaneous uniqueness, but neither this nor the
121+
/// original implementation are good enough to safely do anything with that uniqueness anyway.
122+
fn try_is_unique(&self) -> Option<bool>
123+
{
124+
Some(Arc::strong_count(&self.own) == 1)
125+
}
126+
}
127+
128+
/// These aliases work for a view into any array whose reference type is `NonNull`:
129+
130+
pub type ArrayView<'a, A, D> = ViewBase<'a, D, NonNull<A>, A>;
131+
pub type ArrayViewMut<'a, A, D> = ViewBaseMut<'a, D, NonNull<A>, A>;
132+
pub type RawArrayView<A, D> = RawViewBase<D, NonNull<A>, A>;
133+
pub type RawArrayViewMut<A, D> = RawViewBaseMut<D, NonNull<A>, A>;

src/core/array.rs

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
//! Owning array types.
2+
3+
use core::{fmt::Debug, marker::PhantomData};
4+
5+
use super::{
6+
arrayref::{RawRefBase, RefBase},
7+
backend::Backend,
8+
};
9+
10+
/// Base type for arrays with owning semantics.
11+
pub struct OwnedBase<L, B: Backend>
12+
{
13+
pub(super) aref: RefBase<L, B::Ref>,
14+
pub(super) own: B::Owned,
15+
}
16+
17+
/// Base type for array views.
18+
///
19+
/// Views are like references; in fact, they're just wrappers for references.
20+
/// The difference is that a reference's layout must be identical to the array
21+
/// from which is has been derived; a view's layout may be different, representing
22+
/// a segment, strided, or otherwise incomplete look at its parent array.
23+
#[derive(Debug)]
24+
pub struct ViewBase<'a, L, R, E>
25+
{
26+
aref: RefBase<L, R>,
27+
life: PhantomData<&'a E>,
28+
}
29+
30+
/// Base type for array views with mutable data.
31+
///
32+
/// All kinds of views can have their layout mutated. However, data mutation
33+
/// is tracked separately via two different types.
34+
#[derive(Debug)]
35+
pub struct ViewBaseMut<'a, L, R, E>
36+
{
37+
aref: RefBase<L, R>,
38+
life: PhantomData<&'a mut E>,
39+
}
40+
41+
/// Base type for array views without lifetimes.
42+
#[derive(Debug)]
43+
pub struct RawViewBase<L, R, E>
44+
{
45+
rref: RawRefBase<L, R>,
46+
life: PhantomData<*const E>,
47+
}
48+
49+
/// Base type for array views without lifetimes, but with mutable data.
50+
#[derive(Debug)]
51+
pub struct RawViewBaseMut<L, R, E>
52+
{
53+
rref: RawRefBase<L, R>,
54+
life: PhantomData<*const E>,
55+
}
56+
57+
/// A trait for arrays with mutable data that can be made unique.
58+
///
59+
/// Essentially all monomorphizations of [`OwnedBase`], [`ViewBaseMut`],
60+
/// and [`RawViewBaseMut`] should implement Uniqueable; this applies even
61+
/// when the array type does not have any data sharing capabilities.
62+
///
63+
/// There are already blanket implementations for `ViewBaseMut` and
64+
/// `RawViewBaseMut`; as a result, any creation of these types
65+
/// _must_ ensure that the underlying data is unique (a.k.a, unshared)
66+
/// before creating these mutable views.
67+
pub unsafe trait Uniqueable
68+
{
69+
fn try_ensure_unique(&mut self);
70+
71+
fn try_is_unique(&self) -> Option<bool>;
72+
}
73+
74+
/// Trait implemented by all the non-reference array types.
75+
///
76+
/// We'll probably want to split trait into multiple trait, for three reasons:
77+
/// 1. Adding a "Raw" and "Mut" variants will likely be necessary
78+
/// 2. We probably don't want a single trait specified by backend, but instead traits
79+
/// that are specified by reference type, owned type, and backend separately.
80+
/// This allows for blanket implementations that would otherwise be annoying.
81+
/// 3. We may want to add subtraits that break the behavior into logical pieces,
82+
/// instead of having a monolith.
83+
pub unsafe trait NdArray<B: Backend>
84+
{
85+
fn as_ptr(&self) -> *mut B::Elem;
86+
}
87+
88+
mod array_impls
89+
{
90+
use core::fmt::Debug;
91+
use core::ops::{Deref, DerefMut};
92+
93+
use crate::core::{Backend, RawRefBase, RefBase};
94+
95+
use super::{OwnedBase, RawViewBase, RawViewBaseMut, Uniqueable, ViewBase, ViewBaseMut};
96+
97+
impl<L, B: Backend> Deref for OwnedBase<L, B>
98+
{
99+
type Target = RefBase<L, B::Ref>;
100+
101+
fn deref(&self) -> &Self::Target
102+
{
103+
&self.aref
104+
}
105+
}
106+
107+
impl<L, B: Backend> DerefMut for OwnedBase<L, B>
108+
where Self: Uniqueable
109+
{
110+
fn deref_mut(&mut self) -> &mut Self::Target
111+
{
112+
self.try_ensure_unique();
113+
&mut self.aref
114+
}
115+
}
116+
117+
impl<'a, L, R, E> Deref for ViewBase<'a, L, R, E>
118+
{
119+
type Target = RefBase<L, R>;
120+
121+
fn deref(&self) -> &Self::Target
122+
{
123+
&self.aref
124+
}
125+
}
126+
127+
impl<'a, L, R, E> Deref for ViewBaseMut<'a, L, R, E>
128+
{
129+
type Target = RefBase<L, R>;
130+
131+
fn deref(&self) -> &Self::Target
132+
{
133+
&self.aref
134+
}
135+
}
136+
137+
impl<'a, L, R, E> DerefMut for ViewBaseMut<'a, L, R, E>
138+
{
139+
fn deref_mut(&mut self) -> &mut Self::Target
140+
{
141+
&mut self.aref
142+
}
143+
}
144+
145+
impl<L, R, E> Deref for RawViewBase<L, R, E>
146+
{
147+
type Target = RawRefBase<L, R>;
148+
149+
fn deref(&self) -> &Self::Target
150+
{
151+
&self.rref
152+
}
153+
}
154+
155+
impl<L, R, E> Deref for RawViewBaseMut<L, R, E>
156+
{
157+
type Target = RawRefBase<L, R>;
158+
159+
fn deref(&self) -> &Self::Target
160+
{
161+
&self.rref
162+
}
163+
}
164+
165+
impl<L, R, E> DerefMut for RawViewBaseMut<L, R, E>
166+
{
167+
fn deref_mut(&mut self) -> &mut Self::Target
168+
{
169+
&mut self.rref
170+
}
171+
}
172+
173+
unsafe impl<'a, L, R, E> Uniqueable for ViewBaseMut<'a, L, R, E>
174+
{
175+
fn try_ensure_unique(&mut self) {}
176+
177+
fn try_is_unique(&self) -> Option<bool>
178+
{
179+
Some(true)
180+
}
181+
}
182+
183+
unsafe impl<L, R, E> Uniqueable for RawViewBaseMut<L, R, E>
184+
{
185+
fn try_ensure_unique(&mut self) {}
186+
187+
fn try_is_unique(&self) -> Option<bool>
188+
{
189+
None
190+
}
191+
}
192+
193+
impl<L, B> Debug for OwnedBase<L, B>
194+
where
195+
B: Backend + Debug,
196+
B::Ref: Debug,
197+
B::Owned: Debug,
198+
L: Debug,
199+
{
200+
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
201+
{
202+
f.debug_struct("OwnedBase")
203+
.field("aref", &self.aref)
204+
.field("own", &self.own)
205+
.finish()
206+
}
207+
}
208+
}

0 commit comments

Comments
 (0)