use super::leaf::put_string;
use crate::schema::typeparse::ChType;
use bytes::{BufMut, BytesMut};
use std::collections::HashMap;
type DictMap = HashMap<Vec<u8>, u64, foldhash::fast::RandomState>;
pub(crate) struct LowCard {
nullable: bool,
map: DictMap,
dict: BytesMut,
dict_count: u64,
keys: Vec<u64>,
}
impl LowCard {
pub(crate) fn build(inner: &ChType) -> Result<LowCard, String> {
let nullable = match inner {
ChType::Named(n) if n == "String" => false,
ChType::Nullable(b) if matches!(&**b, ChType::Named(n) if n == "String") => true,
other => {
return Err(format!(
"LowCardinality({other:?}) — only LowCardinality(String) \
and LowCardinality(Nullable(String)) are supported"
));
}
};
let mut lc = LowCard {
nullable,
map: DictMap::default(),
dict: BytesMut::new(),
dict_count: 0,
keys: Vec::new(),
};
lc.seed();
Ok(lc)
}
fn seed(&mut self) {
if self.nullable {
put_string(&mut self.dict, b"");
put_string(&mut self.dict, b"");
self.dict_count = 2;
self.map.insert(Vec::new(), 1);
} else {
put_string(&mut self.dict, b"");
self.dict_count = 1;
self.map.insert(Vec::new(), 0);
}
}
#[inline]
pub(crate) fn intern(&mut self, value: &[u8]) {
let idx = match self.map.get(value) {
Some(&idx) => idx,
None => {
let idx = self.dict_count;
put_string(&mut self.dict, value);
self.dict_count += 1;
self.map.insert(value.to_vec(), idx);
idx
}
};
self.keys.push(idx);
}
pub(crate) fn push_null(&mut self) {
self.keys.push(0);
}
pub(crate) fn is_nullable(&self) -> bool {
self.nullable
}
pub(crate) fn push_default(&mut self) {
self.keys.push(0);
}
pub(crate) fn write_prefix(&self, out: &mut BytesMut) {
out.put_i64_le(1);
}
pub(crate) fn write_data(&self, out: &mut BytesMut) {
if self.keys.is_empty() {
return;
}
let code = key_width_code(self.dict_count);
out.put_u64_le(0x600 | u64::from(code));
out.put_u64_le(self.dict_count);
out.put_slice(&self.dict);
out.put_u64_le(self.keys.len() as u64);
match code {
0 => {
for &k in &self.keys {
out.put_u8(k as u8);
}
}
1 => {
for &k in &self.keys {
out.put_u16_le(k as u16);
}
}
2 => {
for &k in &self.keys {
out.put_u32_le(k as u32);
}
}
_ => {
for &k in &self.keys {
out.put_u64_le(k);
}
}
}
}
pub(crate) fn reset(&mut self) {
self.map.clear();
self.dict.clear();
self.keys.clear();
self.dict_count = 0;
self.seed();
}
pub(crate) fn byte_len(&self) -> usize {
self.dict.len() + self.keys.len() * 8
}
}
fn key_width_code(dict_size: u64) -> u8 {
if dict_size <= (1 << 8) {
0
} else if dict_size <= (1 << 16) {
1
} else if dict_size <= (1 << 32) {
2
} else {
3
}
}