<commit_before>extern crate walkdir;
extern crate phf_codegen;
extern crate flate2;

use std::{env, fmt, io};
use std::borrow::{Borrow, Cow};
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

use walkdir::WalkDir;

use flate2::write::GzEncoder;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Compression {
    None,
    Gzip,
    Passthrough,
}

impl fmt::Display for Compression {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Compression::None => fmt.write_str("None"),
            Compression::Gzip => fmt.write_str("Gzip"),
            Compression::Passthrough => panic!("Should not be called"),
        }
    }
}

pub struct IncludeDir {
    files: HashMap<String, (Compression, PathBuf)>,
    name: String,
    passthrough: bool,
    manifest_dir: PathBuf
}

pub fn start(static_name: &str) -> IncludeDir {
    IncludeDir {
        files: HashMap::new(),
        name: static_name.to_owned(),
        passthrough: false,
        manifest_dir: Path::new(&env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not set")).to_owned()
    }
}

#[cfg(windows)]
fn as_key(path: &str) -> Cow<str> {
    Cow::Owned(path.replace("\\", "/"))
}

#[cfg(not(windows))]
fn as_key(path: &str) -> Cow<str> {
    Cow::Borrowed(path)
}

impl IncludeDir {
    /// Don't include any data, but read from the source directory instead.
    pub fn passthrough(&mut self) -> &mut IncludeDir {
        self.passthrough = true;
        self
    }

    /// Add a single file to the binary.
    /// With Gzip compression, the file will be encoded to OUT_DIR first.
    /// For chaining, it's not sensible to return a Result. If any to-be-included
    /// files can't be found, or encoded, this function will panic!.
    pub fn file<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> &mut IncludeDir {
        self.add_file(path, comp).unwrap();
        self
    }

    /// ## Panics
    ///
    /// This function panics when CARGO_MANIFEST_DIR or OUT_DIR are not defined.
    pub fn add_file<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> io::Result<()> {
        let key = path.as_ref().to_string_lossy();
        println!("cargo:rerun-if-changed={}", self.manifest_dir.join(&path).display());

        match comp {
            c if self.passthrough || c == Compression::Passthrough => {
                self.files.insert(as_key(key.borrow()).into_owned(),
                                  (Compression::Passthrough, PathBuf::new()));
            }
            Compression::None => {
                self.files.insert(as_key(key.borrow()).into_owned(),
                                  (comp, path.as_ref().clone().to_owned()));
            }
            Compression::Gzip => {
                // gzip encode file to OUT_DIR
                let in_path = self.manifest_dir.join(&path);
                let mut in_file = BufReader::new(File::open(&in_path)?);

                let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join(&path);
                fs::create_dir_all(&out_path.parent().unwrap())?;
                let out_file = BufWriter::new(File::create(&out_path)?);
                let mut encoder = GzEncoder::new(out_file, flate2::Compression::best());

                io::copy(&mut in_file, &mut encoder)?;

                self.files.insert(as_key(key.borrow()).into_owned(),
                                  (comp, out_path.to_owned()));
            }
            _ => unreachable!(),
        }
        Ok(())
    }

    /// Add a whole directory recursively to the binary.
    /// This function calls `file`, and therefore will panic! on missing files.
    pub fn dir<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> &mut IncludeDir {
        self.add_dir(path, comp).unwrap();
        self
    }

    /// ## Panics
    ///
    /// This function panics when CARGO_MANIFEST_DIR or OUT_DIR are not defined.
    pub fn add_dir<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> io::Result<()> {
        for entry in WalkDir::new(path).follow_links(true).into_iter() {
            match entry {
                Ok(ref e) if !e.file_type().is_dir() => {
                    self.add_file(e.path(), comp)?;
                }
                _ => (),
            }
        }
        Ok(())
    }

    pub fn build(self, out_name: &str) -> io::Result<()> {
        let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join(out_name);
        let mut out_file = BufWriter::new(File::create(&out_path)?);

        write!(&mut out_file,
               "use includedir::*;\n\
                pub static {}: Files = Files {{\n\
                    files:  ",
                self.name)?;

        let mut map: phf_codegen::Map<String> = phf_codegen::Map::new();

        for (name, (compression, path)) in self.files {
            let include_path = format!("{}", self.manifest_dir.join(path).display());

            if compression == Compression::Passthrough {
                map.entry(as_key(&name).into_owned(),
                          "(Compression::Passthrough, &[] as &'static [u8])");
            } else {
                map.entry(as_key(&name).into_owned(),
                          &format!("(Compression::{}, \
                                    include_bytes!(\"{}\") as &'static [u8])",
                                   compression, as_key(&include_path)));
            }
        }

        map.build(&mut out_file)?;

        write!(&mut out_file, "\n}};\n")?;
        Ok(())
    }
}
<commit_msg>Emit relative paths for rerun-if-changed<commit_after>extern crate walkdir;
extern crate phf_codegen;
extern crate flate2;

use std::{env, fmt, io};
use std::borrow::{Borrow, Cow};
use std::collections::HashMap;
use std::fs::{self, File};
use std::io::{BufReader, BufWriter, Write};
use std::path::{Path, PathBuf};

use walkdir::WalkDir;

use flate2::write::GzEncoder;

#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Compression {
    None,
    Gzip,
    Passthrough,
}

impl fmt::Display for Compression {
    fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
        match *self {
            Compression::None => fmt.write_str("None"),
            Compression::Gzip => fmt.write_str("Gzip"),
            Compression::Passthrough => panic!("Should not be called"),
        }
    }
}

pub struct IncludeDir {
    files: HashMap<String, (Compression, PathBuf)>,
    name: String,
    passthrough: bool,
    manifest_dir: PathBuf
}

