use super::is_external;
use crate::chunked::ChunkedArray;
use crate::config::Layout;
use crate::sbt::{Key, Nodes, NodesRead};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Role {
Source,
Target,
}
pub mod header {
pub const ALLOCATED: usize = 0;
pub const RESERVED: usize = 8;
pub const FREE: usize = 16;
pub const FIRST_FREE: usize = 24;
pub const ROOT_AS_SOURCE: usize = 32;
pub const ROOT_AS_TARGET: usize = 40;
pub const LAST_FREE: usize = 48;
}
#[derive(Clone, Debug)]
pub struct Records {
pub layout: Layout,
pub data: ChunkedArray,
pub index: ChunkedArray,
}
const SOURCE: usize = 0;
const TARGET: usize = 8;
impl Records {
#[must_use]
pub fn new(layout: Layout, block_size: usize) -> Self {
let data_size = if layout == Layout::United { 64 } else { 16 };
Self {
layout,
data: ChunkedArray::new(data_size, block_size),
index: ChunkedArray::new(64, block_size),
}
}
pub fn ensure(&mut self, last: u64) {
self.data.ensure_capacity(last + 1);
if self.layout == Layout::Split {
self.index.ensure_capacity(last + 1);
}
}
#[must_use]
pub fn capacity(&self) -> u64 {
if self.layout == Layout::Split {
self.data.capacity().min(self.index.capacity())
} else {
self.data.capacity()
}
}
#[must_use]
pub fn source(&self, link: u64) -> u64 {
self.data.get(link, SOURCE)
}
#[must_use]
pub fn target(&self, link: u64) -> u64 {
self.data.get(link, TARGET)
}
pub fn set_link(&mut self, link: u64, source: u64, target: u64) {
self.data.set(link, SOURCE, source);
self.data.set(link, TARGET, target);
}
#[must_use]
pub fn end(&self, link: u64, role: Role) -> u64 {
match role {
Role::Source => self.source(link),
Role::Target => self.target(link),
}
}
#[must_use]
pub fn other_end(&self, link: u64, role: Role) -> u64 {
match role {
Role::Source => self.target(link),
Role::Target => self.source(link),
}
}
#[must_use]
pub fn header(&self, cell: usize) -> u64 {
match self.layout {
Layout::United if self.data.capacity() > 0 => self.data.get(0, cell),
Layout::Split if self.index.capacity() > 0 => self.index.get(0, cell),
_ => 0,
}
}
pub fn set_header(&mut self, cell: usize, value: u64) {
match self.layout {
Layout::United => {
self.data.ensure_capacity(1);
if self.data.get(0, cell) != value {
self.data.set(0, cell, value);
}
}
Layout::Split => {
self.index.ensure_capacity(1);
if self.index.get(0, cell) != value {
self.index.set(0, cell, value);
}
}
Layout::DataOnly => {}
}
}
const fn tree_offset(&self, role: Role) -> usize {
match (self.layout, role) {
(Layout::United, Role::Source) => 16,
(_, Role::Target) => 40,
(_, Role::Source) => 8,
}
}
fn tree_array(&self) -> &ChunkedArray {
if self.layout == Layout::United {
&self.data
} else {
&self.index
}
}
fn tree_array_mut(&mut self) -> &mut ChunkedArray {
if self.layout == Layout::United {
&mut self.data
} else {
&mut self.index
}
}
#[must_use]
pub fn tree_cell(&self, link: u64, role: Role, which: usize) -> u64 {
self.tree_array()
.get(link, self.tree_offset(role) + which * 8)
}
pub fn set_tree_cell(&mut self, link: u64, role: Role, which: usize, value: u64) {
let offset = self.tree_offset(role) + which * 8;
self.tree_array_mut().set(link, offset, value);
}
#[must_use]
pub fn link_root(&self, link: u64, role: Role) -> u64 {
let offset = if role == Role::Source { 0 } else { 32 };
self.index.get(link, offset)
}
pub fn set_link_root(&mut self, link: u64, role: Role, value: u64) {
let offset = if role == Role::Source { 0 } else { 32 };
self.index.set(link, offset, value);
}
#[must_use]
pub fn tree_of(&self, link: u64, role: Role) -> Option<TreeId> {
let end = self.end(link, role);
if end == 0 || !self.layout.has_embedded_index() {
return None;
}
Some(if self.layout == Layout::Split && !is_external(end) {
TreeId::PerLink(end)
} else {
TreeId::Global
})
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TreeId {
Global,
PerLink(u64),
}
pub struct Tree<'a> {
pub records: &'a Records,
pub role: Role,
pub per_link: bool,
}
pub struct TreeMut<'a> {
pub records: &'a mut Records,
pub role: Role,
pub per_link: bool,
}
fn key_of(records: &Records, role: Role, per_link: bool, node: u64) -> Key {
let end = records.end(node, role);
let other = records.other_end(node, role);
if per_link {
(other, node, 0)
} else {
(end, other, node)
}
}
impl NodesRead for Tree<'_> {
fn left(&self, node: u64) -> u64 {
self.records.tree_cell(node, self.role, 0)
}
fn right(&self, node: u64) -> u64 {
self.records.tree_cell(node, self.role, 1)
}
fn size(&self, node: u64) -> u64 {
self.records.tree_cell(node, self.role, 2)
}
fn key(&self, node: u64) -> Key {
key_of(self.records, self.role, self.per_link, node)
}
}
impl NodesRead for TreeMut<'_> {
fn left(&self, node: u64) -> u64 {
self.records.tree_cell(node, self.role, 0)
}
fn right(&self, node: u64) -> u64 {
self.records.tree_cell(node, self.role, 1)
}
fn size(&self, node: u64) -> u64 {
self.records.tree_cell(node, self.role, 2)
}
fn key(&self, node: u64) -> Key {
key_of(self.records, self.role, self.per_link, node)
}
}
impl Nodes for TreeMut<'_> {
fn set_left(&mut self, node: u64, value: u64) {
self.records.set_tree_cell(node, self.role, 0, value);
}
fn set_right(&mut self, node: u64, value: u64) {
self.records.set_tree_cell(node, self.role, 1, value);
}
fn set_size(&mut self, node: u64, value: u64) {
self.records.set_tree_cell(node, self.role, 2, value);
}
}