// Randomized meldable heap.
// https://en.wikipedia.org/wiki/Randomized_meldable_heap

extern crate slotmap;

use slotmap::{new_key_type, Key, SlotMap};

new_key_type! {
    struct HeapKey;
}

// Intentionally not copy or clone.
struct NodeHandle(HeapKey);

#[derive(Copy, Clone)]
struct Node<T> {
    value: T,
    children: [HeapKey; 2],
    parent: HeapKey,
}

struct RandMeldHeap<T: Ord> {
    sm: SlotMap<HeapKey, Node<T>>,
    rng: std::num::Wrapping<u32>,
    root: HeapKey,
}

impl<T: Ord + std::fmt::Debug> RandMeldHeap<T> {
    pub fn new() -> Self {
        Self {
            sm: SlotMap::with_key(),
            rng: std::num::Wrapping(0xdeadbeef),
            root: HeapKey::null(),
        }
    }

    pub fn coinflip(&mut self) -> bool {
        // Simple LCG for top speed - random quality barely matters.
        self.rng += (self.rng << 8) + std::num::Wrapping(1);
        self.rng >> 31 > std::num::Wrapping(0)
    }

    pub fn insert(&mut self, value: T) -> NodeHandle {
        let k = self.sm.insert(Node {
            value,
            children: [HeapKey::null(), HeapKey::null()],
            parent: HeapKey::null(),
        });

        let root = self.root;
        self.root = self.meld(k, root);

        NodeHandle(k)
    }

    pub fn pop(&mut self) -> Option<T> {
        if let Some(root) = self.sm.remove(self.root) {
            self.root = self.meld(root.children[0], root.children[1]);
            if let Some(new_root) = self.sm.get_mut(self.root) {
                new_root.parent = HeapKey::null();
            }

            Some(root.value)
        } else {
            None
        }
    }

    pub fn remove_key(&mut self, node: NodeHandle) -> T {
        let node = node.0;
        self.unlink_node(node);
        self.sm.remove(node).unwrap().value
    }

    pub fn update_key(&mut self, node: &NodeHandle, value: T) {
        let node = node.0;

        // Unlink and re-insert.
        self.unlink_node(node);
        self.sm[node] = Node {
            value,
            children: [HeapKey::null(), HeapKey::null()],
            parent: HeapKey::null(),
        };
        let root = self.root;
        self.root = self.meld(node, root);
    }

    fn unlink_node(&mut self, node: HeapKey) {
        // Remove node from heap by merging children and placing them where
        // node used to be.
        let children = self.sm[node].children;
        let parent_key = self.sm[node].parent;

        let melded_children = self.meld(children[0], children[1]);
        if let Some(mc) = self.sm.get_mut(melded_children) {
            mc.parent = parent_key;
        }

        if let Some(parent) = self.sm.get_mut(parent_key) {
            if parent.children[0] == node {
                parent.children[0] = melded_children;
            } else {
                parent.children[1] = melded_children;
            }
        } else {
            self.root = melded_children;
        }
    }

    fn meld(&mut self, mut a: HeapKey, mut b: HeapKey) -> HeapKey {
        if a.is_null() {
            return b;
        }
        if b.is_null() {
            return a;
        }

        if self.sm[a].value > self.sm[b].value {
            std::mem::swap(&mut a, &mut b);
        }

        let ret = a;

        // From this point parent and trickle are assumed to be valid keys.
        let mut parent = a;
        let mut trickle = b;

        loop {
            // If a child spot is free, put our trickle there.
            let children = self.sm[parent].children;
            if children[0].is_null() {
                self.sm[parent].children[0] = trickle;
                self.sm[trickle].parent = parent;
                break;
            } else if children[1].is_null() {
                self.sm[parent].children[1] = trickle;
                self.sm[trickle].parent = parent;
                break;
            }

            // No spot free, choose a random child.
            let c = self.coinflip() as usize;
            let child = children[c];
            if self.sm[child].value > self.sm[trickle].value {
                self.sm[parent].children[c] = trickle;
                self.sm[trickle].parent = parent;
                parent = trickle;
                trickle = child;
            } else {
                parent = child;
            }
        }

        ret
    }

    pub fn len(&self) -> usize {
        self.sm.len()
    }
}

fn main() {
    let mut rhm = RandMeldHeap::new();
    let the_answer = rhm.insert(-2);
    let big = rhm.insert(999);

    for k in (0..10).rev() {
        rhm.insert(k * k);
    }

    rhm.update_key(&the_answer, 42);
    rhm.remove_key(big);

    while rhm.len() > 0 {
        println!("{}", rhm.pop().unwrap());
    }
}