pub fn start(static_name: &str) -> IncludeDir {
    IncludeDir {
        files: HashMap::new(),
        name: static_name.to_owned(),
        passthrough: false,
        manifest_dir: Path::new(&env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not set")).to_owned()
    }
}

#[cfg(windows)]
fn as_key(path: &str) -> Cow<str> {
    Cow::Owned(path.replace("\\", "/"))
}

#[cfg(not(windows))]
fn as_key(path: &str) -> Cow<str> {
    Cow::Borrowed(path)
}

impl IncludeDir {
    /// Don't include any data, but read from the source directory instead.
    pub fn passthrough(&mut self) -> &mut IncludeDir {
        self.passthrough = true;
        self
    }

    /// Add a single file to the binary.
    /// With Gzip compression, the file will be encoded to OUT_DIR first.
    /// For chaining, it's not sensible to return a Result. If any to-be-included
    /// files can't be found, or encoded, this function will panic!.
    pub fn file<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> &mut IncludeDir {
        self.add_file(path, comp).unwrap();
        self
    }

    /// ## Panics
    ///
    /// This function panics when CARGO_MANIFEST_DIR or OUT_DIR are not defined.
    pub fn add_file<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> io::Result<()> {
        let key = path.as_ref().to_string_lossy();
        println!("cargo:rerun-if-changed={}", path.as_ref().display());

        match comp {
            c if self.passthrough || c == Compression::Passthrough => {
                self.files.insert(as_key(key.borrow()).into_owned(),
                                  (Compression::Passthrough, PathBuf::new()));
            }
            Compression::None => {
                self.files.insert(as_key(key.borrow()).into_owned(),
                                  (comp, path.as_ref().clone().to_owned()));
            }
            Compression::Gzip => {
                // gzip encode file to OUT_DIR
                let in_path = self.manifest_dir.join(&path);
                let mut in_file = BufReader::new(File::open(&in_path)?);

                let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join(&path);
                fs::create_dir_all(&out_path.parent().unwrap())?;
                let out_file = BufWriter::new(File::create(&out_path)?);
                let mut encoder = GzEncoder::new(out_file, flate2::Compression::best());

                io::copy(&mut in_file, &mut encoder)?;

                self.files.insert(as_key(key.borrow()).into_owned(),
                                  (comp, out_path.to_owned()));
            }
            _ => unreachable!(),
        }
        Ok(())
    }

    /// Add a whole directory recursively to the binary.
    /// This function calls `file`, and therefore will panic! on missing files.
    pub fn dir<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> &mut IncludeDir {
        self.add_dir(path, comp).unwrap();
        self
    }

    /// ## Panics
    ///
    /// This function panics when CARGO_MANIFEST_DIR or OUT_DIR are not defined.
    pub fn add_dir<P: AsRef<Path>>(&mut self, path: P, comp: Compression) -> io::Result<()> {
        for entry in WalkDir::new(path).follow_links(true).into_iter() {
            match entry {
                Ok(ref e) if !e.file_type().is_dir() => {
                    self.add_file(e.path(), comp)?;
                }
                _ => (),
            }
        }
        Ok(())
    }

    pub fn build(self, out_name: &str) -> io::Result<()> {
        let out_path = Path::new(&env::var("OUT_DIR").unwrap()).join(out_name);
        let mut out_file = BufWriter::new(File::create(&out_path)?);

        write!(&mut out_file,
               "use includedir::*;\n\
                pub static {}: Files = Files {{\n\
                    files:  ",
                self.name)?;

        let mut map: phf_codegen::Map<String> = phf_codegen::Map::new();

        for (name, (compression, path)) in self.files {
            let include_path = format!("{}", self.manifest_dir.join(path).display());

            if compression == Compression::Passthrough {
                map.entry(as_key(&name).into_owned(),
                          "(Compression::Passthrough, &[] as &'static [u8])");
            } else {
                map.entry(as_key(&name).into_owned(),
                          &format!("(Compression::{}, \
                                    include_bytes!(\"{}\") as &'static [u8])",
                                   compression, as_key(&include_path)));
            }
        }

        map.build(&mut out_file)?;

        write!(&mut out_file, "\n}};\n")?;
        Ok(())
    }
}
<|endoftext|>


<commit_before>use hermes::stm::Txn;
use hermes::stm::TxnErr;
use hermes::stm::TxnValRef;
use index::btree::Slice;
use index::btree::*;
use itertools::free::chain;
use std::cell::UnsafeCell;
use std::mem;
use std::sync::atomic::AtomicPtr;
use std::sync::Arc;

pub struct InNode {
    pub keys: EntryKeySlice,
    pub ptrs: NodePtrCellSlice,
    pub len: usize,
    pub right: NodeCellRef,
}

pub struct InNodeKeysSplit {
    pub keys_2: EntryKeySlice,
    pub keys_1_len: usize,
    pub keys_2_len: usize,
    pub pivot_key: EntryKey,
}

pub struct InNodePtrSplit {
    pub ptrs_2: NodePtrCellSlice,
}

impl InNode {
    pub fn key_pos_from_ptr_pos(&self, ptr_pos: usize) -> usize {
        if ptr_pos == 0 {
            0
        } else {
            ptr_pos - 1
        }
    }
    pub fn search(&self, key: &EntryKey) -> usize {
        self.keys[..self.len]
            .binary_search(key)
            .map(|i| i + 1)
            .unwrap_or_else(|i| i)
    }
    pub fn remove_at(&mut self, ptr_pos: usize) {
        let mut n_key_len = self.len;
        let mut n_ptr_len = n_key_len + 1;
        let key_pos = self.key_pos_from_ptr_pos(ptr_pos);
        debug!(
            "Removing from internal node pos {}, len {}",
            key_pos, n_key_len
        );
        self.keys.remove_at(key_pos, &mut n_key_len);
        self.ptrs.remove_at(ptr_pos, &mut n_ptr_len);
        self.len = n_key_len;
    }
    pub fn insert(
        &mut self,
        key: EntryKey,
        new_node: NodeCellRef,
        parent: &NodeCellRef,
    ) -> Option<NodeSplit> {
        let node_len = self.len;
        let ptr_len = self.len + 1;
        let pos = self.search(&key);
        debug!("Insert into internal node at {}, key: {:?}", pos, key);
        debug_assert!(node_len <= NUM_KEYS);
        if node_len == NUM_KEYS {
            let pivot = node_len / 2; // pivot key will be removed
            debug!("Going to split at pivot {}", pivot);
            let parent_guard = parent.write();
            let keys_split = {
                debug!("insert into keys");
                if pivot == pos {
                    debug!("special key treatment when pivot == pos");
                    let mut keys_1 = &mut self.keys;
                    let mut keys_2 = keys_1.split_at_pivot(pivot, node_len);
                    let mut keys_1_len = pivot;
                    let mut keys_2_len = node_len - pivot;
                    let pivot_key = key;
                    InNodeKeysSplit {
                        keys_2,
                        keys_1_len,
                        keys_2_len,
                        pivot_key,
                    }
                } else {
                    let mut keys_1 = &mut self.keys;
                    let mut keys_2 = keys_1.split_at_pivot(pivot + 1, node_len);
                    let mut keys_1_len = pivot; // will not count the pivot
                    let mut keys_2_len = node_len - pivot - 1;
                    let mut key_pos = pos;
                    if pos > pivot {
                        // pivot moved, need to compensate
                        key_pos -= 1;
                    }
                    debug!(
                        "keys 1 len: {}, keys 2 len: {}, pos {}",
                        keys_1_len, keys_2_len, key_pos
                    );
                    debug_assert_ne!(pivot, pos);
                    let pivot_key = keys_1[pivot].to_owned();
                    insert_into_split(
                        key,
                        keys_1,
                        &mut keys_2,
                        &mut keys_1_len,
                        &mut keys_2_len,
                        key_pos,
                    );
                    InNodeKeysSplit {
                        keys_2,
                        keys_1_len,
                        keys_2_len,
                        pivot_key,
                    }
                }
            };
            let ptr_split = {
                if pivot == pos {
                    debug!("special ptr treatment when pivot == pos");
                    let mut ptrs_1 = &mut self.ptrs;
                    let mut ptrs_2 = ptrs_1.split_at_pivot(pivot + 1, ptr_len);
                    let mut ptrs_1_len = pivot + 1;
                    let mut ptrs_2_len = ptr_len - pivot - 1;
                    ptrs_2.insert_at(new_node, 0, &mut ptrs_2_len);
                    debug_assert_eq!(ptrs_1_len, keys_split.keys_1_len + 1);
                    debug_assert_eq!(ptrs_2_len, keys_split.keys_2_len + 1);
                    InNodePtrSplit { ptrs_2 }
                } else {
                    debug!("insert into ptrs");
                    let mut ptrs_1 = &mut self.ptrs;
                    let mut ptrs_2 = ptrs_1.split_at_pivot(pivot + 1, ptr_len);
                    let mut ptrs_1_len = pivot + 1;
                    let mut ptrs_2_len = ptr_len - pivot - 1;
                    let mut ptr_pos = pos + 1;
                    insert_into_split(
                        new_node,
                        ptrs_1,
                        &mut ptrs_2,
                        &mut ptrs_1_len,
                        &mut ptrs_2_len,
                        ptr_pos,
                    );
                    debug_assert_eq!(ptrs_1_len, keys_split.keys_1_len + 1);
                    debug_assert_eq!(ptrs_2_len, keys_split.keys_2_len + 1);
                    InNodePtrSplit { ptrs_2 }
                }
            };
            let node_2 = InNode {
                len: keys_split.keys_2_len,
                keys: keys_split.keys_2,
                ptrs: ptr_split.ptrs_2,
                right: self.right.clone(),
            };
            let node_2_ref = Arc::new(Node::internal(node_2));
            self.len = keys_split.keys_1_len;
            self.right = node_2_ref.clone();
            return Some(NodeSplit {
                new_right_node: node_2_ref,
                left_node_latch: NodeWriteGuard::default(),
                pivot: keys_split.pivot_key,
                parent_latch: parent_guard,
            });
        } else {
            let mut new_node_len = node_len;
            let mut new_node_pointers = node_len + 1;
            self.keys.insert_at(key, pos, &mut new_node_len);
            self.ptrs
                .insert_at(new_node, pos + 1, &mut new_node_pointers);
            self.len = new_node_len;
            return None;
        }
    }
    pub fn rebalance_candidate(&self, pointer_pos: usize) -> usize {
        debug_assert!(pointer_pos <= self.len);
        debug!(
            "Searching for rebalance candidate, pos {}, len {}",
            pointer_pos, self.len
        );
        if pointer_pos == 0 {
            1
        } else if pointer_pos + 1 >= self.len {
            // the last one, pick left
            pointer_pos - 1
        } else {
            // pick the right one
            // we should pick the one  with least pointers, but it cost for the check is too high
            pointer_pos + 1
        }
    }
    pub fn merge_children(
        &mut self,
        left_ptr_pos: usize,
        right_ptr_pos: usize,
        left_node: &mut NodeData,
        right_node: &mut NodeData,
        right_node_next: &mut NodeData,
    ) -> Result<(), TxnErr> {
        let left_node_ref = self.ptrs[left_ptr_pos].clone();
        let left_len = left_node.len();
        let right_len = right_node.len();
        let right_key_pos = self.key_pos_from_ptr_pos(right_ptr_pos);
        let mut merged_len = 0;
        debug!("Merge children, left len {}, right len {}, left_ptr_pos {}, right_ptr_pos {}, right_key_pos {}",
                left_len, right_len, left_ptr_pos, right_ptr_pos, right_key_pos);
        debug_assert_eq!(left_node.is_ext(), right_node.is_ext());
        if !left_node.is_ext() {
            {
                let mut left_innode = left_node.innode_mut();
                let mut right_innode = right_node.innode_mut();
                let right_key = self.keys[right_key_pos].clone();
                left_innode.merge_with(&mut right_innode, right_key);
                left_innode.right = right_innode.right.clone();
                merged_len = left_innode.len;
            }
        } else {
            let mut right_extnode = right_node.extnode_mut();
            let mut left_extnode = left_node.extnode_mut();
            {
                left_extnode.merge_with(&mut right_extnode);
                merged_len = left_extnode.len;
            }
            if !right_node_next.is_none() {
                right_node_next.extnode_mut().prev = left_node_ref
            }
            left_extnode.next = right_extnode.next.clone();
        }
        self.remove_at(right_ptr_pos);
        debug!(
            "Removing merged node at {}, left {}, right {}, merged {}",
            right_ptr_pos,left_len, right_len, merged_len
        );
        debug!("Merged parent level keys: {:?}", self.keys);
        debug!("Merged level keys {:?}", left_node.keys());
        Ok(())
    }
    pub fn merge_with(&mut self, right: &mut Self, right_key: EntryKey) {
        debug!(
            "Merge internal node, left len {}, right len {}, right_key {:?}",
            self.len, right.len, right_key
        );
        let mut self_len = self.len;
        let new_len = self_len + right.len + 1;
        debug_assert!(new_len <= self.keys.len());
        // moving keys
        self.keys[self_len] = right_key;
        for i in self_len + 1..new_len {
            mem::swap(&mut self.keys[i], &mut right.keys[i - self_len - 1]);
        }
        for i in self_len + 1..new_len + 1 {
            mem::swap(&mut self.ptrs[i], &mut right.ptrs[i - self_len - 1]);
        }
        self.len += right.len + 1;
    }
    pub fn relocate_children(
        &mut self,
        left_ptr_pos: usize,
        right_ptr_pos: usize,
        left_node: &mut NodeData,
        right_node: &mut NodeData,
    ) {
        debug_assert_ne!(left_ptr_pos, right_ptr_pos);
        let mut new_right_node_key = Default::default();
        let half_full_pos = (left_node.len() + right_node.len()) / 2;
        debug_assert_eq!(left_node.is_ext(), right_node.is_ext());
        if !left_node.is_ext() {
            // relocate internal sub nodes

            {
                let mut left_innode = left_node.innode_mut();
                let mut right_innode = right_node.innode_mut();

                debug!(
                    "Before relocation internal children. left {}:{:?} right {}:{:?}",
                    left_innode.len, left_innode.keys, right_innode.len, right_innode.keys
                );

                let mut new_left_keys = EntryKeySlice::init();
                let mut new_left_ptrs = NodePtrCellSlice::init();

                let mut new_right_keys = EntryKeySlice::init();
                let mut new_right_ptrs = NodePtrCellSlice::init();

                let pivot_key = self.keys[right_ptr_pos - 1].to_owned();
                let mut new_left_keys_len = 0;
                let mut new_right_keys_len = 0;
                for (i, key) in chain(
                    chain(
                        left_innode.keys[..left_innode.len].iter_mut(),
                        [pivot_key].iter_mut(),
                    ),
                    right_innode.keys[..right_innode.len].iter_mut(),
                )
                .enumerate()
                {
                    let key_owned = mem::replace(key, Default::default());
                    if i < half_full_pos {
                        new_left_keys[i] = key_owned;
                        new_left_keys_len += 1;
                    } else if i == half_full_pos {
                        new_right_node_key = key_owned
                    } else {
                        let nk_index = i - half_full_pos - 1;
                        new_right_keys[nk_index] = key_owned;
                        new_right_keys_len += 1;
                    }
                }

                for (i, ptr) in chain(
                    left_innode.ptrs[..left_innode.len + 1].iter_mut(),
                    right_innode.ptrs[..right_innode.len + 1].iter_mut(),
                )
                .enumerate()
                {
                    let ptr_owned = mem::replace(ptr, Default::default());
                    if i < half_full_pos + 1 {
                        new_left_ptrs[i] = ptr_owned;
                    } else {
                        new_right_ptrs[i - half_full_pos - 1] = ptr_owned;
                    }
                }

                left_innode.keys = new_left_keys;
                left_innode.ptrs = new_left_ptrs;
                left_innode.len = new_left_keys_len;

                right_innode.keys = new_right_keys;
                right_innode.ptrs = new_right_ptrs;
                right_innode.len = new_right_keys_len;

                debug!(
                    "Relocated internal children. left {}:{:?} right {}:{:?}",
                    left_innode.len, left_innode.keys, right_innode.len, right_innode.keys
                );
            }
        } else if left_node.is_ext() {
            // relocate external sub nodes

            let mut left_extnode = left_node.extnode_mut();
            let mut right_extnode = right_node.extnode_mut();

            debug!(
                "Before relocation external children. left {}:{:?} right {}:{:?}",
                left_extnode.len, left_extnode.keys, right_extnode.len, right_extnode.keys
            );

            let mut new_left_keys = EntryKeySlice::init();
            let mut new_right_keys = EntryKeySlice::init();

            let left_len = left_extnode.len;
            let right_len = right_extnode.len;
            let mut new_left_keys_len = 0;
            let mut new_right_keys_len = 0;
            for (i, key) in chain(
                left_extnode.keys[..left_len].iter_mut(),
                right_extnode.keys[..right_len].iter_mut(),
            )
            .enumerate()
            {
                let key_owned = mem::replace(key, Default::default());
                if i < half_full_pos {
                    new_left_keys[i] = key_owned;
                    new_left_keys_len += 1;
                } else {
                    if i == half_full_pos {
                        new_right_node_key = key_owned.clone()
                    }
                    new_right_keys[i - half_full_pos] = key_owned;
                    new_right_keys_len += 1;
                }
            }

            left_extnode.keys = new_left_keys;
            left_extnode.len = new_left_keys_len;

            right_extnode.keys = new_right_keys;
            right_extnode.len = new_right_keys_len;

            debug!(
                "Relocated external children. left {}:{:?} right {}:{:?}",
                left_extnode.len, left_extnode.keys, right_extnode.len, right_extnode.keys
            );
        }

        let right_key_pos = right_ptr_pos - 1;
        debug!(
            "Setting key at pos {} to new key {:?}",
            right_key_pos, new_right_node_key
        );
        self.keys[right_key_pos] = new_right_node_key;
    }
}
<commit_msg>assert non-empty pivot<commit_after>use hermes::stm::Txn;
use hermes::stm::TxnErr;
use hermes::stm::TxnValRef;
use index::btree::Slice;
use index::btree::*;
use itertools::free::chain;
use std::cell::UnsafeCell;
use std::mem;
use std::sync::atomic::AtomicPtr;
use std::sync::Arc;

pub struct InNode {
    pub keys: EntryKeySlice,
    pub ptrs: NodePtrCellSlice,
    pub len: usize,
    pub right: NodeCellRef,
}

pub struct InNodeKeysSplit {
    pub keys_2: EntryKeySlice,
    pub keys_1_len: usize,
    pub keys_2_len: usize,
    pub pivot_key: EntryKey,
}

pub struct InNodePtrSplit {
    pub ptrs_2: NodePtrCellSlice,
}

impl InNode {
    pub fn key_pos_from_ptr_pos(&self, ptr_pos: usize) -> usize {
        if ptr_pos == 0 {
            0
        } else {
            ptr_pos - 1
        }
    }
    pub fn search(&self, key: &EntryKey) -> usize {
        self.keys[..self.len]
            .binary_search(key)
            .map(|i| i + 1)
            .unwrap_or_else(|i| i)
    }
    pub fn remove_at(&mut self, ptr_pos: usize) {
        let mut n_key_len = self.len;
        let mut n_ptr_len = n_key_len + 1;
        let key_pos = self.key_pos_from_ptr_pos(ptr_pos);
        debug!(
            "Removing from internal node pos {}, len {}",
            key_pos, n_key_len
        );
        self.keys.remove_at(key_pos, &mut n_key_len);
        self.ptrs.remove_at(ptr_pos, &mut n_ptr_len);
        self.len = n_key_len;
    }
    pub fn insert(
        &mut self,
        key: EntryKey,
        new_node: NodeCellRef,
        parent: &NodeCellRef,
    ) -> Option<NodeSplit> {
        let node_len = self.len;
        let ptr_len = self.len + 1;
        let pos = self.search(&key);
        debug!("Insert into internal node at {}, key: {:?}", pos, key);
        debug_assert!(node_len <= NUM_KEYS);
        if node_len == NUM_KEYS {
            let pivot = node_len / 2; // pivot key will be removed
            debug!("Going to split at pivot {}", pivot);
            let parent_guard = parent.write();
            let keys_split = {
                debug!("insert into keys");
                if pivot == pos {
                    debug!("special key treatment when pivot == pos");
                    let mut keys_1 = &mut self.keys;
                    let mut keys_2 = keys_1.split_at_pivot(pivot, node_len);
                    let mut keys_1_len = pivot;
                    let mut keys_2_len = node_len - pivot;
                    let pivot_key = key;
                    InNodeKeysSplit {
                        keys_2,
                        keys_1_len,
                        keys_2_len,
                        pivot_key,
                    }
                } else {
                    let mut keys_1 = &mut self.keys;
                    let mut keys_2 = keys_1.split_at_pivot(pivot + 1, node_len);
                    let mut keys_1_len = pivot; // will not count the pivot
                    let mut keys_2_len = node_len - pivot - 1;
                    let mut key_pos = pos;
                    if pos > pivot {
                        // pivot moved, need to compensate
                        key_pos -= 1;
                    }
                    debug!(
                        "keys 1 len: {}, keys 2 len: {}, pos {}",
                        keys_1_len, keys_2_len, key_pos
                    );
                    debug_assert_ne!(pivot, pos);
                    let pivot_key = keys_1[pivot].to_owned();
                    insert_into_split(
                        key,
                        keys_1,
                        &mut keys_2,
                        &mut keys_1_len,
                        &mut keys_2_len,
                        key_pos,
                    );
                    InNodeKeysSplit {
                        keys_2,
                        keys_1_len,
                        keys_2_len,
                        pivot_key,
                    }
                }
            };
            let ptr_split = {
                if pivot == pos {
                    debug!("special ptr treatment when pivot == pos");
                    let mut ptrs_1 = &mut self.ptrs;
                    let mut ptrs_2 = ptrs_1.split_at_pivot(pivot + 1, ptr_len);
                    let mut ptrs_1_len = pivot + 1;
                    let mut ptrs_2_len = ptr_len - pivot - 1;
                    ptrs_2.insert_at(new_node, 0, &mut ptrs_2_len);
                    debug_assert_eq!(ptrs_1_len, keys_split.keys_1_len + 1);
                    debug_assert_eq!(ptrs_2_len, keys_split.keys_2_len + 1);
                    InNodePtrSplit { ptrs_2 }
                } else {
                    debug!("insert into ptrs");
                    let mut ptrs_1 = &mut self.ptrs;
                    let mut ptrs_2 = ptrs_1.split_at_pivot(pivot + 1, ptr_len);
                    let mut ptrs_1_len = pivot + 1;
                    let mut ptrs_2_len = ptr_len - pivot - 1;
                    let mut ptr_pos = pos + 1;
                    insert_into_split(
                        new_node,
                        ptrs_1,
                        &mut ptrs_2,
                        &mut ptrs_1_len,
                        &mut ptrs_2_len,
                        ptr_pos,
                    );
                    debug_assert_eq!(ptrs_1_len, keys_split.keys_1_len + 1);
                    debug_assert_eq!(ptrs_2_len, keys_split.keys_2_len + 1);
                    InNodePtrSplit { ptrs_2 }
                }
            };
            let node_2 = InNode {
                len: keys_split.keys_2_len,
                keys: keys_split.keys_2,
                ptrs: ptr_split.ptrs_2,
                right: self.right.clone(),
            };
            let node_2_ref = Arc::new(Node::internal(node_2));
            self.len = keys_split.keys_1_len;
            self.right = node_2_ref.clone();
            return Some(NodeSplit {
                new_right_node: node_2_ref,
                left_node_latch: NodeWriteGuard::default(),
                pivot: keys_split.pivot_key,
                parent_latch: parent_guard,
            });
        } else {
            let mut new_node_len = node_len;
            let mut new_node_pointers = node_len + 1;
            self.keys.insert_at(key, pos, &mut new_node_len);
            self.ptrs
                .insert_at(new_node, pos + 1, &mut new_node_pointers);
            self.len = new_node_len;
            return None;
        }
    }
    pub fn rebalance_candidate(&self, pointer_pos: usize) -> usize {
        debug_assert!(pointer_pos <= self.len);
        debug!(
            "Searching for rebalance candidate, pos {}, len {}",
            pointer_pos, self.len
        );
        if pointer_pos == 0 {
            1
        } else if pointer_pos + 1 >= self.len {
            // the last one, pick left
            pointer_pos - 1
        } else {
            // pick the right one
            // we should pick the one  with least pointers, but it cost for the check is too high
            pointer_pos + 1
        }
    }
    pub fn merge_children(
        &mut self,
        left_ptr_pos: usize,
        right_ptr_pos: usize,
        left_node: &mut NodeData,
        right_node: &mut NodeData,
        right_node_next: &mut NodeData,
    ) -> Result<(), TxnErr> {
        let left_node_ref = self.ptrs[left_ptr_pos].clone();
        let left_len = left_node.len();
        let right_len = right_node.len();
        let right_key_pos = self.key_pos_from_ptr_pos(right_ptr_pos);
        let mut merged_len = 0;
        debug!("Merge children, left len {}, right len {}, left_ptr_pos {}, right_ptr_pos {}, right_key_pos {}",
                left_len, right_len, left_ptr_pos, right_ptr_pos, right_key_pos);
        debug_assert_eq!(left_node.is_ext(), right_node.is_ext());
        if !left_node.is_ext() {
            {
                let mut left_innode = left_node.innode_mut();
                let mut right_innode = right_node.innode_mut();
                let right_key = self.keys[right_key_pos].clone();
                left_innode.merge_with(&mut right_innode, right_key);
                left_innode.right = right_innode.right.clone();
                merged_len = left_innode.len;
            }
        } else {
            let mut right_extnode = right_node.extnode_mut();
            let mut left_extnode = left_node.extnode_mut();
            {
                left_extnode.merge_with(&mut right_extnode);
                merged_len = left_extnode.len;
            }
            if !right_node_next.is_none() {
                right_node_next.extnode_mut().prev = left_node_ref
            }
            left_extnode.next = right_extnode.next.clone();
        }
        self.remove_at(right_ptr_pos);
        debug!(
            "Removing merged node at {}, left {}, right {}, merged {}",
            right_ptr_pos,left_len, right_len, merged_len
        );
        debug!("Merged parent level keys: {:?}", self.keys);
        debug!("Merged level keys {:?}", left_node.keys());
        Ok(())
    }
    pub fn merge_with(&mut self, right: &mut Self, right_key: EntryKey) {
        debug!(
            "Merge internal node, left len {}, right len {}, right_key {:?}",
            self.len, right.len, right_key
        );
        let mut self_len = self.len;
        let new_len = self_len + right.len + 1;
        debug_assert!(new_len <= self.keys.len());
        // moving keys
        self.keys[self_len] = right_key;
        for i in self_len + 1..new_len {
            mem::swap(&mut self.keys[i], &mut right.keys[i - self_len - 1]);
        }
        for i in self_len + 1..new_len + 1 {
            mem::swap(&mut self.ptrs[i], &mut right.ptrs[i - self_len - 1]);
        }
        self.len += right.len + 1;
    }
    pub fn relocate_children(
        &mut self,
        left_ptr_pos: usize,
        right_ptr_pos: usize,
        left_node: &mut NodeData,
        right_node: &mut NodeData,
    ) {
        debug_assert_ne!(left_ptr_pos, right_ptr_pos);
        let mut new_right_node_key = Default::default();
        let half_full_pos = (left_node.len() + right_node.len()) / 2;
        debug_assert_eq!(left_node.is_ext(), right_node.is_ext());
        if !left_node.is_ext() {
            // relocate internal sub nodes

            {
                let mut left_innode = left_node.innode_mut();
                let mut right_innode = right_node.innode_mut();

                debug!(
                    "Before relocation internal children. left {}:{:?} right {}:{:?}",
                    left_innode.len, left_innode.keys, right_innode.len, right_innode.keys
                );

                let mut new_left_keys = EntryKeySlice::init();
                let mut new_left_ptrs = NodePtrCellSlice::init();

                let mut new_right_keys = EntryKeySlice::init();
                let mut new_right_ptrs = NodePtrCellSlice::init();

                let pivot_key = self.keys[right_ptr_pos - 1].to_owned();
                let mut new_left_keys_len = 0;
                let mut new_right_keys_len = 0;
                debug_assert!(pivot_key > smallvec!(0));
                for (i, key) in chain(
                    chain(
                        left_innode.keys[..left_innode.len].iter_mut(),
                        [pivot_key].iter_mut(),
                    ),
                    right_innode.keys[..right_innode.len].iter_mut(),
                )
                .enumerate()
                {
                    let key_owned = mem::replace(key, Default::default());
                    if i < half_full_pos {
                        new_left_keys[i] = key_owned;
                        new_left_keys_len += 1;
                    } else if i == half_full_pos {
                        new_right_node_key = key_owned
                    } else {
                        let nk_index = i - half_full_pos - 1;
                        new_right_keys[nk_index] = key_owned;
                        new_right_keys_len += 1;
                    }
                }

                for (i, ptr) in chain(
                    left_innode.ptrs[..left_innode.len + 1].iter_mut(),
                    right_innode.ptrs[..right_innode.len + 1].iter_mut(),
                )
                .enumerate()
                {
                    let ptr_owned = mem::replace(ptr, Default::default());
                    if i < half_full_pos + 1 {
                        new_left_ptrs[i] = ptr_owned;
                    } else {
                        new_right_ptrs[i - half_full_pos - 1] = ptr_owned;
                    }
                }

                left_innode.keys = new_left_keys;
                left_innode.ptrs = new_left_ptrs;
                left_innode.len = new_left_keys_len;

                right_innode.keys = new_right_keys;
                right_innode.ptrs = new_right_ptrs;
                right_innode.len = new_right_keys_len;

                debug!(
                    "Relocated internal children. left {}:{:?} right {}:{:?}",
                    left_innode.len, left_innode.keys, right_innode.len, right_innode.keys
                );
            }
        } else if left_node.is_ext() {
            // relocate external sub nodes

            let mut left_extnode = left_node.extnode_mut();
            let mut right_extnode = right_node.extnode_mut();

            debug!(
                "Before relocation external children. left {}:{:?} right {}:{:?}",
                left_extnode.len, left_extnode.keys, right_extnode.len, right_extnode.keys
            );

            let mut new_left_keys = EntryKeySlice::init();
            let mut new_right_keys = EntryKeySlice::init();

            let left_len = left_extnode.len;
            let right_len = right_extnode.len;
            let mut new_left_keys_len = 0;
            let mut new_right_keys_len = 0;
            for (i, key) in chain(
                left_extnode.keys[..left_len].iter_mut(),
                right_extnode.keys[..right_len].iter_mut(),
            )
            .enumerate()
            {
                let key_owned = mem::replace(key, Default::default());
                if i < half_full_pos {
                    new_left_keys[i] = key_owned;
                    new_left_keys_len += 1;
                } else {
                    if i == half_full_pos {
                        new_right_node_key = key_owned.clone()
                    }
                    new_right_keys[i - half_full_pos] = key_owned;
                    new_right_keys_len += 1;
                }
            }

            left_extnode.keys = new_left_keys;
            left_extnode.len = new_left_keys_len;

            right_extnode.keys = new_right_keys;
            right_extnode.len = new_right_keys_len;

            debug!(
                "Relocated external children. left {}:{:?} right {}:{:?}",
                left_extnode.len, left_extnode.keys, right_extnode.len, right_extnode.keys
            );
        }

        let right_key_pos = right_ptr_pos - 1;
        debug!(
            "Setting key at pos {} to new key {:?}",
            right_key_pos, new_right_node_key
        );
        self.keys[right_key_pos] = new_right_node_key;
    }
}
<|endoftext|>


<commit_before>use libc::{c_char, c_int, FILE};
use object::*;
use code::*;
use pystate::PyThreadState;
use pyarena::PyArena;

pub const PyCF_MASK : c_int = (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT |
                   CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION |
                   CO_FUTURE_UNICODE_LITERALS);
pub const PyCF_MASK_OBSOLETE : c_int = (CO_NESTED);
pub const PyCF_SOURCE_IS_UTF8 : c_int = 0x0100;
pub const PyCF_DONT_IMPLY_DEDENT : c_int = 0x0200;
pub const PyCF_ONLY_AST : c_int = 0x0400;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyCompilerFlags {
    cf_flags : c_int
}

#[allow(missing_copy_implementations)]
pub enum Struct__mod { }
#[allow(missing_copy_implementations)]
pub enum Struct__node { }
#[allow(missing_copy_implementations)]
pub enum Struct_symtable { }

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn Py_SetProgramName(arg1: *mut c_char);
    pub fn Py_GetProgramName() -> *mut c_char;
    pub fn Py_SetPythonHome(arg1: *mut c_char);
    pub fn Py_GetPythonHome() -> *mut c_char;
    pub fn Py_Initialize();
    pub fn Py_InitializeEx(arg1: c_int);
    pub fn Py_Finalize();
    pub fn Py_IsInitialized() -> c_int;
    pub fn Py_NewInterpreter() -> *mut PyThreadState;
    pub fn Py_EndInterpreter(arg1: *mut PyThreadState);
    pub fn PyRun_AnyFileFlags(arg1: *mut FILE, arg2: *const c_char,
                              arg3: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_AnyFileExFlags(arg1: *mut FILE, arg2: *const c_char,
                                arg3: c_int,
                                arg4: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_SimpleStringFlags(arg1: *const c_char,
                                   arg2: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_SimpleFileExFlags(arg1: *mut FILE,
                                   arg2: *const c_char,
                                   arg3: c_int,
                                   arg4: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveOneFlags(arg1: *mut FILE,
                                     arg2: *const c_char,
                                     arg3: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveLoopFlags(arg1: *mut FILE,
                                      arg2: *const c_char,
                                      arg3: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyParser_ASTFromString(arg1: *const c_char,
                                  arg2: *const c_char,
                                  arg3: c_int,
                                  flags: *mut PyCompilerFlags,
                                  arg4: *mut PyArena) -> *mut Struct__mod;
    pub fn PyParser_ASTFromFile(arg1: *mut FILE, arg2: *const c_char,
                                arg3: c_int,
                                arg4: *mut c_char,
                                arg5: *mut c_char,
                                arg6: *mut PyCompilerFlags,
                                arg7: *mut c_int, arg8: *mut PyArena)
     -> *mut Struct__mod;
    pub fn PyParser_SimpleParseStringFlags(arg1: *const c_char,
                                           arg2: c_int,
                                           arg3: c_int)
     -> *mut Struct__node;
    pub fn PyParser_SimpleParseFileFlags(arg1: *mut FILE,
                                         arg2: *const c_char,
                                         arg3: c_int,
                                         arg4: c_int)
     -> *mut Struct__node;
    pub fn PyRun_StringFlags(arg1: *const c_char, arg2: c_int,
                             arg3: *mut PyObject, arg4: *mut PyObject,
                             arg5: *mut PyCompilerFlags) -> *mut PyObject;
    pub fn PyRun_FileExFlags(arg1: *mut FILE, arg2: *const c_char,
                             arg3: c_int, arg4: *mut PyObject,
                             arg5: *mut PyObject, arg6: c_int,
                             arg7: *mut PyCompilerFlags) -> *mut PyObject;
    pub fn Py_CompileStringFlags(arg1: *const c_char,
                                 arg2: *const c_char,
                                 arg3: c_int,
                                 arg4: *mut PyCompilerFlags) -> *mut PyObject;
    pub fn Py_SymtableString(arg1: *const c_char,
                             arg2: *const c_char, arg3: c_int)
     -> *mut Struct_symtable;
    pub fn PyErr_Print();
    pub fn PyErr_PrintEx(arg1: c_int);
    pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject,
                         arg3: *mut PyObject);
    pub fn Py_AtExit(func: Option<unsafe extern "C" fn()>)
     -> c_int;
    pub fn Py_Exit(arg1: c_int);
    pub fn Py_FdIsInteractive(arg1: *mut FILE, arg2: *const c_char)
     -> c_int;
    pub fn Py_Main(argc: c_int, argv: *mut *mut c_char)
     -> c_int;
    pub fn Py_GetProgramFullPath() -> *mut c_char;
    pub fn Py_GetPrefix() -> *mut c_char;
    pub fn Py_GetExecPrefix() -> *mut c_char;
    pub fn Py_GetPath() -> *mut c_char;
    pub fn Py_GetVersion() -> *const c_char;
    pub fn Py_GetPlatform() -> *const c_char;
    pub fn Py_GetCopyright() -> *const c_char;
    pub fn Py_GetCompiler() -> *const c_char;
    pub fn Py_GetBuildInfo() -> *const c_char;
    fn _Py_svnversion() -> *const c_char;
    pub fn Py_SubversionRevision() -> *const c_char;
    pub fn Py_SubversionShortBranch() -> *const c_char;
    fn _Py_hgidentifier() -> *const c_char;
    fn _Py_hgversion() -> *const c_char;
}

<commit_msg>Remove private svn and hg symbols<commit_after>use libc::{c_char, c_int, FILE};
use object::*;
use code::*;
use pystate::PyThreadState;
use pyarena::PyArena;

pub const PyCF_MASK : c_int = (CO_FUTURE_DIVISION | CO_FUTURE_ABSOLUTE_IMPORT |
                   CO_FUTURE_WITH_STATEMENT | CO_FUTURE_PRINT_FUNCTION |
                   CO_FUTURE_UNICODE_LITERALS);
pub const PyCF_MASK_OBSOLETE : c_int = (CO_NESTED);
pub const PyCF_SOURCE_IS_UTF8 : c_int = 0x0100;
pub const PyCF_DONT_IMPLY_DEDENT : c_int = 0x0200;
pub const PyCF_ONLY_AST : c_int = 0x0400;

#[repr(C)]
#[derive(Copy, Clone)]
pub struct PyCompilerFlags {
    cf_flags : c_int
}

#[allow(missing_copy_implementations)]
pub enum Struct__mod { }
#[allow(missing_copy_implementations)]
pub enum Struct__node { }
#[allow(missing_copy_implementations)]
pub enum Struct_symtable { }

#[cfg_attr(windows, link(name="pythonXY"))] extern "C" {
    pub fn Py_SetProgramName(arg1: *mut c_char);
    pub fn Py_GetProgramName() -> *mut c_char;
    pub fn Py_SetPythonHome(arg1: *mut c_char);
    pub fn Py_GetPythonHome() -> *mut c_char;
    pub fn Py_Initialize();
    pub fn Py_InitializeEx(arg1: c_int);
    pub fn Py_Finalize();
    pub fn Py_IsInitialized() -> c_int;
    pub fn Py_NewInterpreter() -> *mut PyThreadState;
    pub fn Py_EndInterpreter(arg1: *mut PyThreadState);
    pub fn PyRun_AnyFileFlags(arg1: *mut FILE, arg2: *const c_char,
                              arg3: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_AnyFileExFlags(arg1: *mut FILE, arg2: *const c_char,
                                arg3: c_int,
                                arg4: *mut PyCompilerFlags) -> c_int;
    pub fn PyRun_SimpleStringFlags(arg1: *const c_char,
                                   arg2: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_SimpleFileExFlags(arg1: *mut FILE,
                                   arg2: *const c_char,
                                   arg3: c_int,
                                   arg4: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveOneFlags(arg1: *mut FILE,
                                     arg2: *const c_char,
                                     arg3: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyRun_InteractiveLoopFlags(arg1: *mut FILE,
                                      arg2: *const c_char,
                                      arg3: *mut PyCompilerFlags)
     -> c_int;
    pub fn PyParser_ASTFromString(arg1: *const c_char,
                                  arg2: *const c_char,
                                  arg3: c_int,
                                  flags: *mut PyCompilerFlags,
                                  arg4: *mut PyArena) -> *mut Struct__mod;
    pub fn PyParser_ASTFromFile(arg1: *mut FILE, arg2: *const c_char,
                                arg3: c_int,
                                arg4: *mut c_char,
                                arg5: *mut c_char,
                                arg6: *mut PyCompilerFlags,
                                arg7: *mut c_int, arg8: *mut PyArena)
     -> *mut Struct__mod;
    pub fn PyParser_SimpleParseStringFlags(arg1: *const c_char,
                                           arg2: c_int,
                                           arg3: c_int)
     -> *mut Struct__node;
    pub fn PyParser_SimpleParseFileFlags(arg1: *mut FILE,
                                         arg2: *const c_char,
                                         arg3: c_int,
                                         arg4: c_int)
     -> *mut Struct__node;
    pub fn PyRun_StringFlags(arg1: *const c_char, arg2: c_int,
                             arg3: *mut PyObject, arg4: *mut PyObject,
                             arg5: *mut PyCompilerFlags) -> *mut PyObject;
    pub fn PyRun_FileExFlags(arg1: *mut FILE, arg2: *const c_char,
                             arg3: c_int, arg4: *mut PyObject,
                             arg5: *mut PyObject, arg6: c_int,
                             arg7: *mut PyCompilerFlags) -> *mut PyObject;
    pub fn Py_CompileStringFlags(arg1: *const c_char,
                                 arg2: *const c_char,
                                 arg3: c_int,
                                 arg4: *mut PyCompilerFlags) -> *mut PyObject;
    pub fn Py_SymtableString(arg1: *const c_char,
                             arg2: *const c_char, arg3: c_int)
     -> *mut Struct_symtable;
    pub fn PyErr_Print();
    pub fn PyErr_PrintEx(arg1: c_int);
    pub fn PyErr_Display(arg1: *mut PyObject, arg2: *mut PyObject,
                         arg3: *mut PyObject);
    pub fn Py_AtExit(func: Option<unsafe extern "C" fn()>)
     -> c_int;
    pub fn Py_Exit(arg1: c_int);
    pub fn Py_FdIsInteractive(arg1: *mut FILE, arg2: *const c_char)
     -> c_int;
    pub fn Py_Main(argc: c_int, argv: *mut *mut c_char)
     -> c_int;
    pub fn Py_GetProgramFullPath() -> *mut c_char;
    pub fn Py_GetPrefix() -> *mut c_char;
    pub fn Py_GetExecPrefix() -> *mut c_char;
    pub fn Py_GetPath() -> *mut c_char;
    pub fn Py_GetVersion() -> *const c_char;
    pub fn Py_GetPlatform() -> *const c_char;
    pub fn Py_GetCopyright() -> *const c_char;
    pub fn Py_GetCompiler() -> *const c_char;
    pub fn Py_GetBuildInfo() -> *const c_char;
    pub fn Py_SubversionRevision() -> *const c_char;
    pub fn Py_SubversionShortBranch() -> *const c_char;
}

<|endoftext|>


<commit_before>//! Data structures and implementations for union-of-patterns.

use std::mem;
use std::cmp::Ordering;
use std::iter::FromIterator;

use itertools::Itertools;

use util::set::{self, IsSubsetOf};
use super::{Atom, Class, Element, Repetition, Sequence, flatten_vec};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod union_impl {
    use std::slice;
    use super::super::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Union of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Union<T: Atom>(union_impl::Inner<T>);

impl<T: Atom> Union<T> {
    /// Create a new union from the given vector.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Unions must have at least two members");
        }
        Union(v)
    }

    /// Fetch an iterator over the members of the union
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    /// Get the number of members in the union
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Union<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }

    fn into_inner(self) -> union_impl::Inner<T> {
        self.0
    }

    /// Flatten the union and apply implementation-defined optimizations.
    pub fn reduce(&mut self) {
        for elt in self.0.iter_mut() {
            elt.reduce();
        }
        flatten_vec(&mut self.0,
                    |elt| match elt { &Element::Union(ref u) => Some(u.len()), _ => None },
                    |elt| match elt { Element::Union(u) => u.into_inner(), _ => unreachable!() });

        let mut reduced = self.0.clone().into_iter()
            .sorted_by(|a, b| { if a.is_subset_of(b) || b.is_subset_of(a) { Ordering::Equal }
                                else { a.cmp(b) } })
            .into_iter()
            .coalesce(|a, b| { if a.is_subset_of(&b) { Ok(b) }
                               else if b.is_subset_of(&a) { Ok(a) }
                               else { Err((a, b)) } })
            .collect();
        mem::swap(&mut self.0, &mut reduced);
    }
}

impl<T: Atom> set::Contains<T> for Union<T> {
    fn contains(&self, atom: T) -> bool {
        self.0.iter().any(|m| m.contains(atom))
    }
}

impl<T: Atom> FromIterator<Element<T>> for Union<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Union::new(iter.into_iter().collect())
    }
}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Union<T> {
    /// A union is a subset of a sequence S if it consists entirely of
    /// sequences whose elements are subsets of the corresponding element in S.
    fn is_subset_of(&self, seq: &Sequence<T>) -> bool {
        self.iter().all(|m| match m {
            &Element::Sequence(ref member_seq) =>
                seq.len() == member_seq.len() &&
                seq.iter().zip(member_seq.iter()).all(|(seq_elt, member_seq_elt)| member_seq_elt.is_subset_of(seq_elt)),
            _ => false })
    }
}

macro_rules! is_subset_if_all_members_are_subsets {
    ($T: ident,$Other: ty, $name: ident) => {
        impl<$T: Atom> set::IsSubsetOf<$Other> for Union<$T> {
            /// A union is a subset of a $name if all members are subsets.
            fn is_subset_of(&self, $name: &$Other) -> bool {
                self.iter().all(|m| m.is_subset_of($name))
            }
        }
    };
}

is_subset_if_all_members_are_subsets!(T, Repetition<T>, repetition);
is_subset_if_all_members_are_subsets!(T, Class<T>, class);
is_subset_if_all_members_are_subsets!(T, Union<T>, union);

impl<T: Atom> set::IsSubsetOf<Element<T>> for Union<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Class(ref c) => self.is_subset_of(c),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Repeat(ref r) => self.is_subset_of(r),
            &Element::Union(ref u) => self.is_subset_of(u),

            // A union is a subset of a wildcard if all members are
            // also subsets.
            &Element::Wildcard => self.iter().all(|m| m.is_subset_of(&Element::Wildcard)),

            // Unions always contain at least two unique members, thus they
            // cannot be subsets of single atoms.
            &Element::Atom(_) => false,
            &Element::Anchor(_) => false,
        }
    }
}
<commit_msg>pattern/union: remove unused import item<commit_after>//! Data structures and implementations for union-of-patterns.

use std::mem;
use std::cmp::Ordering;
use std::iter::FromIterator;

use itertools::Itertools;

use util::set::{self, IsSubsetOf};
use super::{Atom, Class, Element, Repetition, Sequence, flatten_vec};

// To hide the implementation details, we wrap the type alias in
// a private submodule.
mod union_impl {
    use super::super::Element;
    pub type Inner<T> = Vec<Element<T>>;
}

/// Union of patterns.
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
pub struct Union<T: Atom>(union_impl::Inner<T>);

impl<T: Atom> Union<T> {
    /// Create a new union from the given vector.
    pub fn new(v: Vec<Element<T>>) -> Self {
        if v.len() < 2 {
            panic!("Unions must have at least two members");
        }
        Union(v)
    }

    /// Fetch an iterator over the members of the union
    pub fn iter<'a>(&'a self) -> impl Iterator<Item=&'a Element<T>> {
        self.0.iter()
    }

    /// Get the number of members in the union
    pub fn len(&self) -> usize {
        self.0.len()
    }

    /// Transforms each contained atom using the supplied function or closure
    /// to produce a new sequence.
    pub fn map_atoms<U, F>(self, f: F) -> Union<U>
        where F: Fn(T) -> U,
              U: Atom
    {
        self.0.into_iter().map(|elt| elt.map_atoms(&f)).collect()
    }

    fn into_inner(self) -> union_impl::Inner<T> {
        self.0
    }

    /// Flatten the union and apply implementation-defined optimizations.
    pub fn reduce(&mut self) {
        for elt in self.0.iter_mut() {
            elt.reduce();
        }
        flatten_vec(&mut self.0,
                    |elt| match elt { &Element::Union(ref u) => Some(u.len()), _ => None },
                    |elt| match elt { Element::Union(u) => u.into_inner(), _ => unreachable!() });

        let mut reduced = self.0.clone().into_iter()
            .sorted_by(|a, b| { if a.is_subset_of(b) || b.is_subset_of(a) { Ordering::Equal }
                                else { a.cmp(b) } })
            .into_iter()
            .coalesce(|a, b| { if a.is_subset_of(&b) { Ok(b) }
                               else if b.is_subset_of(&a) { Ok(a) }
                               else { Err((a, b)) } })
            .collect();
        mem::swap(&mut self.0, &mut reduced);
    }
}

