///|
/// A query or its geometry validation error, with an explicit output interval.
pub struct BatchQuery[T] {
query : Result[T, @geom.GeometryError]
offset : Int32
capacity : Int32
}
///|
pub fn[T] BatchQuery::new(
query : Result[T, @geom.GeometryError],
offset~ : Int32,
capacity~ : Int32,
) -> BatchQuery[T] {
{ query, offset, capacity, }
}
///|
pub(all) suberror BatchError {
InvalidOutputRange(position~ : Int32)
OverlappingOutputRanges(first~ : Int32, second~ : Int32)
InsufficientWorkspace(required~ : Int32, available~ : Int32)
} derive(Debug, Eq)
///|
pub extend BatchError with @debug.Debug::{to_repr}
///|
pub extend BatchError with Eq::{equal, not_equal}
///|
fn[T] StaticObjectIndex::run_batch(
self : StaticObjectIndex,
queries : ArrayView[BatchQuery[T]],
output : FixedArray[UInt32],
workspace : Workspace,
region : (T) -> Region,
) -> Array[Result[QueryStats, @geom.GeometryError]] raise BatchError {
let intervals : Array[(Int32, Int32, Int32)] = []
for i in 0..= 0 &&
q.offset <= output.length() &&
q.capacity >= 0 &&
q.capacity <= output.length() - q.offset else {
raise InvalidOutputRange(position=i)
}
if q.capacity > 0 {
intervals.push((q.offset, q.offset + q.capacity, i))
}
}
intervals.sort_by(fn(a, b) { a.0.compare(b.0) })
for i in 1..= self.summary.workspace_required else {
raise InsufficientWorkspace(
required=self.summary.workspace_required,
available=workspace.capacity(),
)
}
let reports = []
for q in queries {
match q.query {
Err(error) => reports.push(Err(error))
Ok(query) => {
// All range and workspace checks have already succeeded for the batch.
let report = try! self.run_query(
region(query),
output,
workspace,
q.offset,
Some(q.capacity),
)
reports.push(Ok(report))
}
}
}
reports
}
///|
/// Validates every output interval before writing; reports follow input order.
pub fn StaticObjectIndex::query_aabb_batch_into(
self : StaticObjectIndex,
queries : ArrayView[BatchQuery[@geom.Aabb]],
output : FixedArray[UInt32],
workspace : Workspace,
) -> Array[Result[QueryStats, @geom.GeometryError]] raise BatchError {
self.run_batch(queries, output, workspace, b => Box(b))
}
///|
pub fn StaticObjectIndex::query_ray_candidates_batch_into(
self : StaticObjectIndex,
queries : ArrayView[BatchQuery[@geom.Ray]],
output : FixedArray[UInt32],
workspace : Workspace,
) -> Array[Result[QueryStats, @geom.GeometryError]] raise BatchError {
self.run_batch(queries, output, workspace, ray => Ray(ray))
}