handlegraph 0.7.0-alpha.9

Library for use in variation graphs
Documentation
use super::paged::PagedIntVec;
use super::vector::PackedIntVec;

use super::traits::*;

#[derive(Debug, Clone)]
pub struct RobustPagedIntVec {
    first_page: PackedIntVec,
    other_pages: PagedIntVec,
}

crate::impl_space_usage!(RobustPagedIntVec, [first_page, other_pages]);

impl RobustPagedIntVec {
    pub fn new(page_size: usize) -> Self {
        let width = 64 - page_size.leading_zeros() as usize;
        let first_page = PackedIntVec::new_with_width(width);
        let other_pages = PagedIntVec::new_with_width(page_size, width);
        Self {
            first_page,
            other_pages,
        }
    }

    pub fn resize(&mut self, new_size: usize) {
        if new_size > self.page_width() {
            self.first_page.resize(self.page_width());
            self.other_pages.resize(new_size - self.page_width());
        } else {
            self.first_page.resize(new_size);
            self.other_pages.clear();
        }
    }

    pub fn reserve(&mut self, capacity: usize) {
        if capacity > self.page_width() {
            self.first_page.reserve(self.page_width());
            self.other_pages.reserve(capacity - self.page_width());
        } else {
            self.first_page.reserve(capacity);
        }
    }

    #[inline]
    pub fn page_width(&self) -> usize {
        self.other_pages.page_width()
    }

    #[inline]
    pub fn page_size(&self) -> usize {
        self.other_pages.page_width()
    }

    #[inline]
    pub fn append_pages(&mut self, buf: &mut Vec<u64>, mut data: &[u64]) {
        if data.is_empty() {
            return;
        }

        if self.first_page.len() < self.page_width() {
            let first_page_slots = self.page_width() - self.first_page.len();
            let split_index = first_page_slots.min(data.len());
            let (page, rest) = data.split_at(split_index);
            self.first_page.append_slice(page);
            data = rest;
        }

        if !data.is_empty() {
            self.other_pages.append_pages(buf, data);
        }
    }

    pub fn print_diagnostics(&self) {
        println!("First page");
        print!(" -- ");
        self.first_page.print_diagnostics();
        println!("Other pages");
        self.other_pages.print_diagnostics();
    }
}

impl PackedCollection for RobustPagedIntVec {
    #[inline]
    fn len(&self) -> usize {
        self.first_page.len() + self.other_pages.len()
    }

    #[inline]
    fn is_empty(&self) -> bool {
        self.first_page.is_empty() && self.other_pages.is_empty()
    }

    #[inline]
    fn clear(&mut self) {
        self.first_page.clear();
        self.other_pages.clear();
    }

    #[inline]
    fn set(&mut self, index: usize, value: u64) {
        if index < self.page_width() {
            self.first_page.set(index, value);
        } else {
            self.other_pages.set(index - self.page_width(), value);
        }
    }

    #[inline]
    fn get(&self, index: usize) -> u64 {
        if index < self.page_width() {
            self.first_page.get(index)
        } else {
            self.other_pages.get(index - self.page_width())
        }
    }

    #[inline]
    fn append(&mut self, value: u64) {
        if self.first_page.len() < self.page_width() {
            self.first_page.append(value);
        } else {
            self.other_pages.append(value);
        }
    }

    #[inline]
    fn pop(&mut self) {
        if self.other_pages.is_empty() {
            self.first_page.pop()
        } else {
            self.other_pages.pop()
        }
    }
}

#[cfg(test)]
mod tests {

    use super::*;
    use quickcheck::{quickcheck, Arbitrary, Gen};

    impl Arbitrary for RobustPagedIntVec {
        fn arbitrary<G: Gen>(g: &mut G) -> RobustPagedIntVec {
            let only_first = bool::arbitrary(g);

            let page_pow = u32::arbitrary(g) % 4;
            let page_size = 16 << page_pow;

            assert!(page_size % 2 == 0 && page_size >= 16 && page_size <= 256);
            let mut paged = RobustPagedIntVec::new(page_size);
            let mut values: Vec<u64> = Vec::arbitrary(g);

            if !only_first {
                while values.len() < page_size {
                    let v = u64::arbitrary(g);
                    values.push(v);
                }
            }

            values.into_iter().for_each(|v| paged.append(v));

            paged
        }
    }

    quickcheck! {
        fn prop_robust_append(paged: RobustPagedIntVec, value: u64) -> bool {
            let mut paged = paged;

            let entries_before = paged.len();

            paged.append(value);

            let entries_correct = paged.len() == entries_before + 1;
            let last_val_correct = paged.get(paged.len() - 1) == value;

            entries_correct && last_val_correct
        }
    }

    quickcheck! {
        fn prop_robust_set(paged: RobustPagedIntVec, ix: usize, value: u64) -> bool {
            let mut paged = paged;
            if paged.len() == 0 {
                return true;
            }
            let ix = ix % paged.len();

            let len_before = paged.len();
            paged.set(ix, value);

            let set_correct = paged.get(ix) == value;
            let len_correct = paged.len() == len_before;

            set_correct && len_correct
        }
    }

    quickcheck! {
        fn prop_robust_pop(paged: RobustPagedIntVec) -> bool {
            let mut paged = paged;

            let len_before = paged.len();

            paged.pop();

            if len_before == 0 {
                paged.len() == 0
            } else {
                paged.len() == len_before - 1
            }
        }
    }
}