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 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 pub fn copy(&self) -> Self {
204 let data = self.as_slice().to_vec();
205 Self {
206 data: Arc::new(data),
207 dim: self.dim.clone(),
208 strides: self.strides.clone(),
209 offset: 0,
210 }
211 }
212
213 pub fn flags(&self) -> ArrayFlags {
215 let layout = self.layout();
216 ArrayFlags {
217 c_contiguous: layout.is_c_contiguous(),
218 f_contiguous: layout.is_f_contiguous(),
219 owndata: true, writeable: true,
221 }
222 }
223}
224
225impl<T: Element, D: Dimension> Clone for ArcArray<T, D> {
226 fn clone(&self) -> Self {
227 Self {
228 data: Arc::clone(&self.data),
229 dim: self.dim.clone(),
230 strides: self.strides.clone(),
231 offset: self.offset,
232 }
233 }
234}
235
236impl<T: Element, D: Dimension> From<Array<T, D>> for ArcArray<T, D> {
237 fn from(arr: Array<T, D>) -> Self {
238 Self::from_owned(arr)
239 }
240}
241
242fn compute_c_strides(shape: &[usize]) -> Vec<isize> {
244 let ndim = shape.len();
245 if ndim == 0 {
246 return vec![];
247 }
248 let mut strides = vec![0isize; ndim];
249 strides[ndim - 1] = 1;
250 for i in (0..ndim - 1).rev() {
251 strides[i] = strides[i + 1] * shape[i + 1] as isize;
252 }
253 strides
254}
255
256#[cfg(test)]
257mod tests {
258 use super::*;
259 use crate::dimension::{Ix1, Ix2};
260
261 #[test]
262 fn arc_from_owned() {
263 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
264 let arc = ArcArray::from_owned(arr);
265 assert_eq!(arc.shape(), &[3]);
266 assert_eq!(arc.as_slice(), &[1.0, 2.0, 3.0]);
267 assert_eq!(arc.ref_count(), 1);
268 }
269
270 #[test]
271 fn arc_clone_shares() {
272 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
273 let arc1 = ArcArray::from_owned(arr);
274 let arc2 = arc1.clone();
275 assert_eq!(arc1.ref_count(), 2);
276 assert_eq!(arc2.ref_count(), 2);
277 assert_eq!(arc1.as_ptr(), arc2.as_ptr());
278 }
279
280 #[test]
281 fn arc_cow_on_mutation() {
282 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
283 let arc1 = ArcArray::from_owned(arr);
284 let mut arc2 = arc1.clone();
285
286 assert_eq!(arc1.as_ptr(), arc2.as_ptr());
288 assert_eq!(arc1.ref_count(), 2);
289
290 arc2.as_slice_mut()[0] = 99.0;
292
293 assert_ne!(arc1.as_ptr(), arc2.as_ptr());
295 assert_eq!(arc1.as_slice(), &[1.0, 2.0, 3.0]);
296 assert_eq!(arc2.as_slice(), &[99.0, 2.0, 3.0]);
297 assert_eq!(arc1.ref_count(), 1);
298 assert_eq!(arc2.ref_count(), 1);
299 }
300
301 #[test]
302 fn arc_view_sees_old_data_after_cow() {
303 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
304 let mut arc = ArcArray::from_owned(arr);
305 let arc_clone = arc.clone();
306
307 let view = arc_clone.view();
309 assert_eq!(view.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
310
311 arc.as_slice_mut()[0] = 99.0;
313
314 assert_eq!(view.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
316 assert_eq!(arc.as_slice(), &[99.0, 2.0, 3.0]);
318 }
319
320 #[test]
321 fn arc_unique_no_clone() {
322 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
323 let mut arc = ArcArray::from_owned(arr);
324 let ptr_before = arc.as_ptr();
325
326 arc.as_slice_mut()[0] = 99.0;
328 assert_eq!(arc.as_ptr(), ptr_before);
329 assert_eq!(arc.as_slice(), &[99.0, 2.0, 3.0]);
330 }
331
332 #[test]
333 fn arc_into_owned() {
334 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0; 6]).unwrap();
335 let arc = ArcArray::from_owned(arr);
336 let owned = arc.into_owned();
337 assert_eq!(owned.shape(), &[2, 3]);
338 }
339
340 #[test]
341 fn arc_mapv_inplace() {
342 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
343 let mut arc = ArcArray::from_owned(arr);
344 arc.mapv_inplace(|x| x * 2.0);
345 assert_eq!(arc.as_slice(), &[2.0, 4.0, 6.0]);
346 }
347
348 #[test]
349 fn arc_copy_is_independent() {
350 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
351 let arc = ArcArray::from_owned(arr);
352 let copy = arc.copy();
353 assert_ne!(arc.as_ptr(), copy.as_ptr());
354 assert_eq!(arc.ref_count(), 1); assert_eq!(copy.ref_count(), 1);
356 }
357
358 #[test]
361 fn arc_from_owned_after_transpose_is_standard_layout() {
362 use crate::dimension::Ix2;
367 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
368 .unwrap();
369 let transposed = crate::manipulation::transpose(&arr, None).unwrap();
370 assert_eq!(transposed.shape(), &[3, 2]);
371 let arc = ArcArray::<f64, crate::dimension::IxDyn>::from_owned(transposed);
372 assert_eq!(arc.as_slice(), &[1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
376 }
377
378 #[test]
379 fn arc_from_owned_with_broadcast_to_materializes_data() {
380 use crate::dimension::Ix1;
384 let a = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
385 let b = crate::manipulation::broadcast_to(&a, &[2, 3]).unwrap();
386 assert_eq!(b.shape(), &[2, 3]);
387 let arc = ArcArray::<f64, crate::dimension::IxDyn>::from_owned(b);
388 assert_eq!(arc.as_slice(), &[1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
390 }
391}