impl<T: Atom> set::Contains<T> for Union<T> {
    fn contains(&self, atom: T) -> bool {
        self.0.iter().any(|m| m.contains(atom))
    }
}

impl<T: Atom> FromIterator<Element<T>> for Union<T> {
    fn from_iter<I>(iter: I) -> Self
        where I: IntoIterator<Item=Element<T>>
    {
        Union::new(iter.into_iter().collect())
    }
}

impl<T: Atom> set::IsSubsetOf<Sequence<T>> for Union<T> {
    /// A union is a subset of a sequence S if it consists entirely of
    /// sequences whose elements are subsets of the corresponding element in S.
    fn is_subset_of(&self, seq: &Sequence<T>) -> bool {
        self.iter().all(|m| match m {
            &Element::Sequence(ref member_seq) =>
                seq.len() == member_seq.len() &&
                seq.iter().zip(member_seq.iter()).all(|(seq_elt, member_seq_elt)| member_seq_elt.is_subset_of(seq_elt)),
            _ => false })
    }
}

macro_rules! is_subset_if_all_members_are_subsets {
    ($T: ident,$Other: ty, $name: ident) => {
        impl<$T: Atom> set::IsSubsetOf<$Other> for Union<$T> {
            /// A union is a subset of a $name if all members are subsets.
            fn is_subset_of(&self, $name: &$Other) -> bool {
                self.iter().all(|m| m.is_subset_of($name))
            }
        }
    };
}

