Skip to content

Commit 953f2e9

Browse files
authored
Move LayoutBitset to its own module (#1567)
This is a follow-on to #1563; it probably should have been the same PR. In additon to reserving the name `Layout`, we'd also like to clean up the `src/layout` module so that we can pack it full of new features for #1506. So we collapse everything that's currently there into `layout::bitset`, and add a `pub use` declaration to re-export it. As a side note, I'd eventually like `layout` to act as a template for how we handle modules: minimal module-level code and clear module-level documentation. I've made #1566 to track that library-wide.
1 parent 6e02f15 commit 953f2e9

File tree

3 files changed

+274
-279
lines changed

3 files changed

+274
-279
lines changed

src/layout/bitset.rs

Lines changed: 271 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,271 @@
1+
//! Compact representations of array layouts.
2+
3+
use alloc::fmt;
4+
5+
// Layout is a bitset used for internal layout description of
6+
// arrays, producers and sets of producers.
7+
// The type is public but users don't interact with it.
8+
#[doc(hidden)]
9+
/// Memory layout description
10+
#[derive(Copy, Clone)]
11+
pub struct LayoutBitset(pub(super) u32);
12+
13+
#[deprecated(since = "0.18.0", note = "Layout has been renamed to LayoutBitset")]
14+
#[allow(dead_code)]
15+
/// Memory layout description, deprecated. See [`LayoutBitset`] instead.
16+
pub type Layout = LayoutBitset;
17+
18+
impl LayoutBitset
19+
{
20+
pub(crate) const CORDER: u32 = 0b01;
21+
pub(crate) const FORDER: u32 = 0b10;
22+
pub(crate) const CPREFER: u32 = 0b0100;
23+
pub(crate) const FPREFER: u32 = 0b1000;
24+
25+
#[inline(always)]
26+
pub(crate) fn is(self, flag: u32) -> bool
27+
{
28+
self.0 & flag != 0
29+
}
30+
31+
/// Return layout common to both inputs
32+
#[inline(always)]
33+
pub(crate) fn intersect(self, other: LayoutBitset) -> LayoutBitset
34+
{
35+
LayoutBitset(self.0 & other.0)
36+
}
37+
38+
/// Return a layout that simultaneously "is" what both of the inputs are
39+
#[inline(always)]
40+
pub(crate) fn also(self, other: LayoutBitset) -> LayoutBitset
41+
{
42+
LayoutBitset(self.0 | other.0)
43+
}
44+
45+
#[inline(always)]
46+
pub(crate) fn one_dimensional() -> LayoutBitset
47+
{
48+
LayoutBitset::c().also(LayoutBitset::f())
49+
}
50+
51+
#[inline(always)]
52+
pub(crate) fn c() -> LayoutBitset
53+
{
54+
LayoutBitset(LayoutBitset::CORDER | LayoutBitset::CPREFER)
55+
}
56+
57+
#[inline(always)]
58+
pub(crate) fn f() -> LayoutBitset
59+
{
60+
LayoutBitset(LayoutBitset::FORDER | LayoutBitset::FPREFER)
61+
}
62+
63+
#[inline(always)]
64+
pub(crate) fn cpref() -> LayoutBitset
65+
{
66+
LayoutBitset(LayoutBitset::CPREFER)
67+
}
68+
69+
#[inline(always)]
70+
pub(crate) fn fpref() -> LayoutBitset
71+
{
72+
LayoutBitset(LayoutBitset::FPREFER)
73+
}
74+
75+
#[inline(always)]
76+
pub(crate) fn none() -> LayoutBitset
77+
{
78+
LayoutBitset(0)
79+
}
80+
81+
/// A simple "score" method which scores positive for preferring C-order, negative for F-order
82+
/// Subject to change when we can describe other layouts
83+
#[inline]
84+
pub(crate) fn tendency(self) -> i32
85+
{
86+
(self.is(LayoutBitset::CORDER) as i32 - self.is(LayoutBitset::FORDER) as i32)
87+
+ (self.is(LayoutBitset::CPREFER) as i32 - self.is(LayoutBitset::FPREFER) as i32)
88+
}
89+
}
90+
91+
const LAYOUT_NAMES: &[&str] = &["C", "F", "c", "f"];
92+
93+
impl fmt::Debug for LayoutBitset
94+
{
95+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
96+
{
97+
if self.0 == 0 {
98+
write!(f, "Custom")?
99+
} else {
100+
(0..32).filter(|&i| self.is(1 << i)).try_fold((), |_, i| {
101+
if let Some(name) = LAYOUT_NAMES.get(i) {
102+
write!(f, "{}", name)
103+
} else {
104+
write!(f, "{:#x}", i)
105+
}
106+
})?;
107+
};
108+
write!(f, " ({:#x})", self.0)
109+
}
110+
}
111+
112+
#[cfg(test)]
113+
mod tests
114+
{
115+
use super::*;
116+
use crate::imp_prelude::*;
117+
use crate::NdProducer;
118+
119+
type M = Array2<f32>;
120+
type M1 = Array1<f32>;
121+
type M0 = Array0<f32>;
122+
123+
macro_rules! assert_layouts {
124+
($mat:expr, $($layout:ident),*) => {{
125+
let layout = $mat.view().layout();
126+
$(
127+
assert!(layout.is(LayoutBitset::$layout),
128+
"Assertion failed: array {:?} is not layout {}",
129+
$mat,
130+
stringify!($layout));
131+
)*
132+
}};
133+
}
134+
135+
macro_rules! assert_not_layouts {
136+
($mat:expr, $($layout:ident),*) => {{
137+
let layout = $mat.view().layout();
138+
$(
139+
assert!(!layout.is(LayoutBitset::$layout),
140+
"Assertion failed: array {:?} show not have layout {}",
141+
$mat,
142+
stringify!($layout));
143+
)*
144+
}};
145+
}
146+
147+
#[test]
148+
fn contig_layouts()
149+
{
150+
let a = M::zeros((5, 5));
151+
let b = M::zeros((5, 5).f());
152+
let ac = a.view().layout();
153+
let af = b.view().layout();
154+
assert!(ac.is(LayoutBitset::CORDER) && ac.is(LayoutBitset::CPREFER));
155+
assert!(!ac.is(LayoutBitset::FORDER) && !ac.is(LayoutBitset::FPREFER));
156+
assert!(!af.is(LayoutBitset::CORDER) && !af.is(LayoutBitset::CPREFER));
157+
assert!(af.is(LayoutBitset::FORDER) && af.is(LayoutBitset::FPREFER));
158+
}
159+
160+
#[test]
161+
fn contig_cf_layouts()
162+
{
163+
let a = M::zeros((5, 1));
164+
let b = M::zeros((1, 5).f());
165+
assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
166+
assert_layouts!(b, CORDER, CPREFER, FORDER, FPREFER);
167+
168+
let a = M1::zeros(5);
169+
let b = M1::zeros(5.f());
170+
assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
171+
assert_layouts!(b, CORDER, CPREFER, FORDER, FPREFER);
172+
173+
let a = M0::zeros(());
174+
assert_layouts!(a, CORDER, CPREFER, FORDER, FPREFER);
175+
176+
let a = M::zeros((5, 5));
177+
let b = M::zeros((5, 5).f());
178+
let arow = a.slice(s![..1, ..]);
179+
let bcol = b.slice(s![.., ..1]);
180+
assert_layouts!(arow, CORDER, CPREFER, FORDER, FPREFER);
181+
assert_layouts!(bcol, CORDER, CPREFER, FORDER, FPREFER);
182+
183+
let acol = a.slice(s![.., ..1]);
184+
let brow = b.slice(s![..1, ..]);
185+
assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
186+
assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
187+
}
188+
189+
#[test]
190+
fn stride_layouts()
191+
{
192+
let a = M::zeros((5, 5));
193+
194+
{
195+
let v1 = a.slice(s![1.., ..]).layout();
196+
let v2 = a.slice(s![.., 1..]).layout();
197+
198+
assert!(v1.is(LayoutBitset::CORDER) && v1.is(LayoutBitset::CPREFER));
199+
assert!(!v1.is(LayoutBitset::FORDER) && !v1.is(LayoutBitset::FPREFER));
200+
assert!(!v2.is(LayoutBitset::CORDER) && v2.is(LayoutBitset::CPREFER));
201+
assert!(!v2.is(LayoutBitset::FORDER) && !v2.is(LayoutBitset::FPREFER));
202+
}
203+
204+
let b = M::zeros((5, 5).f());
205+
206+
{
207+
let v1 = b.slice(s![1.., ..]).layout();
208+
let v2 = b.slice(s![.., 1..]).layout();
209+
210+
assert!(!v1.is(LayoutBitset::CORDER) && !v1.is(LayoutBitset::CPREFER));
211+
assert!(!v1.is(LayoutBitset::FORDER) && v1.is(LayoutBitset::FPREFER));
212+
assert!(!v2.is(LayoutBitset::CORDER) && !v2.is(LayoutBitset::CPREFER));
213+
assert!(v2.is(LayoutBitset::FORDER) && v2.is(LayoutBitset::FPREFER));
214+
}
215+
}
216+
217+
#[test]
218+
fn no_layouts()
219+
{
220+
let a = M::zeros((5, 5));
221+
let b = M::zeros((5, 5).f());
222+
223+
// 2D row/column matrixes
224+
let arow = a.slice(s![0..1, ..]);
225+
let acol = a.slice(s![.., 0..1]);
226+
let brow = b.slice(s![0..1, ..]);
227+
let bcol = b.slice(s![.., 0..1]);
228+
assert_layouts!(arow, CORDER, FORDER);
229+
assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
230+
assert_layouts!(bcol, CORDER, FORDER);
231+
assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
232+
233+
// 2D row/column matrixes - now made with insert axis
234+
for &axis in &[Axis(0), Axis(1)] {
235+
let arow = a.slice(s![0, ..]).insert_axis(axis);
236+
let acol = a.slice(s![.., 0]).insert_axis(axis);
237+
let brow = b.slice(s![0, ..]).insert_axis(axis);
238+
let bcol = b.slice(s![.., 0]).insert_axis(axis);
239+
assert_layouts!(arow, CORDER, FORDER);
240+
assert_not_layouts!(acol, CORDER, CPREFER, FORDER, FPREFER);
241+
assert_layouts!(bcol, CORDER, FORDER);
242+
assert_not_layouts!(brow, CORDER, CPREFER, FORDER, FPREFER);
243+
}
244+
}
245+
246+
#[test]
247+
fn skip_layouts()
248+
{
249+
let a = M::zeros((5, 5));
250+
{
251+
let v1 = a.slice(s![..;2, ..]).layout();
252+
let v2 = a.slice(s![.., ..;2]).layout();
253+
254+
assert!(!v1.is(LayoutBitset::CORDER) && v1.is(LayoutBitset::CPREFER));
255+
assert!(!v1.is(LayoutBitset::FORDER) && !v1.is(LayoutBitset::FPREFER));
256+
assert!(!v2.is(LayoutBitset::CORDER) && !v2.is(LayoutBitset::CPREFER));
257+
assert!(!v2.is(LayoutBitset::FORDER) && !v2.is(LayoutBitset::FPREFER));
258+
}
259+
260+
let b = M::zeros((5, 5).f());
261+
{
262+
let v1 = b.slice(s![..;2, ..]).layout();
263+
let v2 = b.slice(s![.., ..;2]).layout();
264+
265+
assert!(!v1.is(LayoutBitset::CORDER) && !v1.is(LayoutBitset::CPREFER));
266+
assert!(!v1.is(LayoutBitset::FORDER) && !v1.is(LayoutBitset::FPREFER));
267+
assert!(!v2.is(LayoutBitset::CORDER) && !v2.is(LayoutBitset::CPREFER));
268+
assert!(!v2.is(LayoutBitset::FORDER) && v2.is(LayoutBitset::FPREFER));
269+
}
270+
}
271+
}

src/layout/layoutfmt.rs

Lines changed: 0 additions & 32 deletions
This file was deleted.

0 commit comments

Comments
 (0)