///|
priv struct EncodedColumn {
encoding : Int32
dictionary_size : Int32
streams : Array[(Int32, Bytes)]
}
///|
/// Writer deliberately emits RLEv1 DIRECT, allowed in ORC 0.12 files.
fn encode_column(kind : Kind, values : Array[Cell]) -> EncodedColumn {
let streams : Array[(Int32, Bytes)] = []
let present = values.map(x => x != Null)
if present.any(x => !x) {
streams.push((0, encode_bits(present)))
}
let values = values.filter(x => x != Null)
if kind == String && values.length() >= 4 {
let unique : Map[String, Bool] = Map([])
for v in values {
if v is Text(s) {
unique[s] = true
}
}
if unique.length() <= values.length() / 2 {
let dictionary = unique.keys().collect()
dictionary.sort_by(utf8_compare)
let ids : Map[String, Int32] = Map([])
let data = output()
let lengths : Array[UInt64] = []
for i = 0; i < dictionary.length(); i = i + 1 {
let raw = @utf8.encode(dictionary[i])
ids[dictionary[i]] = i
lengths.push(raw.length().to_uint64())
data.raw(raw)
}
let references = values.map(v => {
match v {
Text(s) => ids.get(s).unwrap().to_uint64()
_ => 0UL
}
})
streams.push((1, encode_rle1(references, false)))
streams.push((2, encode_rle1(lengths, false)))
streams.push((3, data.finish()))
return { encoding: 1, dictionary_size: dictionary.length(), streams, }
}
}
let raw = output()
match kind {
Boolean =>
streams.push(
(
1,
encode_bits(
values.map(v => {
match v {
Bool(x) => x
_ => false
}
}),
),
),
)
Byte => {
for v in values {
if v is Integer(x) {
raw.byte(x.to_int())
}
}
streams.push((1, encode_bytes(raw.finish())))
}
Short | Int | Long | Date => {
let ints = values.map(v => {
match v {
Integer(n) => n.reinterpret_as_uint64()
Days(n) => n.to_int64().reinterpret_as_uint64()
_ => 0UL
}
})
streams.push((1, encode_rle1(ints, true)))
}
Float | Double => {
for v in values {
if v is Real(n) {
if kind == Float {
raw.little(
Float::from_double(n).reinterpret_as_uint().to_uint64(),
4,
)
} else {
raw.little(n.reinterpret_as_uint64(), 8)
}
}
}
streams.push((1, raw.finish()))
}
String | Binary => {
let lengths : Array[UInt64] = []
for v in values {
let bytes = match v {
Text(s) => @utf8.encode(s)
Blob(b) => b
_ => b""
}
raw.raw(bytes)
lengths.push(bytes.length().to_uint64())
}
streams.push((1, raw.finish()))
streams.push((2, encode_rle1(lengths, false)))
}
}
{ encoding: 0, dictionary_size: 0, streams, }
}