Remove hashing of the entire script by making Expr and Stmt Hash.

This commit is contained in:
Stephen Chung
2021-01-04 11:58:24 +08:00
parent e2a47b2a65
commit cf9d35166d
6 changed files with 191 additions and 112 deletions

View File

@@ -8,14 +8,13 @@ use crate::stdlib::{
boxed::Box,
collections::HashMap,
fmt,
hash::Hash,
hash::{Hash, Hasher},
num::{NonZeroU64, NonZeroUsize},
ops::{Add, AddAssign},
ops::{Add, AddAssign, Deref, DerefMut},
string::String,
vec,
vec::Vec,
};
use crate::syntax::FnCustomSyntaxEval;
use crate::token::Token;
use crate::utils::StraightHasherBuilder;
use crate::{
@@ -492,11 +491,7 @@ impl AST {
(true, true) => vec![],
};
let source = if other.source.is_some() {
other.source.clone()
} else {
self.source.clone()
};
let source = other.source.clone().or_else(|| self.source.clone());
let mut functions = functions.as_ref().clone();
functions.merge_filtered(&other.functions, &mut filter);
@@ -696,24 +691,68 @@ pub enum ReturnType {
Exception,
}
/// A type that wraps a [`HashMap`]`<u64, Stmt>` for the `switch` statement and implements [`Hash`].
#[derive(Clone)]
pub struct SwitchHashWrapper(HashMap<u64, Stmt, StraightHasherBuilder>);
impl From<HashMap<u64, Stmt, StraightHasherBuilder>> for SwitchHashWrapper {
fn from(value: HashMap<u64, Stmt, StraightHasherBuilder>) -> Self {
Self(value)
}
}
impl AsRef<HashMap<u64, Stmt, StraightHasherBuilder>> for SwitchHashWrapper {
fn as_ref(&self) -> &HashMap<u64, Stmt, StraightHasherBuilder> {
&self.0
}
}
impl AsMut<HashMap<u64, Stmt, StraightHasherBuilder>> for SwitchHashWrapper {
fn as_mut(&mut self) -> &mut HashMap<u64, Stmt, StraightHasherBuilder> {
&mut self.0
}
}
impl Deref for SwitchHashWrapper {
type Target = HashMap<u64, Stmt, StraightHasherBuilder>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for SwitchHashWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl fmt::Debug for SwitchHashWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
impl Hash for SwitchHashWrapper {
fn hash<H: Hasher>(&self, state: &mut H) {
let mut keys: Vec<_> = self.0.keys().collect();
keys.sort();
keys.into_iter().for_each(|key| {
key.hash(state);
self.0.get(&key).unwrap().hash(state);
});
}
}
/// _(INTERNALS)_ A statement.
/// Exported under the `internals` feature only.
///
/// # WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Hash)]
pub enum Stmt {
/// No-op.
Noop(Position),
/// `if` expr `{` stmt `}` `else` `{` stmt `}`
If(Expr, Box<(Stmt, Option<Stmt>)>, Position),
/// `switch` expr `{` literal or _ `=>` stmt `,` ... `}`
Switch(
Expr,
Box<(HashMap<u64, Stmt, StraightHasherBuilder>, Option<Stmt>)>,
Position,
),
Switch(Expr, Box<(SwitchHashWrapper, Option<Stmt>)>, Position),
/// `while` expr `{` stmt `}`
While(Expr, Box<Stmt>, Position),
/// `do` `{` stmt `}` `while`|`until` expr
@@ -899,10 +938,8 @@ impl Stmt {
/// # WARNING
///
/// This type is volatile and may change.
#[derive(Clone)]
#[derive(Clone, Hash)]
pub struct CustomExpr {
/// Implementation function.
pub func: Shared<FnCustomSyntaxEval>,
/// List of keywords.
pub keywords: StaticVec<Expr>,
/// List of tokens actually parsed.
@@ -926,7 +963,7 @@ impl fmt::Debug for CustomExpr {
/// # WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Hash)]
pub struct BinaryExpr {
/// LHS expression.
pub lhs: Expr,
@@ -940,7 +977,7 @@ pub struct BinaryExpr {
/// # WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, Hash)]
pub struct FnCallExpr {
/// Pre-calculated hash for a script-defined function of the same name and number of parameters.
/// None if native Rust only.
@@ -959,13 +996,83 @@ pub struct FnCallExpr {
pub args: StaticVec<Expr>,
}
/// A type that wraps a [`FLOAT`] and implements [`Hash`].
#[cfg(not(feature = "no_float"))]
#[derive(Clone, Copy)]
pub struct FloatWrapper(FLOAT);
#[cfg(not(feature = "no_float"))]
impl Hash for FloatWrapper {
fn hash<H: Hasher>(&self, state: &mut H) {
self.0.to_le_bytes().hash(state);
}
}
#[cfg(not(feature = "no_float"))]
impl AsRef<FLOAT> for FloatWrapper {
fn as_ref(&self) -> &FLOAT {
&self.0
}
}
#[cfg(not(feature = "no_float"))]
impl AsMut<FLOAT> for FloatWrapper {
fn as_mut(&mut self) -> &mut FLOAT {
&mut self.0
}
}
#[cfg(not(feature = "no_float"))]
impl Deref for FloatWrapper {
type Target = FLOAT;
fn deref(&self) -> &Self::Target {
&self.0
}
}
#[cfg(not(feature = "no_float"))]
impl DerefMut for FloatWrapper {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
#[cfg(not(feature = "no_float"))]
impl fmt::Debug for FloatWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(not(feature = "no_float"))]
impl fmt::Display for FloatWrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg(not(feature = "no_float"))]
impl From<FLOAT> for FloatWrapper {
fn from(value: FLOAT) -> Self {
Self::new(value)
}
}
#[cfg(not(feature = "no_float"))]
impl FloatWrapper {
pub const fn new(value: FLOAT) -> Self {
Self(value)
}
}
/// _(INTERNALS)_ An expression sub-tree.
/// Exported under the `internals` feature only.
///
/// # WARNING
///
/// This type is volatile and may change.
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Hash)]
pub enum Expr {
/// Dynamic constant.
/// Used to hold either an [`Array`] or [`Map`] literal for quick cloning.
@@ -977,7 +1084,7 @@ pub enum Expr {
IntegerConstant(INT, Position),
/// Floating-point constant.
#[cfg(not(feature = "no_float"))]
FloatConstant(FLOAT, Position),
FloatConstant(FloatWrapper, Position),
/// Character constant.
CharConstant(char, Position),
/// [String][ImmutableString] constant.
@@ -1250,19 +1357,20 @@ mod tests {
/// This test is to make sure no code changes increase the sizes of critical data structures.
#[test]
fn check_struct_sizes() {
use std::mem::size_of;
use crate::stdlib::mem::size_of;
use crate::*;
assert_eq!(size_of::<crate::Dynamic>(), 16);
assert_eq!(size_of::<Option<crate::Dynamic>>(), 16);
assert_eq!(size_of::<crate::Position>(), 4);
assert_eq!(size_of::<crate::ast::Expr>(), 16);
assert_eq!(size_of::<Option<crate::ast::Expr>>(), 16);
assert_eq!(size_of::<crate::ast::Stmt>(), 32);
assert_eq!(size_of::<Option<crate::ast::Stmt>>(), 32);
assert_eq!(size_of::<crate::FnPtr>(), 32);
assert_eq!(size_of::<crate::Scope>(), 48);
assert_eq!(size_of::<crate::LexError>(), 56);
assert_eq!(size_of::<crate::ParseError>(), 16);
assert_eq!(size_of::<crate::EvalAltResult>(), 72);
assert_eq!(size_of::<Dynamic>(), 16);
assert_eq!(size_of::<Option<Dynamic>>(), 16);
assert_eq!(size_of::<Position>(), 4);
assert_eq!(size_of::<ast::Expr>(), 16);
assert_eq!(size_of::<Option<ast::Expr>>(), 16);
assert_eq!(size_of::<ast::Stmt>(), 32);
assert_eq!(size_of::<Option<ast::Stmt>>(), 32);
assert_eq!(size_of::<FnPtr>(), 32);
assert_eq!(size_of::<Scope>(), 48);
assert_eq!(size_of::<LexError>(), 56);
assert_eq!(size_of::<ParseError>(), 16);
assert_eq!(size_of::<EvalAltResult>(), 72);
}
}