locustdb 0.3.4

Embeddable high-performance analytics database.
Documentation
use crate::engine::data_types::*;
use crate::mem_store::*;
use std::{u16, u32, u8};
use std::convert::From;
use std::sync::Arc;

pub struct IntegerColumn;

impl IntegerColumn {
    pub fn new_boxed(name: &str,
                     mut values: Vec<i64>,
                     mut min: i64,
                     mut max: i64,
                     delta_encode: bool,
                     null: Option<Vec<u8>>) -> Arc<Column> {
        let null = null.map(|mut n| {
            n.shrink_to_fit();
            n
        });
        let original_range = Some((min, max));
        let min0 = min;
        let max0 = max;
        if delta_encode && !values.is_empty() {
            let mut previous = values[0];
            max = previous;
            min = previous;
            for curr in &mut values[1..] {
                let tmp = *curr;
                *curr -= previous;
                previous = tmp;
                if max < *curr { max = *curr }
                if min > *curr { min = *curr }
            }
        }
        let interval = if min < 0 && max > 0 {
            max as u64 + (-min) as u64
        } else {
            (max - min) as u64
        };
        let mut column = if min >= 0 && max <= From::from(u8::MAX) {
            IntegerColumn::create_col::<u8>(name, values, 0, min0, max0, delta_encode, null, EncodingType::U8)
        } else if interval <= From::from(u8::MAX) {
            IntegerColumn::create_col::<u8>(name, values, min, min0, max0, delta_encode, null, EncodingType::U8)
        } else if min >= 0 && max <= From::from(u16::MAX) {
            IntegerColumn::create_col::<u16>(name, values, 0, min0, max0, delta_encode, null, EncodingType::U16)
        } else if interval <= From::from(u16::MAX) {
            IntegerColumn::create_col::<u16>(name, values, min, min0, max0, delta_encode, null, EncodingType::U16)
        } else if min >= 0 && max <= From::from(u32::MAX) {
            IntegerColumn::create_col::<u32>(name, values, 0, min0, max0, delta_encode, null, EncodingType::U32)
        } else if interval <= From::from(u32::MAX) {
            IntegerColumn::create_col::<u32>(name, values, min, min0, max0, delta_encode, null, EncodingType::U32)
        } else {
            values.shrink_to_fit();
            match null {
                Some(present) => if delta_encode {
                    Column::new(
                        name,
                        values.len(),
                        original_range,
                        vec![CodecOp::Delta(EncodingType::I64), CodecOp::PushDataSection(1), CodecOp::Nullable],
                        vec![values.into(), present.into()])
                } else {
                    Column::new(
                        name,
                        values.len(),
                        original_range,
                        vec![CodecOp::PushDataSection(1), CodecOp::Nullable],
                        vec![values.into(), present.into()])
                }
                None => if delta_encode {
                    Column::new(
                        name,
                        values.len(),
                        original_range,
                        vec![CodecOp::Delta(EncodingType::I64)],
                        vec![DataSection::I64(values)])
                } else {
                    Column::new(
                        name,
                        values.len(),
                        original_range,
                        vec![],
                        vec![DataSection::I64(values)])
                }
            }
        };
        column.lz4_encode();
        Arc::new(column)
    }

    #[allow(clippy::too_many_arguments)]
    pub fn create_col<T>(name: &str,
                         values: Vec<i64>,
                         offset: i64,
                         min: i64, max: i64,
                         delta_encode: bool,
                         null_map: Option<Vec<u8>>,
                         t: EncodingType) -> Column
        where T: GenericIntVec<T>, Vec<T>: Into<DataSection> {
        let values = IntegerColumn::encode::<T>(values, offset);
        let len = values.len();
        let codec = if null_map.is_some() {
            match (offset == 0, delta_encode) {
                (true, true) => vec![CodecOp::Delta(t), CodecOp::PushDataSection(1), CodecOp::Nullable],
                (true, false) => vec![CodecOp::PushDataSection(1), CodecOp::Nullable, CodecOp::ToI64(t)],
                (false, true) => vec![CodecOp::Add(t, offset), CodecOp::Delta(EncodingType::I64), CodecOp::PushDataSection(1), CodecOp::Nullable],
                (false, false) => vec![CodecOp::PushDataSection(1), CodecOp::Nullable, CodecOp::Add(t, offset)],
            }
        } else {
            match (offset == 0, delta_encode) {
                (true, true) => vec![CodecOp::Delta(t)],
                (true, false) => vec![CodecOp::ToI64(t)],
                (false, true) => vec![CodecOp::Add(t, offset), CodecOp::Delta(EncodingType::I64)],
                (false, false) => vec![CodecOp::Add(t, offset)],
            }
        };

        Column::new(
            name,
            len,
            Some((min - offset, max - offset)),
            codec,
            if let Some(present) = null_map { vec![values.into(), present.into()] } else { vec![values.into()] })
    }

    pub fn encode<T: GenericIntVec<T>>(values: Vec<i64>, offset: i64) -> Vec<T> {
        let mut encoded_vals = Vec::with_capacity(values.len());
        for v in values {
            let encoded_val = T::from(v - offset);
            if encoded_val.is_none() {
                unreachable!("{} {}", v, offset);
            }
            encoded_vals.push(encoded_val.unwrap());
        }
        encoded_vals
    }
}