use std::sync::Arc;
use linkrs_core::types::VertexId;
use linkrs_core::{EdgeHeader, Value};
#[derive(Debug, Clone)]
pub struct EdgeHeaderColumn {
src: Vec<VertexId>,
dst: Vec<VertexId>,
edge_type: Vec<Arc<str>>,
ranking: Vec<i64>,
}
impl EdgeHeaderColumn {
pub(crate) fn from_parts(
src: Vec<VertexId>,
dst: Vec<VertexId>,
edge_type: Vec<String>,
ranking: Vec<i64>,
) -> Self {
debug_assert!(
src.len() == dst.len() && src.len() == edge_type.len() && src.len() == ranking.len(),
"edge identity vectors must share one length"
);
let edge_type = edge_type
.into_iter()
.map(|s| Arc::from(s.as_str()))
.collect();
Self {
src,
dst,
edge_type,
ranking,
}
}
pub(crate) fn len(&self) -> usize {
self.src.len()
}
pub(crate) fn estimated_size(&self) -> usize {
self.src.capacity() * std::mem::size_of::<VertexId>()
+ self.dst.capacity() * std::mem::size_of::<VertexId>()
+ self.edge_type.iter().map(|s| s.len()).sum::<usize>()
+ self.ranking.capacity() * std::mem::size_of::<i64>()
}
pub(crate) fn header_at(&self, idx: usize) -> Option<EdgeHeader> {
match (
self.src.get(idx),
self.dst.get(idx),
self.edge_type.get(idx),
self.ranking.get(idx),
) {
(Some(&src), Some(&dst), Some(edge_type), Some(&ranking)) => {
Some(EdgeHeader::new(src, dst, edge_type.to_string(), ranking))
}
_ => None,
}
}
pub(crate) fn to_values(&self) -> Vec<Value> {
self.src
.iter()
.zip(self.dst.iter())
.zip(self.edge_type.iter())
.zip(self.ranking.iter())
.map(|(((src, dst), edge_type), ranking)| {
Value::edge_header(EdgeHeader::new(*src, *dst, edge_type.to_string(), *ranking))
})
.collect()
}
pub(crate) fn gather(&self, indices: &[usize]) -> Self {
Self {
src: indices.iter().map(|&i| self.src[i]).collect(),
dst: indices.iter().map(|&i| self.dst[i]).collect(),
edge_type: indices.iter().map(|&i| self.edge_type[i].clone()).collect(),
ranking: indices.iter().map(|&i| self.ranking[i]).collect(),
}
}
pub(crate) fn truncate(&mut self, len: usize) {
self.src.truncate(len);
self.dst.truncate(len);
self.edge_type.truncate(len);
self.ranking.truncate(len);
}
pub(crate) fn permute(&mut self, perm: &[usize]) {
let old = std::mem::replace(
self,
Self {
src: Vec::new(),
dst: Vec::new(),
edge_type: Vec::new(),
ranking: Vec::new(),
},
);
self.src = perm.iter().map(|&i| old.src[i]).collect();
self.dst = perm.iter().map(|&i| old.dst[i]).collect();
self.edge_type = perm.iter().map(|&i| old.edge_type[i].clone()).collect();
self.ranking = perm.iter().map(|&i| old.ranking[i]).collect();
}
pub(crate) fn extend_indexed(&mut self, other: &Self, indices: &[usize]) {
self.src.extend(indices.iter().map(|&i| other.src[i]));
self.dst.extend(indices.iter().map(|&i| other.dst[i]));
self.edge_type
.extend(indices.iter().map(|&i| other.edge_type[i].clone()));
self.ranking
.extend(indices.iter().map(|&i| other.ranking[i]));
}
pub(crate) fn push(&mut self, src: VertexId, dst: VertexId, edge_type: &str, ranking: i64) {
self.src.push(src);
self.dst.push(dst);
self.edge_type.push(Arc::from(edge_type));
self.ranking.push(ranking);
}
}
#[inline]
pub(crate) fn bitmap_is_valid(bitmap: &[u64], idx: usize) -> bool {
bitmap[idx / 64] & (1u64 << (idx % 64)) != 0
}
#[inline]
pub(crate) fn bitmap_set_bit(bitmap: &mut [u64], idx: usize, valid: bool) {
if valid {
bitmap[idx / 64] |= 1u64 << (idx % 64);
} else {
bitmap[idx / 64] &= !(1u64 << (idx % 64));
}
}
pub(crate) fn gather_bitmap(bitmap: &[u64], indices: &[usize]) -> Vec<u64> {
let mut out = vec![0u64; indices.len().div_ceil(64)];
for (j, &i) in indices.iter().enumerate() {
bitmap_set_bit(&mut out, j, bitmap_is_valid(bitmap, i));
}
out
}
macro_rules! column_variants {
($name:ident $(, $extra:ident)*) => {
#[derive(Debug, Clone)]
pub enum $name {
$($extra,)*
I64(Vec<i64>),
F64(Vec<f64>),
I32(Vec<i32>),
Bool(Vec<bool>),
Date(Vec<i64>),
DateTime(Vec<i64>),
Utf8(Vec<Arc<str>>),
Decimal(Vec<Decimal128Value>),
NullableI64(Vec<i64>, Vec<u64>),
NullableF64(Vec<f64>, Vec<u64>),
NullableI32(Vec<i32>, Vec<u64>),
NullableBool(Vec<bool>, Vec<u64>),
NullableDate(Vec<i64>, Vec<u64>),
NullableDateTime(Vec<i64>, Vec<u64>),
NullableUtf8(Vec<Arc<str>>, Vec<u64>),
NullableDecimal(Vec<Decimal128Value>, Vec<u64>),
VertexIdentity(Vec<linkrs_core::types::VertexId>),
EdgeHeader(EdgeHeaderColumn),
Fallback(Vec<Value>),
}
impl $name {
pub fn len(&self) -> usize {
match self {
$($name::$extra => 0,)*
$name::I64(v) => v.len(),
$name::F64(v) => v.len(),
$name::I32(v) => v.len(),
$name::Bool(v) => v.len(),
$name::Date(v) => v.len(),
$name::DateTime(v) => v.len(),
$name::Utf8(v) => v.len(),
$name::Decimal(v) => v.len(),
$name::NullableI64(v, _) => v.len(),
$name::NullableF64(v, _) => v.len(),
$name::NullableI32(v, _) => v.len(),
$name::NullableBool(v, _) => v.len(),
$name::NullableDate(v, _) => v.len(),
$name::NullableDateTime(v, _) => v.len(),
$name::NullableUtf8(v, _) => v.len(),
$name::NullableDecimal(v, _) => v.len(),
$name::VertexIdentity(v) => v.len(),
$name::EdgeHeader(v) => v.len(),
$name::Fallback(v) => v.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn estimated_size(&self) -> usize {
match self {
$($name::$extra => 0,)*
$name::I64(v) => v.capacity() * std::mem::size_of::<i64>(),
$name::F64(v) => v.capacity() * std::mem::size_of::<f64>(),
$name::I32(v) => v.capacity() * std::mem::size_of::<i32>(),
$name::Bool(v) => v.capacity() * std::mem::size_of::<bool>(),
$name::Date(v) => v.capacity() * std::mem::size_of::<i64>(),
$name::DateTime(v) => v.capacity() * std::mem::size_of::<i64>(),
$name::Utf8(v) => v.iter().map(|s| s.len()).sum(),
$name::Decimal(v) => v.capacity() * std::mem::size_of::<Decimal128Value>(),
$name::NullableI64(v, b) => {
v.capacity() * std::mem::size_of::<i64>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::NullableF64(v, b) => {
v.capacity() * std::mem::size_of::<f64>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::NullableI32(v, b) => {
v.capacity() * std::mem::size_of::<i32>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::NullableBool(v, b) => {
v.capacity() * std::mem::size_of::<bool>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::NullableDate(v, b) => {
v.capacity() * std::mem::size_of::<i64>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::NullableDateTime(v, b) => {
v.capacity() * std::mem::size_of::<i64>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::NullableUtf8(v, b) => {
v.iter().map(|s| s.len()).sum::<usize>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::NullableDecimal(v, b) => {
v.capacity() * std::mem::size_of::<Decimal128Value>()
+ b.capacity() * std::mem::size_of::<u64>()
}
$name::VertexIdentity(v) => {
v.capacity() * std::mem::size_of::<linkrs_core::types::VertexId>()
}
$name::EdgeHeader(v) => v.estimated_size(),
$name::Fallback(v) => v.iter().map(Value::estimated_size).sum(),
}
}
}
};
}
pub(crate) use column_variants;
macro_rules! gather_column {
($out:ident, $col:expr, $indices:expr) => {{
let indices: &[usize] = $indices;
match $col {
TypedColumn::I64(v) => $out::I64(indices.iter().map(|&i| v[i]).collect()),
TypedColumn::F64(v) => $out::F64(indices.iter().map(|&i| v[i]).collect()),
TypedColumn::I32(v) => $out::I32(indices.iter().map(|&i| v[i]).collect()),
TypedColumn::Bool(v) => $out::Bool(indices.iter().map(|&i| v[i]).collect()),
TypedColumn::Date(v) => $out::Date(indices.iter().map(|&i| v[i]).collect()),
TypedColumn::DateTime(v) => $out::DateTime(indices.iter().map(|&i| v[i]).collect()),
TypedColumn::Utf8(v) => $out::Utf8(indices.iter().map(|&i| v[i].clone()).collect()),
TypedColumn::Decimal(v) => {
$out::Decimal(indices.iter().map(|&i| v[i].clone()).collect())
}
TypedColumn::NullableI64(v, b) => $out::NullableI64(
indices.iter().map(|&i| v[i]).collect(),
gather_bitmap(b, indices),
),
TypedColumn::NullableF64(v, b) => $out::NullableF64(
indices.iter().map(|&i| v[i]).collect(),
gather_bitmap(b, indices),
),
TypedColumn::NullableI32(v, b) => $out::NullableI32(
indices.iter().map(|&i| v[i]).collect(),
gather_bitmap(b, indices),
),
TypedColumn::NullableBool(v, b) => $out::NullableBool(
indices.iter().map(|&i| v[i]).collect(),
gather_bitmap(b, indices),
),
TypedColumn::NullableDate(v, b) => $out::NullableDate(
indices.iter().map(|&i| v[i]).collect(),
gather_bitmap(b, indices),
),
TypedColumn::NullableDateTime(v, b) => $out::NullableDateTime(
indices.iter().map(|&i| v[i]).collect(),
gather_bitmap(b, indices),
),
TypedColumn::NullableUtf8(v, b) => $out::NullableUtf8(
indices.iter().map(|&i| v[i].clone()).collect(),
gather_bitmap(b, indices),
),
TypedColumn::NullableDecimal(v, b) => $out::NullableDecimal(
indices.iter().map(|&i| v[i].clone()).collect(),
gather_bitmap(b, indices),
),
TypedColumn::VertexIdentity(v) => {
$out::VertexIdentity(indices.iter().map(|&i| v[i]).collect())
}
TypedColumn::EdgeHeader(v) => $out::EdgeHeader(v.gather(indices)),
TypedColumn::Fallback(v) => {
$out::Fallback(indices.iter().map(|&i| v[i].clone()).collect())
}
}
}};
}
pub(crate) use gather_column;