aboutsummaryrefslogblamecommitdiffstats
path: root/src/util/edit_map.rs
blob: 813630674bfc194cdd58029075b52954278b3fe7 (plain) (tree)















































































































































                                                                                 
use crate::tokenizer::Event;

/// To do: could we do without `HashMap`, so we don’t need `std`?
use std::collections::HashMap;

pub fn shift_links(events: &mut [Event], jumps: &[(usize, isize)]) {
    let map = |before| {
        let mut jump_index = 0;
        let mut jump = 0;

        while jump_index < jumps.len() {
            if jumps[jump_index].0 > before {
                break;
            }

            jump = jumps[jump_index].1;
            jump_index += 1;
        }

        #[allow(clippy::pedantic)]
        let next_i = (before as isize) + jump;
        assert!(next_i >= 0, "cannot shift before `0`");
        #[allow(clippy::pedantic)]
        let next = next_i as usize;
        next
    };

    let mut index = 0;

    while index < events.len() {
        let event = &mut events[index];
        event.previous = event.previous.map(map);
        event.next = event.next.map(map);
        index += 1;
    }
}

/// Make it easy to insert and remove things while being performant and keeping
/// links in check.
pub struct EditMap {
    consumed: bool,
    map: HashMap<usize, (usize, Vec<Event>)>,
}

impl EditMap {
    /// Create a new edit map.
    pub fn new() -> EditMap {
        EditMap {
            consumed: false,
            map: HashMap::new(),
        }
    }
    /// Create an edit: a remove and/or add at a certain place.
    pub fn add(&mut self, index: usize, mut remove: usize, mut add: Vec<Event>) {
        assert!(!self.consumed, "cannot add after consuming");

        if let Some((curr_remove, mut curr_add)) = self.map.remove(&index) {
            remove += curr_remove;
            curr_add.append(&mut add);
            add = curr_add;
        }

        self.map.insert(index, (remove, add));
    }
    /// Done, change the events.
    pub fn consume(&mut self, events: &mut [Event]) -> Vec<Event> {
        let mut indices: Vec<&usize> = self.map.keys().collect();
        let mut next_events: Vec<Event> = vec![];
        let mut start = 0;

        assert!(!self.consumed, "cannot consume after consuming");
        self.consumed = true;

        let mut index = 0;

        while index < events.len() {
            let event = &events[index];
            println!(
                "ev: {:?} {:?} {:?} {:?} {:?} {:?}",
                index,
                event.event_type,
                event.token_type,
                event.content_type,
                event.previous,
                event.next
            );
            index += 1;
        }

        indices.sort_unstable();

        let mut jumps: Vec<(usize, isize)> = vec![];
        let mut index_into_indices = 0;
        let mut shift: isize = 0;
        while index_into_indices < indices.len() {
            let index = *indices[index_into_indices];
            let edit = self.map.get(&index).unwrap();
            println!("?? {:?} {:?} {:?}", shift, edit.1.len(), edit.0);

            #[allow(clippy::pedantic)]
            let next = shift + (edit.1.len() as isize) - (edit.0 as isize);
            shift = next;
            jumps.push((index, shift));
            index_into_indices += 1;
        }

        let mut index_into_indices = 0;

        while index_into_indices < indices.len() {
            let index = *indices[index_into_indices];

            if start < index {
                let append = &mut events[start..index].to_vec();
                shift_links(append, &jumps);
                next_events.append(append);
            }

            let (remove, add) = self.map.get(&index).unwrap();

            if !add.is_empty() {
                let append = &mut add.clone();
                let mut index = 0;

                while index < append.len() {
                    let event = &mut append[index];
                    assert!(event.previous.is_none(), "to do?");
                    assert!(event.next.is_none(), "to do?");
                    index += 1;
                }

                next_events.append(append);
            }

            start = index + remove;
            index_into_indices += 1;
        }

        if start < events.len() {
            next_events.append(&mut events[start..].to_vec());
        }

        next_events
    }
}