is_subset_if_all_members_are_subsets!(T, Repetition<T>, repetition);
is_subset_if_all_members_are_subsets!(T, Class<T>, class);
is_subset_if_all_members_are_subsets!(T, Union<T>, union);

impl<T: Atom> set::IsSubsetOf<Element<T>> for Union<T> {
    fn is_subset_of(&self, elt: &Element<T>) -> bool {
        match elt {
            &Element::Tagged{ref element, ..} => self.is_subset_of(&**element),
            &Element::Class(ref c) => self.is_subset_of(c),
            &Element::Sequence(ref s) => self.is_subset_of(s),
            &Element::Repeat(ref r) => self.is_subset_of(r),
            &Element::Union(ref u) => self.is_subset_of(u),

            // A union is a subset of a wildcard if all members are
            // also subsets.
            &Element::Wildcard => self.iter().all(|m| m.is_subset_of(&Element::Wildcard)),

            // Unions always contain at least two unique members, thus they
            // cannot be subsets of single atoms.
            &Element::Atom(_) => false,
            &Element::Anchor(_) => false,
        }
    }
}
<|endoftext|>


<commit_before>use prolog::and_stack::*;
use prolog::ast::*;

use std::ops::IndexMut;

pub trait CopierTarget
{
    fn source(&self) -> usize;
    fn threshold(&self) -> usize;
    fn push(&mut self, HeapCellValue);
    fn store(&self, Addr) -> Addr;
    fn deref(&self, Addr) -> Addr;
    fn stack(&mut self) -> &mut AndStack;

