oxihuman-core 0.1.2

Core data structures, algorithms, and asset management for OxiHuman
Documentation
#![allow(dead_code)]

use std::collections::HashMap;

#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct ArenaString {
    id: usize,
    offset: usize,
    len: usize,
}

#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct StringArena {
    buffer: Vec<u8>,
    index: HashMap<usize, (usize, usize)>,
    next_id: usize,
}

#[allow(dead_code)]
pub fn new_string_arena() -> StringArena {
    StringArena {
        buffer: Vec::new(),
        index: HashMap::new(),
        next_id: 0,
    }
}

#[allow(dead_code)]
pub fn arena_alloc_str(arena: &mut StringArena, s: &str) -> ArenaString {
    let offset = arena.buffer.len();
    arena.buffer.extend_from_slice(s.as_bytes());
    let id = arena.next_id;
    arena.index.insert(id, (offset, s.len()));
    arena.next_id += 1;
    ArenaString {
        id,
        offset,
        len: s.len(),
    }
}

#[allow(dead_code)]
pub fn arena_get_str<'a>(arena: &'a StringArena, handle: &ArenaString) -> Option<&'a str> {
    arena.index.get(&handle.id).and_then(|&(off, len)| {
        std::str::from_utf8(&arena.buffer[off..off + len]).ok()
    })
}

#[allow(dead_code)]
pub fn arena_str_count(arena: &StringArena) -> usize {
    arena.index.len()
}

#[allow(dead_code)]
pub fn arena_total_bytes(arena: &StringArena) -> usize {
    arena.buffer.len()
}

#[allow(dead_code)]
pub fn arena_clear(arena: &mut StringArena) {
    arena.buffer.clear();
    arena.index.clear();
    arena.next_id = 0;
}

#[allow(dead_code)]
pub fn arena_contains(arena: &StringArena, s: &str) -> bool {
    let bytes = s.as_bytes();
    arena.index.values().any(|&(off, len)| {
        len == bytes.len() && arena.buffer[off..off + len] == *bytes
    })
}

#[allow(dead_code)]
pub fn arena_dedup(arena: &StringArena) -> usize {
    let mut seen = std::collections::HashSet::new();
    let mut dupes = 0usize;
    for &(off, len) in arena.index.values() {
        let slice = &arena.buffer[off..off + len];
        if !seen.insert(slice.to_vec()) {
            dupes += 1;
        }
    }
    dupes
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_new_arena() {
        let arena = new_string_arena();
        assert_eq!(arena_str_count(&arena), 0);
    }

    #[test]
    fn test_alloc_and_get() {
        let mut arena = new_string_arena();
        let h = arena_alloc_str(&mut arena, "hello");
        assert_eq!(arena_get_str(&arena, &h), Some("hello"));
    }

    #[test]
    fn test_multiple_allocs() {
        let mut arena = new_string_arena();
        let h1 = arena_alloc_str(&mut arena, "foo");
        let h2 = arena_alloc_str(&mut arena, "bar");
        assert_eq!(arena_get_str(&arena, &h1), Some("foo"));
        assert_eq!(arena_get_str(&arena, &h2), Some("bar"));
    }

    #[test]
    fn test_str_count() {
        let mut arena = new_string_arena();
        arena_alloc_str(&mut arena, "a");
        arena_alloc_str(&mut arena, "b");
        assert_eq!(arena_str_count(&arena), 2);
    }

    #[test]
    fn test_total_bytes() {
        let mut arena = new_string_arena();
        arena_alloc_str(&mut arena, "abc");
        arena_alloc_str(&mut arena, "de");
        assert_eq!(arena_total_bytes(&arena), 5);
    }

    #[test]
    fn test_clear() {
        let mut arena = new_string_arena();
        arena_alloc_str(&mut arena, "xyz");
        arena_clear(&mut arena);
        assert_eq!(arena_str_count(&arena), 0);
        assert_eq!(arena_total_bytes(&arena), 0);
    }

    #[test]
    fn test_contains() {
        let mut arena = new_string_arena();
        arena_alloc_str(&mut arena, "test");
        assert!(arena_contains(&arena, "test"));
        assert!(!arena_contains(&arena, "nope"));
    }

    #[test]
    fn test_dedup_none() {
        let mut arena = new_string_arena();
        arena_alloc_str(&mut arena, "a");
        arena_alloc_str(&mut arena, "b");
        assert_eq!(arena_dedup(&arena), 0);
    }

    #[test]
    fn test_dedup_some() {
        let mut arena = new_string_arena();
        arena_alloc_str(&mut arena, "a");
        arena_alloc_str(&mut arena, "a");
        assert_eq!(arena_dedup(&arena), 1);
    }

    #[test]
    fn test_empty_string() {
        let mut arena = new_string_arena();
        let h = arena_alloc_str(&mut arena, "");
        assert_eq!(arena_get_str(&arena, &h), Some(""));
    }
}