use std::sync::Arc;
use std::sync::LazyLock;
use vortex_alp::ALP;
use vortex_alp::ALPRD;
use vortex_array::arrays::Bool;
use vortex_array::arrays::Chunked;
use vortex_array::arrays::Constant;
use vortex_array::arrays::Decimal;
use vortex_array::arrays::Dict;
use vortex_array::arrays::Extension;
use vortex_array::arrays::FixedSizeList;
use vortex_array::arrays::List;
use vortex_array::arrays::ListView;
use vortex_array::arrays::Masked;
use vortex_array::arrays::Null;
use vortex_array::arrays::Primitive;
use vortex_array::arrays::Struct;
use vortex_array::arrays::VarBin;
use vortex_array::arrays::VarBinView;
use vortex_array::dtype::FieldPath;
use vortex_array::session::ArrayRegistry;
use vortex_array::session::ArraySession;
#[cfg(feature = "zstd")]
use vortex_btrblocks::BtrBlocksCompressorBuilder;
#[cfg(feature = "zstd")]
use vortex_btrblocks::FloatCode;
#[cfg(feature = "zstd")]
use vortex_btrblocks::IntCode;
#[cfg(feature = "zstd")]
use vortex_btrblocks::StringCode;
use vortex_bytebool::ByteBool;
use vortex_datetime_parts::DateTimeParts;
use vortex_decimal_byte_parts::DecimalByteParts;
use vortex_fastlanes::BitPacked;
use vortex_fastlanes::Delta;
use vortex_fastlanes::FoR;
use vortex_fastlanes::RLE;
use vortex_fsst::FSST;
use vortex_layout::LayoutStrategy;
use vortex_layout::layouts::buffered::BufferedStrategy;
use vortex_layout::layouts::chunked::writer::ChunkedLayoutStrategy;
use vortex_layout::layouts::collect::CollectStrategy;
use vortex_layout::layouts::compressed::CompressingStrategy;
use vortex_layout::layouts::compressed::CompressorPlugin;
use vortex_layout::layouts::dict::writer::DictStrategy;
use vortex_layout::layouts::flat::writer::FlatLayoutStrategy;
use vortex_layout::layouts::repartition::RepartitionStrategy;
use vortex_layout::layouts::repartition::RepartitionWriterOptions;
use vortex_layout::layouts::table::TableStrategy;
use vortex_layout::layouts::zoned::writer::ZonedLayoutOptions;
use vortex_layout::layouts::zoned::writer::ZonedStrategy;
use vortex_pco::Pco;
use vortex_runend::RunEnd;
use vortex_sequence::Sequence;
use vortex_sparse::Sparse;
use vortex_utils::aliases::hash_map::HashMap;
use vortex_zigzag::ZigZag;
#[cfg(feature = "zstd")]
use vortex_zstd::Zstd;
#[cfg(all(feature = "zstd", feature = "unstable_encodings"))]
use vortex_zstd::ZstdBuffers;
const ONE_MEG: u64 = 1 << 20;
pub static ALLOWED_ENCODINGS: LazyLock<ArrayRegistry> = LazyLock::new(|| {
let session = ArraySession::empty();
session.register(Null);
session.register(Bool);
session.register(Primitive);
session.register(Decimal);
session.register(VarBin);
session.register(VarBinView);
session.register(List);
session.register(ListView);
session.register(FixedSizeList);
session.register(Struct);
session.register(Extension);
session.register(Chunked);
session.register(Constant);
session.register(Masked);
session.register(Dict);
session.register(ALP);
session.register(ALPRD);
session.register(BitPacked);
session.register(ByteBool);
session.register(DateTimeParts);
session.register(DecimalByteParts);
session.register(Delta);
session.register(FoR);
session.register(FSST);
session.register(Pco);
session.register(RLE);
session.register(RunEnd);
session.register(Sequence);
session.register(Sparse);
session.register(ZigZag);
#[cfg(feature = "zstd")]
session.register(Zstd);
#[cfg(all(feature = "zstd", feature = "unstable_encodings"))]
session.register(ZstdBuffers);
session.registry().clone()
});
pub struct WriteStrategyBuilder {
compressor: Option<Arc<dyn CompressorPlugin>>,
row_block_size: usize,
field_writers: HashMap<FieldPath, Arc<dyn LayoutStrategy>>,
allow_encodings: Option<ArrayRegistry>,
flat_strategy: Option<Arc<dyn LayoutStrategy>>,
}
impl Default for WriteStrategyBuilder {
fn default() -> Self {
Self {
compressor: None,
row_block_size: 8192,
field_writers: HashMap::new(),
allow_encodings: Some(ALLOWED_ENCODINGS.clone()),
flat_strategy: None,
}
}
}
impl WriteStrategyBuilder {
pub fn with_compressor<C: CompressorPlugin>(mut self, compressor: C) -> Self {
self.compressor = Some(Arc::new(compressor));
self
}
pub fn with_row_block_size(mut self, row_block_size: usize) -> Self {
self.row_block_size = row_block_size;
self
}
pub fn with_field_writer(
mut self,
field: impl Into<FieldPath>,
writer: Arc<dyn LayoutStrategy>,
) -> Self {
self.field_writers.insert(field.into(), writer);
self
}
pub fn with_allow_encodings(mut self, allow_encodings: ArrayRegistry) -> Self {
self.allow_encodings = Some(allow_encodings);
self
}
pub fn with_flat_strategy(mut self, flat: Arc<dyn LayoutStrategy>) -> Self {
self.flat_strategy = Some(flat);
self
}
#[cfg(feature = "zstd")]
pub fn with_cuda_compatible_encodings(mut self) -> Self {
let mut builder = BtrBlocksCompressorBuilder::default()
.exclude_int([IntCode::Sparse, IntCode::Rle])
.exclude_float([FloatCode::Rle, FloatCode::Sparse])
.exclude_string([StringCode::Dict, StringCode::Fsst]);
#[cfg(feature = "unstable_encodings")]
{
builder = builder.include_string([StringCode::ZstdBuffers]);
}
#[cfg(not(feature = "unstable_encodings"))]
{
builder = builder.include_string([StringCode::Zstd]);
}
self.compressor = Some(Arc::new(builder.build()));
self
}
#[cfg(feature = "zstd")]
pub fn with_compact_encodings(mut self) -> Self {
let btrblocks = BtrBlocksCompressorBuilder::default()
.include_string([StringCode::Zstd])
.include_int([IntCode::Pco])
.include_float([FloatCode::Pco])
.build();
self.compressor = Some(Arc::new(btrblocks));
self
}
pub fn build(self) -> Arc<dyn LayoutStrategy> {
let flat: Arc<dyn LayoutStrategy> = if let Some(flat) = self.flat_strategy {
flat
} else if let Some(allow_encodings) = self.allow_encodings {
Arc::new(FlatLayoutStrategy::default().with_allow_encodings(allow_encodings))
} else {
Arc::new(FlatLayoutStrategy::default())
};
let chunked = ChunkedLayoutStrategy::new(flat.clone());
let buffered = BufferedStrategy::new(chunked, 2 * ONE_MEG); let compressing = if let Some(ref compressor) = self.compressor {
CompressingStrategy::new_opaque(buffered, compressor.clone())
} else {
CompressingStrategy::new_btrblocks(buffered, true)
};
let coalescing = RepartitionStrategy::new(
compressing,
RepartitionWriterOptions {
block_size_minimum: ONE_MEG,
block_len_multiple: self.row_block_size,
block_size_target: Some(ONE_MEG),
canonicalize: true,
},
);
let compress_then_flat = if let Some(ref compressor) = self.compressor {
CompressingStrategy::new_opaque(flat, compressor.clone())
} else {
CompressingStrategy::new_btrblocks(flat, false)
};
let dict = DictStrategy::new(
coalescing.clone(),
compress_then_flat.clone(),
coalescing,
Default::default(),
);
let stats = ZonedStrategy::new(
dict,
compress_then_flat.clone(),
ZonedLayoutOptions {
block_size: self.row_block_size,
..Default::default()
},
);
let repartition = RepartitionStrategy::new(
stats,
RepartitionWriterOptions {
block_size_minimum: 0,
block_len_multiple: self.row_block_size,
block_size_target: None,
canonicalize: false,
},
);
let validity_strategy = CollectStrategy::new(compress_then_flat);
let table_strategy = TableStrategy::new(Arc::new(validity_strategy), Arc::new(repartition))
.with_field_writers(self.field_writers);
Arc::new(table_strategy)
}
}