Skip to main content

faer/perm/
permref.rs

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