faer/perm/
permref.rs

1use super::*;
2use crate::utils::bound::{Array, Dim};
3use crate::{Idx, assert};
4
5/// see [`super::PermRef`]
6#[derive(Debug)]
7pub struct Ref<'a, I: Index, N: Shape = usize> {
8	pub(super) forward: &'a [N::Idx<I>],
9	pub(super) inverse: &'a [N::Idx<I>],
10}
11
12impl<I: Index, N: Shape> Copy for Ref<'_, I, N> {}
13impl<I: Index, N: Shape> Clone for Ref<'_, I, N> {
14	#[inline]
15	fn clone(&self) -> Self {
16		*self
17	}
18}
19
20impl<'short, I: Index, N: Shape> Reborrow<'short> for Ref<'_, I, N> {
21	type Target = Ref<'short, I, N>;
22
23	#[inline]
24	fn rb(&'short self) -> Self::Target {
25		*self
26	}
27}
28impl<'short, I: Index, N: Shape> ReborrowMut<'short> for Ref<'_, I, N> {
29	type Target = Ref<'short, I, N>;
30
31	#[inline]
32	fn rb_mut(&'short mut self) -> Self::Target {
33		*self
34	}
35}
36impl<'a, I: Index, N: Shape> IntoConst for Ref<'a, I, N> {
37	type Target = Ref<'a, I, N>;
38
39	#[inline]
40	fn into_const(self) -> Self::Target {
41		self
42	}
43}
44
45impl<I: Index, N: Shape, Inner: for<'short> Reborrow<'short, Target = Ref<'short, I, N>>> generic::Perm<Inner> {
46	/// convert `self` to a permutation view
47	#[inline]
48	pub fn as_ref(&self) -> PermRef<'_, I, N> {
49		PermRef { 0: self.0.rb() }
50	}
51}
52
53impl<'a, I: Index, N: Shape> PermRef<'a, I, N> {
54	/// returns the input permutation with the given shape after checking that it matches the
55	/// current shape
56	#[inline]
57	pub fn as_shape<M: Shape>(self, dim: M) -> PermRef<'a, I, M> {
58		assert!(self.len().unbound() == dim.unbound());
59
60		PermRef {
61			0: Ref {
62				forward: unsafe { core::slice::from_raw_parts(self.forward.as_ptr() as _, dim.unbound()) },
63				inverse: unsafe { core::slice::from_raw_parts(self.inverse.as_ptr() as _, dim.unbound()) },
64			},
65		}
66	}
67
68	/// creates a new permutation, by checking the validity of the inputs
69	///
70	/// # panics
71	///
72	/// the function panics if any of the following conditions are violated:
73	/// * `forward` and `inverse` must have the same length which must be less than or equal to
74	/// `I::Signed::MAX`, be valid permutations, and be inverse permutations of each other
75	#[inline]
76	#[track_caller]
77	pub fn new_checked(forward: &'a [Idx<N, I>], inverse: &'a [Idx<N, I>], dim: N) -> Self {
78		#[track_caller]
79		fn check<I: Index>(forward: &[I], inverse: &[I], n: usize) {
80			assert!(all(n <= I::Signed::MAX.zx(), forward.len() == n, inverse.len() == n,));
81			for (i, &p) in forward.iter().enumerate() {
82				let p = p.to_signed().zx();
83				assert!(p < n);
84				assert!(inverse[p].to_signed().zx() == i);
85			}
86		}
87
88		check(
89			I::canonicalize(N::cast_idx_slice(forward)),
90			I::canonicalize(N::cast_idx_slice(inverse)),
91			dim.unbound(),
92		);
93		Self { 0: Ref { forward, inverse } }
94	}
95
96	/// creates a new permutation reference, without checking the validity of the inputs
97	///
98	/// # safety
99	///
100	/// `forward` and `inverse` must have the same length which must be less than or equal to
101	/// `I::Signed::MAX`, be valid permutations, and be inverse permutations of each other
102	#[inline]
103	#[track_caller]
104	pub unsafe fn new_unchecked(forward: &'a [Idx<N, I>], inverse: &'a [Idx<N, I>], dim: N) -> Self {
105		assert!(all(
106			dim.unbound() <= I::Signed::MAX.zx(),
107			forward.len() == dim.unbound(),
108			inverse.len() == dim.unbound(),
109		));
110		Self { 0: Ref { forward, inverse } }
111	}
112
113	/// returns the permutation as an array
114	#[inline]
115	pub fn arrays(self) -> (&'a [Idx<N, I>], &'a [Idx<N, I>]) {
116		(self.forward, self.inverse)
117	}
118
119	/// returns the dimension of the permutation
120	#[inline]
121	pub fn len(&self) -> N {
122		unsafe { N::new_unbound(self.forward.len()) }
123	}
124
125	/// returns the inverse permutation
126	#[inline]
127	pub fn inverse(self) -> Self {
128		Self {
129			0: Ref {
130				forward: self.inverse,
131				inverse: self.forward,
132			},
133		}
134	}
135
136	/// cast the permutation to the fixed width index type
137	#[inline(always)]
138	pub fn canonicalized(self) -> PermRef<'a, I::FixedWidth, N> {
139		unsafe {
140			PermRef {
141				0: Ref {
142					forward: core::slice::from_raw_parts(self.forward.as_ptr() as _, self.forward.len()),
143					inverse: core::slice::from_raw_parts(self.inverse.as_ptr() as _, self.inverse.len()),
144				},
145			}
146		}
147	}
148
149	/// cast the permutation from the fixed width index type
150	#[inline(always)]
151	pub fn uncanonicalized<J: Index>(self) -> PermRef<'a, J, N> {
152		assert!(core::mem::size_of::<J>() == core::mem::size_of::<I>());
153		unsafe {
154			PermRef {
155				0: Ref {
156					forward: core::slice::from_raw_parts(self.forward.as_ptr() as _, self.forward.len()),
157					inverse: core::slice::from_raw_parts(self.inverse.as_ptr() as _, self.inverse.len()),
158				},
159			}
160		}
161	}
162}
163
164impl<'a, 'N, I: Index> PermRef<'a, I, Dim<'N>> {
165	/// returns the permutation as an array
166	#[inline]
167	pub fn bound_arrays(self) -> (&'a Array<'N, Idx<Dim<'N>, I>>, &'a Array<'N, Idx<Dim<'N>, I>>) {
168		unsafe {
169			(
170				&*(self.forward as *const [Idx<Dim<'N>, I>] as *const Array<'N, Idx<Dim<'N>, I>>),
171				&*(self.inverse as *const [Idx<Dim<'N>, I>] as *const Array<'N, Idx<Dim<'N>, I>>),
172			)
173		}
174	}
175}