    //TODO: extend this so include a boundary() function which is constant!!
    // this will return self.h. the threshold() will be used to set the addresses
    // contained within the terms so that the offsets match those of the heap
    // to be truncated by BLOCK, ie. starting at the BLOCK.H value. This should
    // allow us to get around the latest bug.

    // duplicate_term(L1, L2) uses Cheney's algorithm to copy the term at
    // L1 to L2. forwarding_terms is kept to restore the innards of L1
    // after it's been copied to L2.
    fn duplicate_term(&mut self, a: Addr) where Self: IndexMut<usize, Output=HeapCellValue>
    {
        let mut forward_trail: Vec<(Ref, HeapCellValue)>= Vec::new();
        let mut scan = self.source();
        let old_h = self.threshold();

        self.push(HeapCellValue::from(a));

        while scan < self.threshold() {
            match self[scan].clone() {
                HeapCellValue::Con(_) | HeapCellValue::NamedStr(_, _) =>
                    scan += 1,
                HeapCellValue::Lis(a) => {
                    self[scan] = HeapCellValue::Lis(self.threshold());

                    let hcv = self[a].clone();
                    self.push(hcv);

                    let hcv = self[a+1].clone();
                    self.push(hcv);

                    scan += 1;
                },
                HeapCellValue::Ref(r) => {
                    let ra = Addr::from(r);
                    let rd = self.store(self.deref(ra.clone()));

                    match rd {
                        Addr::HeapCell(hc) if hc >= old_h => {
                            self[scan] = HeapCellValue::Ref(Ref::HeapCell(hc));
                            scan += 1;
                        },
                        _ if ra == rd => {
                            self[scan] = HeapCellValue::Ref(Ref::HeapCell(scan));

                            match r {
                                Ref::HeapCell(hc) =>
                                    self[hc] = HeapCellValue::Ref(Ref::HeapCell(scan)),
                                Ref::StackCell(fr, sc) =>
                                    self.stack()[fr][sc] = Addr::HeapCell(scan)
                            };

                            forward_trail.push((r, HeapCellValue::Ref(r)));
                            scan += 1;
                        },
                        _ => self[scan] = HeapCellValue::from(rd)
                    }
                },
                HeapCellValue::Str(s) => {
                    match self[s].clone() {
                        HeapCellValue::NamedStr(arity, name) => {
                            let threshold = self.threshold();

                            self[scan] = HeapCellValue::Str(threshold);
                            self[s] = HeapCellValue::Str(threshold);

                            forward_trail.push((Ref::HeapCell(s),
                                                HeapCellValue::NamedStr(arity, name.clone())));

                            self.push(HeapCellValue::NamedStr(arity, name));

                            for i in 0 .. arity {
                                let hcv = self[s + 1 + i].clone();
                                self.push(hcv);
                            }
                        },
                        HeapCellValue::Str(o) =>
                            self[scan] = HeapCellValue::Str(o),
                        _ => {}
                    };

                    scan += 1;
                }
            };
        }

        for (r, hcv) in forward_trail {
            match r {
                Ref::HeapCell(hc) => self[hc] = hcv,
                Ref::StackCell(fr, sc) => self.stack()[fr][sc] = hcv.as_addr(0)
            }
        }
    }
}
<commit_msg>remove finished TODO<commit_after>use prolog::and_stack::*;
use prolog::ast::*;

