use super::{BlockId, FunctionId};
use std::collections::HashSet;
use std::hash::{Hash, Hasher};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct SuperblockId(u32);
impl SuperblockId {
#[inline]
#[must_use]
pub const fn new(id: u32) -> Self {
Self(id)
}
#[inline]
#[must_use]
pub const fn as_u32(self) -> u32 {
self.0
}
}
impl Hash for SuperblockId {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
#[derive(Debug, Clone)]
pub struct Superblock {
id: SuperblockId,
blocks: Vec<BlockId>,
block_set: HashSet<BlockId>,
cost: u64,
function: FunctionId,
}
impl Superblock {
#[must_use]
pub fn new(id: SuperblockId, blocks: Vec<BlockId>, function: FunctionId) -> Self {
let block_set: HashSet<BlockId> = blocks.iter().copied().collect();
let cost = blocks.len() as u64;
Self {
id,
blocks,
block_set,
cost,
function,
}
}
#[inline]
#[must_use]
pub fn id(&self) -> SuperblockId {
self.id
}
#[inline]
#[must_use]
pub fn block_count(&self) -> usize {
self.blocks.len()
}
#[inline]
#[must_use]
pub fn contains(&self, block: BlockId) -> bool {
self.block_set.contains(&block)
}
#[must_use]
pub fn blocks(&self) -> &[BlockId] {
&self.blocks
}
#[inline]
#[must_use]
pub fn cost_estimate(&self) -> u64 {
self.cost
}
pub fn set_cost_estimate(&mut self, cost: u64) {
self.cost = cost;
}
#[inline]
#[must_use]
pub fn function(&self) -> FunctionId {
self.function
}
pub fn iter(&self) -> impl Iterator<Item = &BlockId> {
self.blocks.iter()
}
}
#[derive(Debug, Clone)]
pub struct SuperblockBuilder {
target_size: usize,
max_size: usize,
next_id: u32,
}
impl SuperblockBuilder {
#[must_use]
pub fn new() -> Self {
Self {
target_size: 64,
max_size: 256,
next_id: 0,
}
}
#[must_use]
pub fn with_target_size(mut self, size: usize) -> Self {
self.target_size = size;
self
}
#[must_use]
pub fn with_max_size(mut self, size: usize) -> Self {
self.max_size = size;
self
}
#[must_use]
pub fn build_from_blocks(&self, blocks: &[BlockId], function: FunctionId) -> Vec<Superblock> {
if blocks.is_empty() {
return Vec::new();
}
let effective_size = self.target_size.min(self.max_size);
let mut superblocks = Vec::new();
let mut next_id = self.next_id;
for chunk in blocks.chunks(effective_size) {
let id = SuperblockId::new(next_id);
next_id += 1;
superblocks.push(Superblock::new(id, chunk.to_vec(), function));
}
superblocks
}
#[must_use]
pub fn build_from_function_blocks(
&self,
function_blocks: &[(FunctionId, Vec<BlockId>)],
) -> Vec<Superblock> {
let mut all_superblocks = Vec::new();
for (function, blocks) in function_blocks {
let superblocks = self.build_from_blocks(blocks, *function);
all_superblocks.extend(superblocks);
}
all_superblocks
}
#[must_use]
pub fn next_id(&self) -> u32 {
self.next_id
}
}
impl Default for SuperblockBuilder {
fn default() -> Self {
Self::new()
}
}