rust-ndarrayの所有権周りのコードを読んだ
GPU用の多次元配列及び線形代数ライブラリをRustで作りたいと思い、rust-ndarrayのソースを読んでみた。
rust-ndarrayはarrayを所有している場合、可変参照の場合、参照の場合をそれぞれDataの持ち方に関する構造体で管理している。
データを所有している場合、OwendRepr
,データを可変参照または参照の場合はVeiwRepr
で管理している。
参照の場合はViewRepr<&'a A>
,可変参照の場合はViewRepr<&'a mut A>
になる。
それぞれに対してArray
, ArrayView
, ArrayViewMut
と型エイリアスしてある。
OwendRepr
は重いのでまず、ViewRepr
を読む。
pub struct ViewRepr<A> {
life: PhantomData<A>
}
となっていて型を消費しているだけ。
次にOwnedRepr
を読む
pub struct OwnedRepr<A> {
ptr: NonNull<A>,
len: usize,
capacity: usize
}
となっている。
実際にポインタを持っている。
でも、ArrayBase
でもポインタ持ってる。
ArrayBase
のポインタは実際に確保されているポインタからoffsetされてる可能性でもあるのかなぁ?
pub struct ArrayBase<S, D>
where
S: RawData,
{
data: S
ptr: std::ptr::NonNull<S::Elem>,
dim: D,
strides: D,
}
となっている
OwnedRepr
の中を読んでみた。
- コンストラクタ
from
- ポインタ系
as_ptr
as_ptr_mut
as_nunnull_mut
as_end_nonnull
- データ領域いじる系
reseve
set_len
- 中身いじる系
modefy_as_vec
- データ取り出す系
take_as_vec
into_vec
as_slice
len
など
データを所有してないとダメそうなやつはある気がする。
てか、RawData
とか他のクレートで制限をつけてるけどこれだけで良くない?と思ったりする
ArrayBase
のdataに関するものとしてはdata_trait.rs
内のトレイトも重要そうなので読む。
トレイトが何個かあって、以下のような関係になってるっぽい。
RawData
を読む
deeplさん頼んだ
配列表現特性。
ArrayBase型の不変量に合致する配列の場合。この特性は、いかなる所有権や寿命も意味しない。配列の要素へのポインタは、安全に参照解除できないかもしれない。
注意:RawDataは、現時点では拡張インターフェースではありません。Rustのtraitは、様々な役割を果たすことができます。この特性は、パブリックメソッドのバインドとして使用されるため、パブリックです。
よくわからない。
つまりは、ArrayBase関する特性を表すトレイトである。
ArrayBaseのinvariants(この単語は”不変”のという意味らしいがよくわからん)に当たる場合のためのもの。
このトレイトは所有権とライフタイムの情報も持たない(基底クラスだから?)
すべての所有権、ライフタイム周りの構造体にimpl
されている
メソッドは
-
_data_slice
(deprecated) _is_poionter_inbounds
がある
ArrayBaseの基底となるクラスが必要なのはわかるけど、なぜそこに_is_pointer_inbounds
が必要なのかはよくわかっていない。
あと、private_decl!()
マクロでpubなトレイトでも外部からは実装できなくなっている
RawDataMut
を読む
RawData
をトレイト境界としてもつ
書き込み可能なarrayに対するものっぽい。
メソッドは
try_ensure_unique
try_is_unique
それぞれのメソッドは、
可能であれば、そのデータへのアクセスが単一かどうかを返すメソッドである。
try_ensure_unique
に関してはOwendArcRepr
とCowRepr
以外はそのまま返している。
そのトレイとが実装されている場合はデータへのアクセスはユニークである。
同様に、try_is_unique
もOwnedArcRepr
とCowRepr
以外はSome(true)を実装する
impl
されているのは
OwnedRepr
ViewRepr<&'a mut A>
ほかの部分は後で読む
RawDataMut
が実装されているものに関してはもともとそのオブジェクトを作成する際に、
mut
であることがわかっているのでこのトレイとの必要性がよくわからない。
RawView
やOwnedArcRepr
などではチェックが入る場合があるっぽいからのそのためなのかねぇ?
RawDataClone
名前の通りCloneできるものに対して実装する
impl
されているのは
OwnedRepr
ViewPrepr<&'a A>
Data
データへのアクセスをsafeに行える
データへのアクセスがsafeであることとinto_owed
とtry_into_onwed_nocopy
とto_shared
の関連性がよくわからない。
どちらかというと、所有していないArrayBase
を所有するためのトレイトなような気がする
DataMut
Data + RawDataMut
safeにデータにアクセスすることが可能でなおかつ書き換え可能なトレイトであること
ここまで読んでいた感想としては、ArcArrayのための昨日が大きいのでは?という気がする
ほかならそんなに気にせず使えるような気がする
git grep S::
してみる(RawData系のトレイトを使われている先を探す)
ndarray-rand/src/lib.rs: IdS: Distribution<S::Elem>,
ndarray-rand/src/lib.rs: IdS: Distribution<S::Elem>,
ndarray-rand/src/lib.rs: IdS: Distribution<S::Elem>,
ndarray-rand/src/lib.rs: IdS: Distribution<S::Elem>,
src/array_serde.rs: fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
src/arraytraits.rs: type Output = S::Elem;
src/arraytraits.rs: fn index(&self, index: I) -> &S::Elem {
src/arraytraits.rs: fn index_mut(&mut self, index: I) -> &mut S::Elem {
src/arraytraits.rs: S::Elem: Eq,
src/arraytraits.rs: type Item = &'a S::Elem;
src/arraytraits.rs: type IntoIter = Iter<'a, S::Elem, D>;
src/arraytraits.rs: type Item = &'a mut S::Elem;
src/arraytraits.rs: type IntoIter = IterMut<'a, S::Elem, D>;
src/arraytraits.rs: S::Elem: hash::Hash,
src/impl_constructors.rs: pub fn uninit<Sh>(shape: Sh) -> ArrayBase<S::MaybeUninit, D>
src/impl_constructors.rs: pub fn build_uninit<Sh, F>(shape: Sh, builder: F) -> ArrayBase<S::MaybeUninit, D>
src/impl_methods.rs: S::to_shared(self)
src/impl_methods.rs: S::into_owned(self)
src/impl_methods.rs: S::try_into_owned_nocopy(self)
src/impl_methods.rs: S::try_ensure_unique(self);
src/impl_methods.rs: S::ensure_unique(self);
src/impl_special_element_types.rs: let data = S::data_subst(data);
src/lib.rs:/// fn fill_lower<S, D>(arr: &mut ArrayBase<S, D>, x: S::Elem)
src/lib.rs:/// S::Elem: Clone,
src/lib.rs: ptr: std::ptr::NonNull<S::Elem>,
src/linalg/impl_linalg.rs: S::Elem: 'static,
src/linalg/impl_linalg.rs: if !same_type::<A, S::Elem>() {
src/linalg/impl_linalg.rs: S::Elem: 'static,
src/linalg/impl_linalg.rs: if !same_type::<A, S::Elem>() {
src/linalg/impl_linalg.rs: S::Elem: 'static,
src/linalg/impl_linalg.rs: if !same_type::<A, S::Elem>() {
src/linalg/impl_linalg.rs: S::Elem: 'static,
tests/array.rs: S::Elem: Clone + Debug + PartialEq,
ensure_unique
やtry_ensure_unique
はViewRepr
やOnwedRepr
では必ず同じものを返す
つまりは、Arc
やRaw
をいい感じに扱うためにできたものである可能性が高い