use std::ops::IndexMut;

pub trait CopierTarget
{
    fn source(&self) -> usize;
    fn threshold(&self) -> usize;
    fn push(&mut self, HeapCellValue);
    fn store(&self, Addr) -> Addr;
    fn deref(&self, Addr) -> Addr;
    fn stack(&mut self) -> &mut AndStack;

    // duplicate_term(L1, L2) uses Cheney's algorithm to copy the term at
    // L1 to L2. forwarding_terms is kept to restore the innards of L1
    // after it's been copied to L2.
    fn duplicate_term(&mut self, a: Addr) where Self: IndexMut<usize, Output=HeapCellValue>
    {
        let mut forward_trail: Vec<(Ref, HeapCellValue)>= Vec::new();
        let mut scan = self.source();
        let old_h = self.threshold();

        self.push(HeapCellValue::from(a));

        while scan < self.threshold() {
            match self[scan].clone() {
                HeapCellValue::Con(_) | HeapCellValue::NamedStr(_, _) =>
                    scan += 1,
                HeapCellValue::Lis(a) => {
                    self[scan] = HeapCellValue::Lis(self.threshold());

                    let hcv = self[a].clone();
                    self.push(hcv);

                    let hcv = self[a+1].clone();
                    self.push(hcv);

                    scan += 1;
                },
                HeapCellValue::Ref(r) => {
                    let ra = Addr::from(r);
                    let rd = self.store(self.deref(ra.clone()));

                    match rd {
                        Addr::HeapCell(hc) if hc >= old_h => {
                            self[scan] = HeapCellValue::Ref(Ref::HeapCell(hc));
                            scan += 1;
                        },
                        _ if ra == rd => {
                            self[scan] = HeapCellValue::Ref(Ref::HeapCell(scan));

                            match r {
                                Ref::HeapCell(hc) =>
                                    self[hc] = HeapCellValue::Ref(Ref::HeapCell(scan)),
                                Ref::StackCell(fr, sc) =>
                                    self.stack()[fr][sc] = Addr::HeapCell(scan)
                            };

                            forward_trail.push((r, HeapCellValue::Ref(r)));
                            scan += 1;
                        },
                        _ => self[scan] = HeapCellValue::from(rd)
                    }
                },
                HeapCellValue::Str(s) => {
                    match self[s].clone() {
                        HeapCellValue::NamedStr(arity, name) => {
                            let threshold = self.threshold();

                            self[scan] = HeapCellValue::Str(threshold);
                            self[s] = HeapCellValue::Str(threshold);

                            forward_trail.push((Ref::HeapCell(s),
                                                HeapCellValue::NamedStr(arity, name.clone())));

                            self.push(HeapCellValue::NamedStr(arity, name));

                            for i in 0 .. arity {
                                let hcv = self[s + 1 + i].clone();
                                self.push(hcv);
                            }
                        },
                        HeapCellValue::Str(o) =>
                            self[scan] = HeapCellValue::Str(o),
                        _ => {}
                    };

                    scan += 1;
                }
            };
        }

        for (r, hcv) in forward_trail {
            match r {
                Ref::HeapCell(hc) => self[hc] = hcv,
                Ref::StackCell(fr, sc) => self.stack()[fr][sc] = hcv.as_addr(0)
            }
        }
    }
}
<|endoftext|>