use std::sync::Arc;
use crate::iteration::comprehension::ast::Comprehension;
use crate::iteration::comprehension::ir::{compile as compile_to_ir, Program};
use super::coord_stream::CoordinateStream;
use super::instance::{KernelScope, ScopedKernelInstance};
use super::scope_once::scope_once_with;
use super::scoped_stream::ScopedKernelStream;
#[derive(Debug, Clone)]
pub struct CompiledComprehension {
program: Arc<Program>,
}
impl CompiledComprehension {
pub fn from_ast(ast: &Comprehension) -> Self {
Self {
program: Arc::new(compile_to_ir(ast)),
}
}
pub fn from_program(program: Arc<Program>) -> Self {
Self { program }
}
pub fn program(&self) -> &Program {
&self.program
}
pub(crate) fn program_arc(&self) -> Arc<Program> {
Arc::clone(&self.program)
}
pub fn coordinate_stream(&self) -> CoordinateStream {
CoordinateStream::new(self.program_arc())
}
pub fn scoped_kernel_stream<K: KernelScope>(
&self,
parent: K,
) -> ScopedKernelStream<K> {
ScopedKernelStream::new(self.program_arc(), parent)
}
pub fn scope_once<K: KernelScope>(
&self,
parent: &K,
coords: &crate::iteration::comprehension::strategies::Tuple,
) -> ScopedKernelInstance<K::Scoped> {
scope_once_with(parent, coords)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::iteration::comprehension::source::{LiteralValue, Source};
fn clause(name: &str, vs: &[i64]) -> Comprehension {
Comprehension::clause(
name,
Source::Literal {
values: vs.iter().map(|n| LiteralValue::Int(*n)).collect(),
},
)
}
#[test]
fn from_ast_compiles_once() {
let ast = clause("k", &[1, 2, 3]);
let compiled = CompiledComprehension::from_ast(&ast);
assert!(!compiled.program().is_empty());
}
#[test]
fn cloning_compiled_shares_arc() {
let ast = clause("k", &[1, 2, 3]);
let a = CompiledComprehension::from_ast(&ast);
let b = a.clone();
let count = Arc::strong_count(&a.program);
assert!(count >= 2, "expected shared Arc, count = {count}");
drop(b);
}
#[test]
fn two_coordinate_streams_share_program() {
let ast = clause("k", &[1, 2, 3]);
let compiled = CompiledComprehension::from_ast(&ast);
let _s1 = compiled.coordinate_stream();
let _s2 = compiled.coordinate_stream();
let count = Arc::strong_count(&compiled.program);
assert!(count >= 3, "expected shared program across streamers, count = {count}");
}
}