#![allow(clippy::too_many_arguments)]
use super::FixedPointAnalysisKind;
#[derive(Clone, Debug, PartialEq)]
pub struct FixedPointForwardGraph {
pub(crate) kind: FixedPointAnalysisKind,
pub(crate) node_count: u32,
pub(crate) edge_count: u32,
pub(crate) pg_nodes_bytes: Vec<u8>,
pub(crate) edge_offsets_bytes: Vec<u8>,
pub(crate) edge_targets_bytes: Vec<u8>,
pub(crate) edge_kind_mask_bytes: Vec<u8>,
pub(crate) pg_node_tags_bytes: Vec<u8>,
pub(crate) stable_layout_hash: u64,
pub(crate) normalized_graph: crate::graph_layout::NormalizedCsrGraph,
pub(crate) normalization_scratch: crate::graph_layout::CsrGraphNormalizationScratch,
}
impl FixedPointForwardGraph {
pub fn new(
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
) -> Result<Self, String> {
Self::new_for_kind(
FixedPointAnalysisKind::Generic,
stage,
node_count,
edge_offsets,
edge_targets,
edge_kind_mask,
)
}
pub fn new_for_kind(
kind: FixedPointAnalysisKind,
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
) -> Result<Self, String> {
let mut normalized_graph = crate::graph_layout::NormalizedCsrGraph::empty();
let mut normalization_scratch = crate::graph_layout::CsrGraphNormalizationScratch::new();
crate::graph_layout::CsrGraph::new(node_count, edge_offsets, edge_targets, edge_kind_mask)
.normalize_into(stage, &mut normalized_graph, &mut normalization_scratch)?;
Self::from_normalized(
kind,
stage,
node_count,
normalized_graph,
normalization_scratch,
)
}
pub fn new_with_edge_kind_mask(
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
allowed_mask: u32,
) -> Result<Self, String> {
Self::new_with_edge_kind_mask_for_kind(
FixedPointAnalysisKind::Generic,
stage,
node_count,
edge_offsets,
edge_targets,
edge_kind_mask,
allowed_mask,
)
}
pub fn new_with_edge_kind_mask_for_kind(
kind: FixedPointAnalysisKind,
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
allowed_mask: u32,
) -> Result<Self, String> {
let mut normalized_graph = crate::graph_layout::NormalizedCsrGraph::empty();
let mut normalization_scratch = crate::graph_layout::CsrGraphNormalizationScratch::new();
crate::graph_layout::CsrGraph::new(node_count, edge_offsets, edge_targets, edge_kind_mask)
.normalize_with_edge_kind_mask_into(
stage,
allowed_mask,
&mut normalized_graph,
&mut normalization_scratch,
)?;
Self::from_normalized(
kind,
stage,
node_count,
normalized_graph,
normalization_scratch,
)
}
fn from_normalized(
kind: FixedPointAnalysisKind,
stage: &str,
node_count: u32,
normalized_graph: crate::graph_layout::NormalizedCsrGraph,
normalization_scratch: crate::graph_layout::CsrGraphNormalizationScratch,
) -> Result<Self, String> {
let mut graph = Self {
kind,
node_count: 0,
edge_count: 0,
pg_nodes_bytes: Vec::new(),
edge_offsets_bytes: Vec::new(),
edge_targets_bytes: Vec::new(),
edge_kind_mask_bytes: Vec::new(),
pg_node_tags_bytes: Vec::new(),
stable_layout_hash: 0,
normalized_graph,
normalization_scratch,
};
graph.replace_from_current_normalized(kind, stage, node_count)?;
Ok(graph)
}
pub fn replace(
&mut self,
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
) -> Result<(), String> {
self.replace_for_kind(
self.kind,
stage,
node_count,
edge_offsets,
edge_targets,
edge_kind_mask,
)
}
pub fn replace_for_kind(
&mut self,
kind: FixedPointAnalysisKind,
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
) -> Result<(), String> {
self.require_kind(kind, stage)?;
crate::graph_layout::CsrGraph::new(node_count, edge_offsets, edge_targets, edge_kind_mask)
.normalize_into(
stage,
&mut self.normalized_graph,
&mut self.normalization_scratch,
)?;
self.replace_from_current_normalized(kind, stage, node_count)
}
pub fn replace_with_edge_kind_mask(
&mut self,
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
allowed_mask: u32,
) -> Result<(), String> {
self.replace_with_edge_kind_mask_for_kind(
self.kind,
stage,
node_count,
edge_offsets,
edge_targets,
edge_kind_mask,
allowed_mask,
)
}
pub fn replace_with_edge_kind_mask_for_kind(
&mut self,
kind: FixedPointAnalysisKind,
stage: &str,
node_count: u32,
edge_offsets: &[u32],
edge_targets: &[u32],
edge_kind_mask: &[u32],
allowed_mask: u32,
) -> Result<(), String> {
self.require_kind(kind, stage)?;
crate::graph_layout::CsrGraph::new(node_count, edge_offsets, edge_targets, edge_kind_mask)
.normalize_with_edge_kind_mask_into(
stage,
allowed_mask,
&mut self.normalized_graph,
&mut self.normalization_scratch,
)?;
self.replace_from_current_normalized(kind, stage, node_count)
}
fn replace_from_current_normalized(
&mut self,
kind: FixedPointAnalysisKind,
stage: &str,
node_count: u32,
) -> Result<(), String> {
let normalized = &self.normalized_graph;
let nodes = usize::try_from(normalized.node_count()).map_err(|_| {
format!("{stage} node_count={node_count} cannot fit usize. Fix: shard the graph before dispatch.")
})?;
self.kind = kind;
self.node_count = normalized.node_count();
self.edge_count = normalized.edge_count();
self.stable_layout_hash = normalized.stable_layout_hash();
crate::dispatch_decode::pack_repeated_u32_into(0, nodes, &mut self.pg_nodes_bytes)?;
crate::dispatch_decode::try_pack_u32_into(
normalized.edge_offsets(),
&mut self.edge_offsets_bytes,
"fixed-point graph edge offsets bytes",
)?;
crate::dispatch_decode::try_pack_u32_into(
normalized.edge_targets(),
&mut self.edge_targets_bytes,
"fixed-point graph edge targets bytes",
)?;
crate::dispatch_decode::try_pack_u32_into(
normalized.edge_kind_mask(),
&mut self.edge_kind_mask_bytes,
"fixed-point graph edge kind mask bytes",
)?;
crate::dispatch_decode::pack_repeated_u32_into(0, nodes, &mut self.pg_node_tags_bytes)?;
Ok(())
}
#[must_use]
pub fn kind(&self) -> FixedPointAnalysisKind {
self.kind
}
pub fn require_kind(
&self,
expected: FixedPointAnalysisKind,
consumer: &str,
) -> Result<(), String> {
if self.kind == expected {
return Ok(());
}
Err(prepared_kind_mismatch(consumer, self.kind, expected))
}
#[must_use]
pub fn node_count(&self) -> u32 {
self.node_count
}
#[must_use]
pub fn edge_count(&self) -> u32 {
self.edge_count
}
#[must_use]
pub fn retained_bytes(&self) -> usize {
self.pg_nodes_bytes.capacity()
+ self.edge_offsets_bytes.capacity()
+ self.edge_targets_bytes.capacity()
+ self.edge_kind_mask_bytes.capacity()
+ self.pg_node_tags_bytes.capacity()
}
#[must_use]
pub fn stable_layout_hash(&self) -> u64 {
self.stable_layout_hash
}
}
#[cold]
fn prepared_kind_mismatch(
consumer: &str,
got: FixedPointAnalysisKind,
expected: FixedPointAnalysisKind,
) -> String {
let mut scratch = crate::error_format::ErrorFormatScratch::default();
let _ = std::fmt::Write::write_fmt(
&mut scratch.buf,
format_args!(
"{consumer} received a {got:?} fixed-point graph, expected {expected:?}. Fix: prepare the graph with the matching Weir analysis constructor."
),
);
scratch.finish()
}