use std::collections::{hash_map::Entry, HashMap};
use std::fmt;
use std::iter::FusedIterator;
use std::ops::Range;
use crate::error::DuplicateVarName;
use crate::VarNo;
mod unowned {
use std::{fmt, ptr::NonNull};
#[derive(Eq)]
pub struct Unowned<T: ?Sized>(NonNull<T>);
unsafe impl<T: ?Sized + Sync> Send for Unowned<T> {}
unsafe impl<T: ?Sized + Sync> Sync for Unowned<T> {}
impl<T: ?Sized> Clone for Unowned<T> {
#[inline(always)]
fn clone(&self) -> Self {
*self
}
}
impl<T: ?Sized> Copy for Unowned<T> {}
impl<T: ?Sized> std::ops::Deref for Unowned<T> {
type Target = T;
#[inline(always)]
fn deref(&self) -> &T {
unsafe { self.0.as_ref() }
}
}
impl<T: ?Sized> std::borrow::Borrow<T> for Unowned<T> {
#[inline(always)]
fn borrow(&self) -> &T {
self
}
}
impl<T: ?Sized + PartialEq> PartialEq for Unowned<T> {
#[inline(always)]
fn eq(&self, other: &Self) -> bool {
**self == **other
}
}
impl<T: ?Sized + std::hash::Hash> std::hash::Hash for Unowned<T> {
#[inline(always)]
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<T: ?Sized> From<Box<T>> for Unowned<T> {
#[inline(always)]
fn from(value: Box<T>) -> Self {
Self(NonNull::from(Box::leak(value)))
}
}
impl<T: ?Sized> From<&'static T> for Unowned<T> {
#[inline(always)]
fn from(value: &'static T) -> Self {
Self(NonNull::from(value))
}
}
impl<T: ?Sized> Unowned<T> {
#[inline(always)]
pub unsafe fn into_box(this: Self) -> Box<T> {
unsafe { Box::from_raw(this.0.as_ptr()) }
}
}
impl<T: ?Sized + fmt::Debug> fmt::Debug for Unowned<T> {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
impl<T: ?Sized + fmt::Display> fmt::Display for Unowned<T> {
#[inline(always)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
(**self).fmt(f)
}
}
}
use unowned::Unowned;
#[derive(Clone)]
pub struct VarNameMap {
names: Vec<Unowned<str>>,
index: HashMap<Unowned<str>, VarNo>,
}
impl Drop for VarNameMap {
fn drop(&mut self) {
self.names.clear();
for (s, _) in self.index.drain() {
drop(unsafe { Unowned::into_box(s) });
}
}
}
impl fmt::Debug for VarNameMap {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(self.names.iter().enumerate().filter(|(_, s)| !s.is_empty()))
.finish()?;
write!(f, " (length: {})", self.len())
}
}
impl Default for VarNameMap {
#[inline(always)]
fn default() -> Self {
Self::new()
}
}
impl VarNameMap {
#[inline]
pub fn new() -> Self {
Self {
names: Vec::new(),
index: HashMap::new(),
}
}
#[inline(always)]
pub fn len(&self) -> VarNo {
self.names.len() as VarNo
}
#[inline(always)]
pub fn is_empty(&self) -> bool {
self.names.is_empty()
}
#[inline]
pub fn reserve(&mut self, additional: VarNo) {
let additional = additional.try_into().unwrap_or(usize::MAX);
self.names.reserve(additional);
self.index.reserve(additional);
}
#[inline(always)]
pub fn named_count(&self) -> VarNo {
self.index.len() as VarNo
}
#[inline]
pub fn add_unnamed(&mut self, additional: VarNo) {
let msg = "too many variables";
let new_len = self.len().checked_add(additional).expect(msg);
self.names.resize(new_len.try_into().expect(msg), "".into());
}
#[track_caller]
pub fn add_named<T: IntoIterator<Item = S>, S: Into<String>>(
&mut self,
names: T,
) -> Result<Range<VarNo>, DuplicateVarName> {
let len_pre = self.names.len() as VarNo;
let it = names.into_iter();
let size_hint = it.size_hint().0;
self.index.reserve(size_hint);
self.names.reserve(size_hint);
for (name, v) in it.zip(len_pre..VarNo::MAX) {
let name: String = name.into();
if name.is_empty() {
self.names.push("".into());
continue;
}
let name = name.into_boxed_str().into();
match self.index.entry(name) {
Entry::Occupied(entry) => {
let present_var = *entry.get();
let name: Box<str> = unsafe { Unowned::into_box(name) };
return Err(DuplicateVarName {
name: name.into_string(),
present_var,
added_vars: len_pre..self.names.len() as VarNo,
});
}
Entry::Vacant(entry) => entry.insert(v),
};
self.names.push(name);
}
Ok(len_pre..self.names.len() as VarNo)
}
pub fn get_or_add(&mut self, name: impl Into<String>) -> (VarNo, bool) {
let name: String = name.into();
if name.is_empty() {
let n = self.names.len() as VarNo;
self.names.push("".into());
return (n, false);
}
let name = name.into_boxed_str().into();
match self.index.entry(name) {
Entry::Occupied(entry) => {
drop(unsafe { Unowned::into_box(name) });
(*entry.get(), true)
}
Entry::Vacant(entry) => {
let n = self.names.len() as VarNo;
if n == VarNo::MAX {
drop(unsafe { Unowned::into_box(name) });
return (n, false);
}
entry.insert(n);
self.names.push(name);
(n, false)
}
}
}
#[inline]
pub fn name_to_var(&self, name: impl AsRef<str>) -> Option<VarNo> {
self.index.get(name.as_ref()).copied()
}
#[inline(always)]
#[track_caller]
pub fn var_name(&self, var: VarNo) -> &str {
&self.names[var as usize]
}
#[track_caller]
pub fn set_var_name(
&mut self,
var: VarNo,
name: impl Into<String>,
) -> Result<(), DuplicateVarName> {
let name: String = name.into();
if name.is_empty() {
self.index
.remove(&std::mem::replace(&mut self.names[var as usize], "".into()));
return Ok(());
}
let name = name.into_boxed_str().into();
match self.index.entry(name) {
Entry::Occupied(entry) => {
let name = unsafe { Unowned::into_box(name) };
let present_var = *entry.get();
if present_var != var {
let len = self.len() as VarNo;
return Err(DuplicateVarName {
name: name.into_string(),
present_var,
added_vars: len..len,
});
}
}
Entry::Vacant(entry) => {
let prev = std::mem::replace(&mut self.names[var as usize], name);
entry.insert(var);
if !prev.is_empty() {
drop(unsafe { Unowned::into_box(prev) });
}
}
};
Ok(())
}
pub fn into_names_iter(mut self) -> IntoNamesIter {
self.index.clear();
IntoNamesIter(std::mem::take(&mut self.names).into_iter())
}
}
#[derive(Debug)]
pub struct IntoNamesIter(std::vec::IntoIter<Unowned<str>>);
#[inline(always)]
unsafe fn unowned_to_string(s: Unowned<str>) -> String {
if s.is_empty() {
String::new()
} else {
unsafe { Unowned::into_box(s) }.into_string()
}
}
impl Drop for IntoNamesIter {
fn drop(&mut self) {
for &name in self.0.as_slice() {
drop(unsafe { unowned_to_string(name) });
}
}
}
impl Iterator for IntoNamesIter {
type Item = String;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let name = self.0.next()?;
Some(unsafe { unowned_to_string(name) })
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Self::Item> {
let name = self.0.nth(n)?;
Some(unsafe { unowned_to_string(name) })
}
}
impl ExactSizeIterator for IntoNamesIter {
#[inline]
fn len(&self) -> usize {
self.0.len()
}
}
impl FusedIterator for IntoNamesIter where std::vec::IntoIter<Unowned<str>>: FusedIterator {}
impl DoubleEndedIterator for IntoNamesIter {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
let name = self.0.next_back()?;
Some(unsafe { unowned_to_string(name) })
}
#[inline]
fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
let name = self.0.nth_back(n)?;
Some(unsafe { unowned_to_string(name) })
}
}