use std::sync::{Arc, OnceLock};
use super::bits::Bits;
use super::column::{Column, Page};
use super::ids::{Ids, Index, RowIds};
use super::name::{Id, IdRef, Name, PageId, Version};
use super::samples::Samples;
use super::values::{Array, Kind, Value, Values};
use crate::{Error, Result};
#[derive(Clone)]
pub struct Table {
pub(crate) name: Name,
pub(crate) ids: RowIds,
pub(crate) index: Arc<OnceLock<Index>>,
pub(crate) fields: Vec<(Name, Field)>,
pub(crate) structure: Version,
pub(crate) order: Version,
}
#[derive(Clone)]
pub(crate) enum Field {
Values(Column, Version),
Reference(Reference),
Sampled(Samples, Version),
}
#[derive(Clone)]
pub(crate) struct Reference {
pub(crate) to: Name,
pub(crate) ids: Column,
pub(crate) rows: Column,
pub(crate) resolved: Arc<[Resolved]>,
pub(crate) version: Version,
pub(crate) inverse: Arc<OnceLock<Inverse>>,
}
pub(crate) const UNWIRED: u32 = u32::MAX;
#[derive(Default)]
pub(crate) struct Inverse {
starts: Vec<u32>,
rows: Vec<u32>,
}
impl Inverse {
pub(crate) fn of(&self, target: usize) -> &[u32] {
match (self.starts.get(target), self.starts.get(target + 1)) {
(Some(&start), Some(&end)) => &self.rows[start as usize..end as usize],
_ => &[],
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub(crate) struct Resolved {
pub(crate) ids: PageId,
pub(crate) order: Version,
pub(crate) structure: Version,
pub(crate) dangling: bool,
}
impl Field {
pub(crate) fn kind(&self) -> Kind {
match self {
Field::Values(column, _) => column.kind(),
Field::Reference(_) => Kind::Reference,
Field::Sampled(..) => Kind::Sampled,
}
}
pub(crate) fn version(&self) -> Version {
match self {
Field::Values(_, v) | Field::Sampled(_, v) => *v,
Field::Reference(r) => r.version,
}
}
pub(crate) fn gather(&self, rows: &[usize]) -> Field {
match self {
Field::Values(column, _) => Field::Values(column.gather(rows), Version::next()),
Field::Reference(reference) => Field::Reference(Reference {
ids: reference.ids.gather(rows),
version: Version::next(),
inverse: Arc::default(),
..reference.clone()
}),
Field::Sampled(samples, _) => Field::Sampled(samples.gather(rows), Version::next()),
}
}
}
impl Reference {
pub(crate) fn new(to: Name, ids: Column) -> Reference {
let rows = Column::missing(&Values::from(Vec::<u32>::new()), 0);
Reference { to, ids, rows, resolved: Arc::new([]), version: Version::next(), inverse: Arc::default() }
}
pub(crate) fn target(&self, row: usize) -> Option<u32> {
match self.rows.get(row)? {
Value::Number(n) => Some(n as u32),
_ => None,
}
}
pub(crate) fn targets(&self) -> Vec<u32> {
let mut out = Vec::with_capacity(self.rows.len());
for page in self.rows.pages() {
let values = &page.values;
match (&values.array, &values.valid) {
(Array::U32(rows), None) => out.extend_from_slice(rows),
(Array::U32(rows), Some(valid)) => {
out.extend(rows.iter().enumerate().map(|(i, &t)| if valid.get(i) { t } else { UNWIRED }));
}
_ => out.extend((0..values.len()).map(|i| match values.get(i) {
Some(Value::Number(n)) => n as u32,
_ => UNWIRED,
})),
}
}
out
}
pub(crate) fn inverse(&self) -> &Inverse {
self.inverse.get_or_init(|| {
let targets = self.targets();
let count = targets.iter().filter(|&&t| t != UNWIRED).max().map_or(0, |&t| t as usize + 1);
let mut starts = vec![0_u32; count + 1];
for &t in targets.iter().filter(|&&t| t != UNWIRED) {
starts[t as usize + 1] += 1;
}
for t in 0..count {
starts[t + 1] += starts[t];
}
let mut next = starts.clone();
let mut rows = vec![0_u32; starts[count] as usize];
for (row, &t) in targets.iter().enumerate() {
if t != UNWIRED {
rows[next[t as usize] as usize] = row as u32;
next[t as usize] += 1;
}
}
Inverse { starts, rows }
})
}
pub(crate) fn resolved_to(
&self,
ids: Column,
targets: &[u32],
order: Version,
structure: Version,
kept: Option<&Reference>,
) -> Reference {
let mut pages = Vec::with_capacity(ids.pages().len());
let mut resolved = Vec::with_capacity(ids.pages().len());
let mut start = 0;
for (p, page) in ids.pages().iter().enumerate() {
let rows = &targets[start..start + page.values.len()];
start += rows.len();
let dangling = (0..rows.len()).any(|i| rows[i] == UNWIRED && page.values.is_valid(i));
let same =
kept.and_then(|k| Some((k.rows.pages().get(p)?, k.ids.pages().get(p)?))).filter(|(old, old_ids)| {
old_ids.id == page.id && matches!(&old.values.array, Array::U32(old) if old[..] == *rows)
});
if let Some((old, _)) = same {
pages.push(old.clone());
} else {
let valid = Bits::from_fn(rows.len(), |i| rows[i] != UNWIRED);
let values = Values { array: Array::U32(rows.to_vec().into()), valid: (!valid.all()).then_some(valid) };
pages.push(Page::new(values));
}
resolved.push(Resolved { ids: page.id, order, structure, dangling });
}
Reference {
to: self.to.clone(),
ids,
rows: Column::of_pages(pages, &Values::from(Vec::<u32>::new())),
resolved: resolved.into(),
version: Version::next(),
inverse: Arc::default(),
}
}
pub(crate) fn stale(&self, order: Version, structure: Version) -> bool {
self.resolved.len() != self.ids.pages().len()
|| self
.ids
.pages()
.iter()
.zip(self.resolved.iter())
.any(|(page, r)| r.ids != page.id || r.order != order || (r.dangling && r.structure != structure))
}
pub(crate) fn resolve(&self, target: &Table) -> Result<Reference> {
let index = target.index()?;
let (order, structure) = (target.order, target.structure);
let mut pages = Vec::with_capacity(self.ids.pages().len());
let mut resolved = Vec::with_capacity(self.ids.pages().len());
for (p, page) in self.ids.pages().iter().enumerate() {
let old = self.resolved.get(p).zip(self.rows.pages().get(p));
if let Some((r, rows)) = old
&& r.ids == page.id
&& r.order == order
&& (!r.dangling || r.structure == structure)
{
pages.push(rows.values.clone());
resolved.push(*r);
continue;
}
let (rows, dangling) = index.resolve(&target.ids, &page.values, UNWIRED);
let valid = Bits::from_fn(rows.len(), |i| rows[i] != UNWIRED);
pages.push(Values { array: Array::U32(rows.into()), valid: (!valid.all()).then_some(valid) });
resolved.push(Resolved { ids: page.id, order, structure, dangling });
}
Ok(Reference {
to: self.to.clone(),
ids: self.ids.clone(),
rows: Column::from_pages(pages, &Values::from(Vec::<u32>::new())),
resolved: resolved.into(),
version: Version::next(),
inverse: Arc::default(),
})
}
}
impl Table {
pub fn new(name: impl Into<Name>, ids: impl Into<Ids>) -> Table {
let version = Version::next();
Table {
name: name.into(),
ids: RowIds::new(&ids.into()),
index: Arc::default(),
fields: Vec::new(),
structure: version,
order: version,
}
}
#[must_use]
pub fn field(mut self, name: impl Into<Name>, values: impl Into<Values>) -> Table {
let column = Column::new(&values.into());
self.insert(name.into(), Field::Values(column, Version::next()));
self
}
#[must_use]
pub fn reference(mut self, name: impl Into<Name>, to: impl Into<Name>, ids: impl Into<Ids>) -> Table {
let ids = match RowIds::new(&ids.into()) {
RowIds::Count(n) => Column::new(&Values::from((0..u64::from(n)).collect::<Vec<_>>())),
RowIds::Listed(column) => column,
};
self.insert(name.into(), Field::Reference(Reference::new(to.into(), ids)));
self
}
pub fn name(&self) -> &Name {
&self.name
}
pub fn len(&self) -> usize {
self.ids.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn ids(&self) -> impl Iterator<Item = Id> + '_ {
(0..self.len()).filter_map(|row| self.ids.id(row))
}
pub fn fields(&self) -> impl Iterator<Item = (&Name, Kind)> + '_ {
self.fields.iter().map(|(name, field)| (name, field.kind()))
}
pub fn kind(&self, name: &str) -> Option<Kind> {
self.field_named(name).map(Field::kind)
}
pub fn get(&self, id: impl Into<Id>, field: &str) -> Option<Value> {
let row = self.row(id.into().as_ref())?;
self.value(row, field, f64::INFINITY)
}
pub fn values(&self, field: &str) -> Option<Values> {
Some(match self.field_named(field)? {
Field::Values(column, _) => column.values(),
Field::Reference(reference) => reference.ids.values(),
Field::Sampled(samples, _) => {
let frame = samples.frame_at(f64::INFINITY);
Values::from((0..self.len()).map(|row| frame.and_then(|f| samples.value(row, f))).collect::<Vec<_>>())
}
})
}
pub(crate) fn value(&self, row: usize, field: &str, at: f64) -> Option<Value> {
match self.field_named(field)? {
Field::Values(column, _) => column.get(row),
Field::Reference(reference) => reference.ids.get(row),
Field::Sampled(samples, _) => samples.value(row, samples.frame_at(at)?).map(Value::Number),
}
}
pub(crate) fn rows(&self, rows: &[usize]) -> Table {
let version = Version::next();
Table {
name: self.name.clone(),
ids: self.ids.gather(rows),
index: Arc::default(),
fields: self.fields.iter().map(|(name, field)| (name.clone(), field.gather(rows))).collect(),
structure: version,
order: version,
}
}
pub(crate) fn row(&self, id: IdRef<'_>) -> Option<usize> {
self.index().ok()?.get(&self.ids, id)
}
pub(crate) fn index(&self) -> Result<&Index> {
if let Some(index) = self.index.get() {
return Ok(index);
}
let index = self.ids.index()?;
Ok(self.index.get_or_init(|| index))
}
pub(crate) fn field_named(&self, name: &str) -> Option<&Field> {
let i = self.fields.binary_search_by(|(n, _)| n.as_str().cmp(name)).ok()?;
Some(&self.fields[i].1)
}
pub(crate) fn insert(&mut self, name: Name, field: Field) {
match self.fields.binary_search_by(|(n, _)| n.cmp(&name)) {
Ok(i) => self.fields[i].1 = field,
Err(i) => self.fields.insert(i, (name, field)),
}
}
pub(crate) fn check(&self) -> Result<()> {
if self.name.is_empty() {
return Err(Error::invalid("a table needs a name"));
}
if let Some(row) = self.ids.hole() {
return Err(Error::invalid("a row needs an id").at(row).at("ids"));
}
self.index().map_err(|e| e.at("ids"))?;
for (name, field) in &self.fields {
let len = match field {
Field::Values(column, _) => column.len(),
Field::Reference(reference) => reference.ids.len(),
Field::Sampled(..) => continue,
};
if len != self.len() {
return Err(Error::invalid(format!("{len} values for {} rows", self.len())).at(name));
}
}
Ok(())
}
}
impl std::fmt::Debug for Table {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Table")
.field("name", &self.name)
.field("rows", &self.len())
.field("fields", &self.fields().collect::<Vec<_>>())
.finish_non_exhaustive()
}
}