Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::cell::RefCell;
- use std::collections::HashMap;
- use std::fmt;
- use std::fmt::{Display, Formatter};
- use std::mem;
- pub struct Interned<'a> {
- index: usize,
- parent: &'a StrManager,
- }
- impl<'a> Display for Interned<'a> {
- fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), fmt::Error> {
- self.parent.internals.borrow().string_locations[self.index].fmt(fmt)
- }
- }
- impl<'a> PartialEq for Interned<'a> {
- fn eq(&self, other: &Self) -> bool {
- self.index == other.index && std::ptr::eq(self.parent, other.parent)
- }
- }
- struct StrManagerInternals {
- strings: HashMap<&'static str, usize>,
- string_locations: Vec<&'static str>,
- buffer: String,
- full_buffers: Vec<String>,
- }
- pub struct StrManager {
- internals: RefCell<StrManagerInternals>,
- }
- impl StrManager {
- pub fn with_capacity(cap: usize) -> Self {
- StrManager {
- internals: RefCell::new(StrManagerInternals {
- strings: HashMap::new(),
- string_locations: Vec::new(),
- buffer: String::with_capacity(cap.next_power_of_two()),
- full_buffers: Vec::new(),
- }),
- }
- }
- pub fn new() -> Self {
- StrManager::with_capacity(128)
- }
- pub fn intern<'a>(&'a mut self, s: &str) -> Interned<'a> {
- if let Some(&index) = self.internals.borrow().strings.get(s) {
- return Interned {
- index,
- parent: self,
- };
- }
- let interned = unsafe { self.alloc(s) };
- let index = self.internals.borrow().string_locations.len();
- self.internals.borrow_mut().string_locations.push(interned);
- Interned {
- index,
- parent: self,
- }
- }
- unsafe fn alloc(&self, s: &str) -> &'static str {
- let mut internals = self.internals.borrow_mut();
- let cap = internals.buffer.capacity();
- if cap < internals.buffer.len() + s.len() {
- let new_cap = (cap.max(s.len()) + 1).next_power_of_two();
- let new_buf = String::with_capacity(new_cap);
- let old_buf = mem::replace(&mut internals.buffer, new_buf);
- internals.full_buffers.push(old_buf);
- }
- let interned = {
- let start = internals.buffer.len();
- internals.buffer.push_str(s);
- &internals.buffer[start..]
- };
- &*(interned as *const str)
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement