Decompose the flat index over the content extent in structure creators

This commit is contained in:
Dennis Kobert
2026-08-17 08:09:27 +00:00
parent 932ed8653e
commit a03db0ac6c
5 changed files with 143 additions and 20 deletions

View File

@@ -39,6 +39,18 @@ pub trait ExtractIndex {
fn innermost_index(&self) -> u64 {
self.try_index().and_then(|mut indices| indices.next()).unwrap_or(0) as u64
}
/// The decompose half of decompose-and-promote: splits the flat innermost
/// index over the content's inner extent into the pushed level's copy and
/// the lane within it. Rectangular domains; an empty inner extent maps
/// everything to copy 0.
fn split_innermost(&self, inner: u64) -> (u64, u64) {
let flat = self.innermost_index();
match inner {
0 => (0, 0),
inner => (flat / inner, flat % inner),
}
}
}
pub trait ExtractVarArgs {
// TODO: Consider returning a slice or something like that
@@ -721,6 +733,7 @@ pub trait DeriveCtx {
fn position_head(&self) -> Option<&PositionLink<'_>>;
fn varargs_head(&self) -> Option<&VarArgLink<'_>>;
fn promoted<'s>(&'s self, spilled_head: &'s IndexLink<'s>, inner_index: u64) -> Derived<'s, Self>;
fn push_level<'s>(&'s self, frame: &'s mut IndexLink<'s>, copy: u64, inner: u64) -> Derived<'s, Self>;
fn with_footprint<'s>(&'s self, footprint: &'s Footprint) -> Derived<'s, Self>;
fn with_varargs<'s>(&'s self, varargs: &'s VarArgLink<'s>) -> Derived<'s, Self>;
fn with_position<'s>(&'s self, position: &'s PositionLink<'s>) -> Derived<'s, Self>;
@@ -1111,6 +1124,10 @@ impl<'a> DeriveCtx for ContextImpl<'a> {
ContextImpl::promoted(self, spilled_head, inner_index)
}
fn push_level<'s>(&'s self, frame: &'s mut IndexLink<'s>, copy: u64, inner: u64) -> ContextImpl<'s> {
ContextImpl::push_level(self, frame, copy, inner)
}
fn with_footprint<'s>(&'s self, footprint: &'s Footprint) -> ContextImpl<'s> {
ContextImpl::with_footprint(self, footprint)
}

View File

@@ -729,15 +729,17 @@ pub struct RecordLazyInput<'a, 'e, N> {
node: &'a N,
cell: &'a crate::node::StatusCell,
input_index: usize,
inner_levels: u8,
_lifetime: std::marker::PhantomData<fn() -> RecordValue<'e>>,
}
impl<'a, 'e, N> RecordLazyInput<'a, 'e, N> {
pub fn new(node: &'a N, cell: &'a crate::node::StatusCell, input_index: usize) -> Self {
pub fn new(node: &'a N, cell: &'a crate::node::StatusCell, input_index: usize, inner_levels: u8) -> Self {
Self {
node,
cell,
input_index,
inner_levels,
_lifetime: std::marker::PhantomData,
}
}
@@ -748,6 +750,36 @@ impl<'a, 'e, N> RecordLazyInput<'a, 'e, N> {
{
Ok(self.node.eval_derived(self.cell, self.input_index, ctx)?.rebind())
}
/// The flat lane count of one copy: the product of the edge's inner-level
/// extents, queried uniform across copies (at copy 0). The dividend of a
/// structure node's decompose-and-promote.
pub fn inner_extent<B>(&self, ctx: &B) -> Result<u64, crate::gpoll::Interrupt>
where
B: crate::context::DeriveCtx,
N: for<'d> DerivedRecordEdge<'d, crate::context::Derived<'d, B>>,
{
inner_extent_of(self.node, ctx, self.inner_levels)
}
}
/// See [`RecordLazyInput::inner_extent`].
fn inner_extent_of<B, N>(node: &N, ctx: &B, levels: u8) -> Result<u64, crate::gpoll::Interrupt>
where
B: crate::context::DeriveCtx,
N: for<'d> DerivedRecordEdge<'d, crate::context::Derived<'d, B>>,
{
let head = ctx.index_head();
let derived = ctx.promoted(&head, 0);
let mut inner: u64 = 1;
for level in 0..levels {
match node.extent_at_derived(&derived, level) {
GPoll::Final(crate::gpoll::Extent::Exactly(count)) => inner *= count as u64,
GPoll::Pending => return Err(crate::gpoll::Interrupt::Pending),
_ => return Err(crate::gpoll::GraphError::new("structure decomposition over a non-exact extent").into()),
}
}
Ok(inner)
}
/// The derive-routing carrier beside its declared attribute reads: evaluating
@@ -759,6 +791,7 @@ pub struct DerivedLazyInput<'a, 'e, Out, N> {
node: &'a N,
cell: &'a crate::node::StatusCell,
input_index: usize,
inner_levels: u8,
reads: &'a [Option<usize>],
read: unsafe fn(Rec, &[Option<usize>]) -> Out,
_lifetime: std::marker::PhantomData<fn() -> RecordValue<'e>>,
@@ -767,17 +800,27 @@ pub struct DerivedLazyInput<'a, 'e, Out, N> {
impl<'a, 'e, Out, N> DerivedLazyInput<'a, 'e, Out, N> {
/// `read` must be sound against the layout the offsets in `reads` were
/// resolved from; the macro proves both at wiring.
pub fn new(node: &'a N, cell: &'a crate::node::StatusCell, input_index: usize, reads: &'a [Option<usize>], read: unsafe fn(Rec, &[Option<usize>]) -> Out) -> Self {
pub fn new(node: &'a N, cell: &'a crate::node::StatusCell, input_index: usize, inner_levels: u8, reads: &'a [Option<usize>], read: unsafe fn(Rec, &[Option<usize>]) -> Out) -> Self {
Self {
node,
cell,
input_index,
inner_levels,
reads,
read,
_lifetime: std::marker::PhantomData,
}
}
/// The flat lane count of one copy; see [`RecordLazyInput::inner_extent`].
pub fn inner_extent<B>(&self, ctx: &B) -> Result<u64, crate::gpoll::Interrupt>
where
B: crate::context::DeriveCtx,
N: for<'d> DerivedRecordEdge<'d, crate::context::Derived<'d, B>>,
{
inner_extent_of(self.node, ctx, self.inner_levels)
}
pub fn eval<'d, C>(&self, ctx: &C) -> Result<Out, crate::gpoll::Interrupt>
where
N: DerivedRecordEdge<'d, C>,
@@ -1399,6 +1442,10 @@ where
}
}
fn extent_at(&self, input: &C, level: u8) -> GPoll<crate::gpoll::Extent> {
self.edge.extent_at(input, level)
}
fn layout(&self) -> &Layout {
&self.union
}