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 aligned: true,
225 }
226 }
227}
228
229impl<T: Element, D: Dimension> Clone for ArcArray<T, D> {
230 fn clone(&self) -> Self {
231 Self {
232 data: Arc::clone(&self.data),
233 dim: self.dim.clone(),
234 strides: self.strides.clone(),
235 offset: self.offset,
236 }
237 }
238}
239
240impl<T: Element, D: Dimension> From<Array<T, D>> for ArcArray<T, D> {
241 fn from(arr: Array<T, D>) -> Self {
242 Self::from_owned(arr)
243 }
244}
245
246fn compute_c_strides(shape: &[usize]) -> Vec<isize> {
248 let ndim = shape.len();
249 if ndim == 0 {
250 return vec![];
251 }
252 let mut strides = vec![0isize; ndim];
253 strides[ndim - 1] = 1;
254 for i in (0..ndim - 1).rev() {
255 strides[i] = strides[i + 1] * shape[i + 1] as isize;
256 }
257 strides
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263 use crate::dimension::{Ix1, Ix2};
264
265 #[test]
266 fn arc_from_owned() {
267 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
268 let arc = ArcArray::from_owned(arr);
269 assert_eq!(arc.shape(), &[3]);
270 assert_eq!(arc.as_slice(), &[1.0, 2.0, 3.0]);
271 assert_eq!(arc.ref_count(), 1);
272 }
273
274 #[test]
275 fn arc_clone_shares() {
276 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
277 let arc1 = ArcArray::from_owned(arr);
278 let arc2 = arc1.clone();
279 assert_eq!(arc1.ref_count(), 2);
280 assert_eq!(arc2.ref_count(), 2);
281 assert_eq!(arc1.as_ptr(), arc2.as_ptr());
282 }
283
284 #[test]
285 fn arc_cow_on_mutation() {
286 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
287 let arc1 = ArcArray::from_owned(arr);
288 let mut arc2 = arc1.clone();
289
290 assert_eq!(arc1.as_ptr(), arc2.as_ptr());
292 assert_eq!(arc1.ref_count(), 2);
293
294 arc2.as_slice_mut()[0] = 99.0;
296
297 assert_ne!(arc1.as_ptr(), arc2.as_ptr());
299 assert_eq!(arc1.as_slice(), &[1.0, 2.0, 3.0]);
300 assert_eq!(arc2.as_slice(), &[99.0, 2.0, 3.0]);
301 assert_eq!(arc1.ref_count(), 1);
302 assert_eq!(arc2.ref_count(), 1);
303 }
304
305 #[test]
306 fn arc_view_sees_old_data_after_cow() {
307 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
308 let mut arc = ArcArray::from_owned(arr);
309 let arc_clone = arc.clone();
310
311 let view = arc_clone.view();
313 assert_eq!(view.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
314
315 arc.as_slice_mut()[0] = 99.0;
317
318 assert_eq!(view.as_slice().unwrap(), &[1.0, 2.0, 3.0]);
320 assert_eq!(arc.as_slice(), &[99.0, 2.0, 3.0]);
322 }
323
324 #[test]
325 fn arc_unique_no_clone() {
326 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
327 let mut arc = ArcArray::from_owned(arr);
328 let ptr_before = arc.as_ptr();
329
330 arc.as_slice_mut()[0] = 99.0;
332 assert_eq!(arc.as_ptr(), ptr_before);
333 assert_eq!(arc.as_slice(), &[99.0, 2.0, 3.0]);
334 }
335
336 #[test]
337 fn arc_into_owned() {
338 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0; 6]).unwrap();
339 let arc = ArcArray::from_owned(arr);
340 let owned = arc.into_owned();
341 assert_eq!(owned.shape(), &[2, 3]);
342 }
343
344 #[test]
345 fn arc_mapv_inplace() {
346 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
347 let mut arc = ArcArray::from_owned(arr);
348 arc.mapv_inplace(|x| x * 2.0);
349 assert_eq!(arc.as_slice(), &[2.0, 4.0, 6.0]);
350 }
351
352 #[test]
353 fn arc_copy_is_independent() {
354 let arr = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
355 let arc = ArcArray::from_owned(arr);
356 let copy = arc.copy();
357 assert_ne!(arc.as_ptr(), copy.as_ptr());
358 assert_eq!(arc.ref_count(), 1); assert_eq!(copy.ref_count(), 1);
360 }
361
362 #[test]
365 fn arc_from_owned_after_transpose_is_standard_layout() {
366 use crate::dimension::Ix2;
371 let arr = Array::<f64, Ix2>::from_vec(Ix2::new([2, 3]), vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0])
372 .unwrap();
373 let transposed = crate::manipulation::transpose(&arr, None).unwrap();
374 assert_eq!(transposed.shape(), &[3, 2]);
375 let arc = ArcArray::<f64, crate::dimension::IxDyn>::from_owned(transposed);
376 assert_eq!(arc.as_slice(), &[1.0, 4.0, 2.0, 5.0, 3.0, 6.0]);
380 }
381
382 #[test]
383 fn arc_from_owned_with_broadcast_to_materializes_data() {
384 use crate::dimension::Ix1;
388 let a = Array::<f64, Ix1>::from_vec(Ix1::new([3]), vec![1.0, 2.0, 3.0]).unwrap();
389 let b = crate::manipulation::broadcast_to(&a, &[2, 3]).unwrap();
390 assert_eq!(b.shape(), &[2, 3]);
391 let arc = ArcArray::<f64, crate::dimension::IxDyn>::from_owned(b);
392 assert_eq!(arc.as_slice(), &[1.0, 2.0, 3.0, 1.0, 2.0, 3.0]);
394 }
395}