1use std::sync::Arc;
4
5use crate::dimension::Dimension;
6use crate::dtype::Element;
7use crate::layout::MemoryLayout;
8
9use super::ArrayFlags;
10use super::owned::Array;
11use super::view::ArrayView;
12
13pub struct ArcArray<T: Element, D: Dimension> {
21 data: Arc<Vec<T>>,
23 dim: D,
25 strides: Vec<isize>,
27 offset: usize,
29}
30
31impl<T: Element, D: Dimension> ArcArray<T, D> {
32 pub fn from_owned(arr: Array<T, D>) -> Self {
37 let dim = arr.dim.clone();
38 let original_strides: Vec<isize> = arr.inner.strides().to_vec();
39
40 if arr.inner.is_standard_layout() {
41 let data = arr.inner.into_raw_vec_and_offset().0;
43 Self {
44 data: Arc::new(data),
45 dim,
46 strides: original_strides,
47 offset: 0,
48 }
49 } else {
50 let shape = dim.as_slice();
52 let is_f = crate::layout::detect_layout(shape, &original_strides)
53 == crate::layout::MemoryLayout::Fortran;
54
55 if is_f {
56 let data = arr.inner.into_raw_vec_and_offset().0;
59 Self {
60 data: Arc::new(data),
61 dim,
62 strides: original_strides,
63 offset: 0,
64 }
65 } else {
66 let contiguous = arr.inner.as_standard_layout().into_owned();
68 let data = contiguous.into_raw_vec_and_offset().0;
69 let strides = compute_c_strides(shape);
70 Self {
71 data: Arc::new(data),
72 dim,
73 strides,
74 offset: 0,
75 }
76 }
77 }
78 }
79
80 #[inline]
82 pub fn shape(&self) -> &[usize] {
83 self.dim.as_slice()
84 }
85
86 #[inline]
88 pub fn ndim(&self) -> usize {
89 self.dim.ndim()
90 }
91
92 #[inline]
94 pub fn size(&self) -> usize {
95 self.dim.size()
96 }
97
98 #[inline]
100 pub fn is_empty(&self) -> bool {
101 self.size() == 0
102 }
103
104 #[inline]
106 pub fn strides(&self) -> &[isize] {
107 &self.strides
108 }
109
110 pub fn layout(&self) -> MemoryLayout {
112 crate::layout::detect_layout(self.dim.as_slice(), &self.strides)
113 }
114
115 #[inline]
117 pub const fn dim(&self) -> &D {
118 &self.dim
119 }
120
121 pub fn ref_count(&self) -> usize {
123 Arc::strong_count(&self.data)
124 }
125
126 pub fn is_unique(&self) -> bool {
128 Arc::strong_count(&self.data) == 1
129 }
130
131 pub fn as_slice(&self) -> &[T] {
133 &self.data[self.offset..self.offset + self.size()]
134 }
135
136 #[inline]
138 pub fn as_ptr(&self) -> *const T {
139 self.as_slice().as_ptr()
140 }
141
142 pub fn view(&self) -> ArrayView<'_, T, D> {
148 let nd_dim = self.dim.to_ndarray_dim();
149 let slice = self.as_slice();
150 let nd_view = ndarray::ArrayView::from_shape(nd_dim, slice)
151 .expect("ArcArray data should be consistent with shape");
152 ArrayView::from_ndarray(nd_view)
153 }
154
155 fn make_unique(&mut self) {
160 if Arc::strong_count(&self.data) > 1 {
161 let slice = &self.data[self.offset..self.offset + self.size()];
162 self.data = Arc::new(slice.to_vec());
163 self.offset = 0;
164 }
165 }
166
167 pub fn as_slice_mut(&mut self) -> &mut [T] {
169 self.make_unique();
170 let size = self.size();
171 let offset = self.offset;
172 Arc::get_mut(&mut self.data)
173 .expect("make_unique should ensure refcount == 1")
174 .get_mut(offset..offset + size)
175 .expect("offset + size should be in bounds")
176 }
177
178 pub fn mapv_inplace(&mut self, f: impl Fn(T) -> T) {
180 self.make_unique();
181 let size = self.size();
182 let offset = self.offset;
183 let data = Arc::get_mut(&mut self.data).expect("unique after make_unique");
184 for elem in &mut data[offset..offset + size] {
185 *elem = f(elem.clone());
186 }
187 }
188
189 pub fn into_owned(self) -> Array<T, D> {
191 let data: Vec<T> = if self.offset == 0 && self.data.len() == self.size() {
192 match Arc::try_unwrap(self.data) {
193 Ok(v) => v,
194 Err(arc) => arc[..].to_vec(),
195 }
196 } else {
197 self.data[self.offset..self.offset + self.size()].to_vec()
198 };
199 Array::from_vec(self.dim, data).expect("data should match shape")
200 }
201
202 #[must_use]
204 pub fn copy(&self) -> Self {
205 let data = self.as_slice().to_vec();
206 Self {
207 data: Arc::new(data),
208 dim: self.dim.clone(),
209 strides: self.strides.clone(),
210 offset: 0,
211 }
212 }
213
214 pub fn flags(&self) -> ArrayFlags {
216 let layout = self.layout();
217 ArrayFlags {
218 c_contiguous: layout.is_c_contiguous(),
219 f_contiguous: layout.is_f_contiguous(),
220 owndata: true, writeable: true,
222 }
223 }
224}
225
226impl<T: Element, D: Dimension> Clone for ArcArray<T, D> {
227 fn clone(&self) -> Self {
228 Self {
229 data: Arc::clone(&self.data),
230 dim: self.dim.clone(),
231 strides: self.strides.clone(),
232 offset: self.offset,
233 }
234 }
235}
236
237impl<T: Element, D: Dimension> From<Array<T, D>> for ArcArray<T, D> {
238 fn from(arr: Array<T, D>) -> Self {
239 Self::from_owned(arr)
240 }
241}
242
243fn compute_c_strides(shape: &[usize]) -> Vec<isize> {
245 let ndim = shape.len();
246 if ndim == 0 {
247 return vec![];
248 }
249 let mut strides = vec![0isize; ndim];
250 strides[ndim - 1] = 1;
251 for i in (0..ndim - 1).rev() {
252 strides[i] = strides[i + 1] * shape[i + 1] as isize;
253 }
254 strides
255}
256
257#[cfg(test)]
258mod tests {
259 use super::*;
260 use crate::dimension::{Ix1, Ix2};
261
262 #[test]
263 fn arc_from_owned() {
264 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
265 let arc = ArcArray::from_owned(arr);
266 assert_eq!(arc.shape(), &[3]);
267 assert_eq!(arc.as_slice(), &[1.0, 2.0, 3.0]);
268 assert_eq!(arc.ref_count(), 1);
269 }
270
271 #[test]
272 fn arc_clone_shares() {
273 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
274 let arc1 = ArcArray::from_owned(arr);
275 let arc2 = arc1.clone();
276 assert_eq!(arc1.ref_count(), 2);
277 assert_eq!(arc2.ref_count(), 2);
278 assert_eq!(arc1.as_ptr(), arc2.as_ptr());
279 }
280
281 #[test]
282 fn arc_cow_on_mutation() {
283 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
284 let arc1 = ArcArray::from_owned(arr);
285 let mut arc2 = arc1.clone();
286
287 assert_eq!(arc1.as_ptr(), arc2.as_ptr());
289 assert_eq!(arc1.ref_count(), 2);
290
291 arc2.as_slice_mut()[0] = 99.0;
293
294 assert_ne!(arc1.as_ptr(), arc2.as_ptr());
296 assert_eq!(arc1.as_slice(), &[1.0, 2.0, 3.0]);
297 assert_eq!(arc2.as_slice(), &[99.0, 2.0, 3.0]);
298 assert_eq!(arc1.ref_count(), 1);
299 assert_eq!(arc2.ref_count(), 1);
300 }
301
302 #[test]
303 fn arc_view_sees_old_data_after_cow() {
304 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
305 let mut arc = ArcArray::from_owned(arr);
306 let arc_clone = arc.clone();
307
308 let view = arc_clone.view();
310 assert_eq!(view.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
311
312 arc.as_slice_mut()[0] = 99.0;
314
315 assert_eq!(view.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
317 assert_eq!(arc.as_slice(), &[99.0, 2.0, 3.0]);
319 }
320
321 #[test]
322 fn arc_unique_no_clone() {
323 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
324 let mut arc = ArcArray::from_owned(arr);
325 let ptr_before = arc.as_ptr();
326
327 arc.as_slice_mut()[0] = 99.0;
329 assert_eq!(arc.as_ptr(), ptr_before);
330 assert_eq!(arc.as_slice(), &[99.0, 2.0, 3.0]);
331 }
332
333 #[test]
334 fn arc_into_owned() {
335 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0; 6]).unwrap();
336 let arc = ArcArray::from_owned(arr);
337 let owned = arc.into_owned();
338 assert_eq!(owned.shape(), &[2, 3]);
339 }
340
341 #[test]
342 fn arc_mapv_inplace() {
343 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
344 let mut arc = ArcArray::from_owned(arr);
345 arc.mapv_inplace(|x| x * 2.0);
346 assert_eq!(arc.as_slice(), &[2.0, 4.0, 6.0]);
347 }
348
349 #[test]
350 fn arc_copy_is_independent() {
351 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
352 let arc = ArcArray::from_owned(arr);
353 let copy = arc.copy();
354 assert_ne!(arc.as_ptr(), copy.as_ptr());
355 assert_eq!(arc.ref_count(), 1); assert_eq!(copy.ref_count(), 1);
357 }
358
359 #[test]
362 fn arc_from_owned_after_transpose_is_standard_layout() {
363 use crate::dimension::Ix2;
368 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
369 .unwrap();
370 let transposed = crate::manipulation::transpose(&arr, None).unwrap();
371 assert_eq!(transposed.shape(), &[3, 2]);
372 let arc = ArcArray::<f64, crate::dimension::IxDyn>::from_owned(transposed);
373 assert_eq!(arc.as_slice(), &[1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
377 }
378
379 #[test]
380 fn arc_from_owned_with_broadcast_to_materializes_data() {
381 use crate::dimension::Ix1;
385 let a = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
386 let b = crate::manipulation::broadcast_to(&a, &[2, 3]).unwrap();
387 assert_eq!(b.shape(), &[2, 3]);
388 let arc = ArcArray::<f64, crate::dimension::IxDyn>::from_owned(b);
389 assert_eq!(arc.as_slice(), &[1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
391 }
392}