Hash functions only once via custom hasher.
This commit is contained in:
parent
439053b153
commit
c9de37e8d1
@ -12,7 +12,7 @@ use crate::r#unsafe::{unsafe_cast_var_name_to_lifetime, unsafe_mut_cast_to_lifet
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::{StaticVec, StraightHasherBuilder};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
use crate::parser::FLOAT;
|
use crate::parser::FLOAT;
|
||||||
@ -196,7 +196,7 @@ impl State {
|
|||||||
///
|
///
|
||||||
/// The key of the `HashMap` is a `u64` hash calculated by the function `calc_fn_hash`.
|
/// The key of the `HashMap` is a `u64` hash calculated by the function `calc_fn_hash`.
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct FunctionsLib(HashMap<u64, Shared<FnDef>>);
|
pub struct FunctionsLib(HashMap<u64, Shared<FnDef>, StraightHasherBuilder>);
|
||||||
|
|
||||||
impl FunctionsLib {
|
impl FunctionsLib {
|
||||||
/// Create a new `FunctionsLib` from a collection of `FnDef`.
|
/// Create a new `FunctionsLib` from a collection of `FnDef`.
|
||||||
@ -261,7 +261,7 @@ impl From<Vec<(u64, Shared<FnDef>)>> for FunctionsLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for FunctionsLib {
|
impl Deref for FunctionsLib {
|
||||||
type Target = HashMap<u64, Shared<FnDef>>;
|
type Target = HashMap<u64, Shared<FnDef>, StraightHasherBuilder>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
@ -269,7 +269,7 @@ impl Deref for FunctionsLib {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DerefMut for FunctionsLib {
|
impl DerefMut for FunctionsLib {
|
||||||
fn deref_mut(&mut self) -> &mut HashMap<u64, Shared<FnDef>> {
|
fn deref_mut(&mut self) -> &mut HashMap<u64, Shared<FnDef>, StraightHasherBuilder> {
|
||||||
&mut self.0
|
&mut self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -952,21 +952,24 @@ impl Engine {
|
|||||||
let mut idx_val = idx_values.pop();
|
let mut idx_val = idx_values.pop();
|
||||||
|
|
||||||
if is_index {
|
if is_index {
|
||||||
|
let pos = rhs.position();
|
||||||
|
|
||||||
match rhs {
|
match rhs {
|
||||||
// xxx[idx].dot_rhs... | xxx[idx][dot_rhs]...
|
// xxx[idx].expr... | xxx[idx][expr]...
|
||||||
Expr::Dot(x) | Expr::Index(x) => {
|
Expr::Dot(x) | Expr::Index(x) => {
|
||||||
|
let (idx, expr, pos) = x.as_ref();
|
||||||
let is_idx = matches!(rhs, Expr::Index(_));
|
let is_idx = matches!(rhs, Expr::Index(_));
|
||||||
let pos = x.0.position();
|
let idx_pos = idx.position();
|
||||||
let this_ptr = &mut self
|
let this_ptr = &mut self.get_indexed_mut(
|
||||||
.get_indexed_mut(state, lib, obj, is_ref, idx_val, pos, op_pos, false)?;
|
state, lib, obj, is_ref, idx_val, idx_pos, op_pos, false,
|
||||||
|
)?;
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, &x.1, idx_values, is_idx, x.2, level, new_val,
|
state, lib, this_ptr, expr, idx_values, is_idx, *pos, level, new_val,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// xxx[rhs] = new_val
|
// xxx[rhs] = new_val
|
||||||
_ if new_val.is_some() => {
|
_ if new_val.is_some() => {
|
||||||
let pos = rhs.position();
|
|
||||||
let this_ptr = &mut self
|
let this_ptr = &mut self
|
||||||
.get_indexed_mut(state, lib, obj, is_ref, idx_val, pos, op_pos, true)?;
|
.get_indexed_mut(state, lib, obj, is_ref, idx_val, pos, op_pos, true)?;
|
||||||
|
|
||||||
@ -975,16 +978,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// xxx[rhs]
|
// xxx[rhs]
|
||||||
_ => self
|
_ => self
|
||||||
.get_indexed_mut(
|
.get_indexed_mut(state, lib, obj, is_ref, idx_val, pos, op_pos, false)
|
||||||
state,
|
|
||||||
lib,
|
|
||||||
obj,
|
|
||||||
is_ref,
|
|
||||||
idx_val,
|
|
||||||
rhs.position(),
|
|
||||||
op_pos,
|
|
||||||
false,
|
|
||||||
)
|
|
||||||
.map(|v| (v.clone_into_dynamic(), false)),
|
.map(|v| (v.clone_into_dynamic(), false)),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1050,57 +1044,51 @@ impl Engine {
|
|||||||
.map(|(v, _)| (v, false))
|
.map(|(v, _)| (v, false))
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
// {xxx:map}.idx_lhs[idx_expr] | {xxx:map}.dot_lhs.rhs
|
// {xxx:map}.prop[expr] | {xxx:map}.prop.expr
|
||||||
Expr::Index(x) | Expr::Dot(x) if obj.is::<Map>() => {
|
Expr::Index(x) | Expr::Dot(x) if obj.is::<Map>() => {
|
||||||
|
let (prop, expr, pos) = x.as_ref();
|
||||||
let is_idx = matches!(rhs, Expr::Index(_));
|
let is_idx = matches!(rhs, Expr::Index(_));
|
||||||
|
|
||||||
let mut val = if let Expr::Property(p) = &x.0 {
|
let mut val = if let Expr::Property(p) = prop {
|
||||||
let ((prop, _, _), _) = p.as_ref();
|
let ((prop, _, _), _) = p.as_ref();
|
||||||
let index = prop.clone().into();
|
let index = prop.clone().into();
|
||||||
self.get_indexed_mut(state, lib, obj, is_ref, index, x.2, op_pos, false)?
|
self.get_indexed_mut(state, lib, obj, is_ref, index, *pos, op_pos, false)?
|
||||||
} else {
|
} else {
|
||||||
// Syntax error
|
unreachable!();
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
|
||||||
"".into(),
|
|
||||||
rhs.position(),
|
|
||||||
)));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, &mut val, &x.1, idx_values, is_idx, x.2, level, new_val,
|
state, lib, &mut val, expr, idx_values, is_idx, *pos, level, new_val,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
// xxx.idx_lhs[idx_expr] | xxx.dot_lhs.rhs
|
// xxx.prop[expr] | xxx.prop.expr
|
||||||
Expr::Index(x) | Expr::Dot(x) => {
|
Expr::Index(x) | Expr::Dot(x) => {
|
||||||
let is_idx = matches!(rhs, Expr::Index(_));
|
let (prop, expr, pos) = x.as_ref();
|
||||||
|
let is_idx = matches!(expr, Expr::Index(_));
|
||||||
let args = &mut [obj, &mut Default::default()];
|
let args = &mut [obj, &mut Default::default()];
|
||||||
|
|
||||||
let (mut val, updated) = if let Expr::Property(p) = &x.0 {
|
let (mut val, updated) = if let Expr::Property(p) = prop {
|
||||||
let ((_, getter, _), _) = p.as_ref();
|
let ((_, getter, _), _) = p.as_ref();
|
||||||
let args = &mut args[..1];
|
let args = &mut args[..1];
|
||||||
self.exec_fn_call(state, lib, getter, true, 0, args, is_ref, None, x.2, 0)?
|
self.exec_fn_call(state, lib, getter, true, 0, args, is_ref, None, *pos, 0)?
|
||||||
} else {
|
} else {
|
||||||
// Syntax error
|
unreachable!();
|
||||||
return Err(Box::new(EvalAltResult::ErrorDotExpr(
|
|
||||||
"".into(),
|
|
||||||
rhs.position(),
|
|
||||||
)));
|
|
||||||
};
|
};
|
||||||
let val = &mut val;
|
let val = &mut val;
|
||||||
let target = &mut val.into();
|
let target = &mut val.into();
|
||||||
|
|
||||||
let (result, may_be_changed) = self.eval_dot_index_chain_helper(
|
let (result, may_be_changed) = self.eval_dot_index_chain_helper(
|
||||||
state, lib, target, &x.1, idx_values, is_idx, x.2, level, new_val,
|
state, lib, target, expr, idx_values, is_idx, *pos, level, new_val,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Feed the value back via a setter just in case it has been updated
|
// Feed the value back via a setter just in case it has been updated
|
||||||
if updated || may_be_changed {
|
if updated || may_be_changed {
|
||||||
if let Expr::Property(p) = &x.0 {
|
if let Expr::Property(p) = prop {
|
||||||
let ((_, _, setter), _) = p.as_ref();
|
let ((_, _, setter), _) = p.as_ref();
|
||||||
// Re-use args because the first &mut parameter will not be consumed
|
// Re-use args because the first &mut parameter will not be consumed
|
||||||
args[1] = val;
|
args[1] = val;
|
||||||
self.exec_fn_call(
|
self.exec_fn_call(
|
||||||
state, lib, setter, true, 0, args, is_ref, None, x.2, 0,
|
state, lib, setter, true, 0, args, is_ref, None, *pos, 0,
|
||||||
)
|
)
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
// If there is no setter, no need to feed it back because the property is read-only
|
// If there is no setter, no need to feed it back because the property is read-only
|
||||||
|
@ -12,7 +12,7 @@ use crate::parser::{
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::{Position, Token};
|
use crate::token::{Position, Token};
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::{StaticVec, StraightHasherBuilder};
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
@ -44,10 +44,14 @@ pub struct Module {
|
|||||||
variables: HashMap<String, Dynamic>,
|
variables: HashMap<String, Dynamic>,
|
||||||
|
|
||||||
/// Flattened collection of all module variables, including those in sub-modules.
|
/// Flattened collection of all module variables, including those in sub-modules.
|
||||||
all_variables: HashMap<u64, Dynamic>,
|
all_variables: HashMap<u64, Dynamic, StraightHasherBuilder>,
|
||||||
|
|
||||||
/// External Rust functions.
|
/// External Rust functions.
|
||||||
functions: HashMap<u64, (String, FnAccess, StaticVec<TypeId>, CallableFunction)>,
|
functions: HashMap<
|
||||||
|
u64,
|
||||||
|
(String, FnAccess, StaticVec<TypeId>, CallableFunction),
|
||||||
|
StraightHasherBuilder,
|
||||||
|
>,
|
||||||
|
|
||||||
/// Script-defined functions.
|
/// Script-defined functions.
|
||||||
lib: FunctionsLib,
|
lib: FunctionsLib,
|
||||||
@ -57,7 +61,7 @@ pub struct Module {
|
|||||||
|
|
||||||
/// Flattened collection of all external Rust functions, native or scripted,
|
/// Flattened collection of all external Rust functions, native or scripted,
|
||||||
/// including those in sub-modules.
|
/// including those in sub-modules.
|
||||||
all_functions: HashMap<u64, CallableFunction>,
|
all_functions: HashMap<u64, CallableFunction, StraightHasherBuilder>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for Module {
|
impl fmt::Debug for Module {
|
||||||
@ -101,7 +105,7 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn new_with_capacity(capacity: usize) -> Self {
|
pub fn new_with_capacity(capacity: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
functions: HashMap::with_capacity(capacity),
|
functions: HashMap::with_capacity_and_hasher(capacity, StraightHasherBuilder),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,7 @@ use crate::error::{LexError, ParseError, ParseErrorType};
|
|||||||
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
use crate::optimize::{optimize_into_ast, OptimizationLevel};
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::{Position, Token, TokenIterator};
|
use crate::token::{Position, Token, TokenIterator};
|
||||||
use crate::utils::StaticVec;
|
use crate::utils::{StaticVec, StraightHasherBuilder};
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::module::ModuleRef;
|
use crate::module::ModuleRef;
|
||||||
@ -1496,22 +1496,21 @@ fn parse_op_assignment_stmt<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Make a dot expression.
|
/// Make a dot expression.
|
||||||
fn make_dot_expr(
|
fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseError> {
|
||||||
lhs: Expr,
|
|
||||||
rhs: Expr,
|
|
||||||
op_pos: Position,
|
|
||||||
is_index: bool,
|
|
||||||
) -> Result<Expr, ParseError> {
|
|
||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
// idx_lhs[idx_rhs].rhs
|
// idx_lhs[idx_expr].rhs
|
||||||
// Attach dot chain to the bottom level of indexing chain
|
// Attach dot chain to the bottom level of indexing chain
|
||||||
(Expr::Index(x), rhs) => {
|
(Expr::Index(x), rhs) => {
|
||||||
Expr::Index(Box::new((x.0, make_dot_expr(x.1, rhs, op_pos, true)?, x.2)))
|
let (idx_lhs, idx_expr, pos) = *x;
|
||||||
|
Expr::Index(Box::new((
|
||||||
|
idx_lhs,
|
||||||
|
make_dot_expr(idx_expr, rhs, op_pos)?,
|
||||||
|
pos,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
// lhs.id
|
// lhs.id
|
||||||
(lhs, Expr::Variable(x)) if x.1.is_none() => {
|
(lhs, Expr::Variable(x)) if x.1.is_none() => {
|
||||||
let (name, pos) = x.0;
|
let (name, pos) = x.0;
|
||||||
let lhs = if is_index { lhs.into_property() } else { lhs };
|
|
||||||
|
|
||||||
let getter = make_getter(&name);
|
let getter = make_getter(&name);
|
||||||
let setter = make_setter(&name);
|
let setter = make_setter(&name);
|
||||||
@ -1519,11 +1518,6 @@ fn make_dot_expr(
|
|||||||
|
|
||||||
Expr::Dot(Box::new((lhs, rhs, op_pos)))
|
Expr::Dot(Box::new((lhs, rhs, op_pos)))
|
||||||
}
|
}
|
||||||
(lhs, Expr::Property(x)) => {
|
|
||||||
let lhs = if is_index { lhs.into_property() } else { lhs };
|
|
||||||
let rhs = Expr::Property(x);
|
|
||||||
Expr::Dot(Box::new((lhs, rhs, op_pos)))
|
|
||||||
}
|
|
||||||
// lhs.module::id - syntax error
|
// lhs.module::id - syntax error
|
||||||
(_, Expr::Variable(x)) if x.1.is_some() => {
|
(_, Expr::Variable(x)) if x.1.is_some() => {
|
||||||
#[cfg(feature = "no_module")]
|
#[cfg(feature = "no_module")]
|
||||||
@ -1531,34 +1525,30 @@ fn make_dot_expr(
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
return Err(PERR::PropertyExpected.into_err(x.1.unwrap().get(0).1));
|
return Err(PERR::PropertyExpected.into_err(x.1.unwrap().get(0).1));
|
||||||
}
|
}
|
||||||
|
// lhs.prop
|
||||||
|
(lhs, prop @ Expr::Property(_)) => Expr::Dot(Box::new((lhs, prop, op_pos))),
|
||||||
// lhs.dot_lhs.dot_rhs
|
// lhs.dot_lhs.dot_rhs
|
||||||
(lhs, Expr::Dot(x)) => {
|
(lhs, Expr::Dot(x)) => {
|
||||||
let (dot_lhs, dot_rhs, pos) = *x;
|
let (dot_lhs, dot_rhs, pos) = *x;
|
||||||
Expr::Dot(Box::new((
|
Expr::Dot(Box::new((
|
||||||
lhs,
|
lhs,
|
||||||
Expr::Dot(Box::new((
|
Expr::Dot(Box::new((dot_lhs.into_property(), dot_rhs, pos))),
|
||||||
dot_lhs.into_property(),
|
|
||||||
dot_rhs.into_property(),
|
|
||||||
pos,
|
|
||||||
))),
|
|
||||||
op_pos,
|
op_pos,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
// lhs.idx_lhs[idx_rhs]
|
// lhs.idx_lhs[idx_rhs]
|
||||||
(lhs, Expr::Index(x)) => {
|
(lhs, Expr::Index(x)) => {
|
||||||
let (idx_lhs, idx_rhs, pos) = *x;
|
let (dot_lhs, dot_rhs, pos) = *x;
|
||||||
Expr::Dot(Box::new((
|
Expr::Dot(Box::new((
|
||||||
lhs,
|
lhs,
|
||||||
Expr::Index(Box::new((
|
Expr::Index(Box::new((dot_lhs.into_property(), dot_rhs, pos))),
|
||||||
idx_lhs.into_property(),
|
|
||||||
idx_rhs.into_property(),
|
|
||||||
pos,
|
|
||||||
))),
|
|
||||||
op_pos,
|
op_pos,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
// lhs.func()
|
||||||
|
(lhs, func @ Expr::FnCall(_)) => Expr::Dot(Box::new((lhs, func, op_pos))),
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
(lhs, rhs) => Expr::Dot(Box::new((lhs, rhs.into_property(), op_pos))),
|
_ => unreachable!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1822,7 +1812,7 @@ fn parse_binary_op<'a>(
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
make_dot_expr(current_lhs, rhs, pos, false)?
|
make_dot_expr(current_lhs, rhs, pos)?
|
||||||
}
|
}
|
||||||
|
|
||||||
token => return Err(PERR::UnknownOperator(token.into()).into_err(pos)),
|
token => return Err(PERR::UnknownOperator(token.into()).into_err(pos)),
|
||||||
@ -2493,22 +2483,20 @@ pub fn parse_global_expr<'a>(
|
|||||||
fn parse_global_level<'a>(
|
fn parse_global_level<'a>(
|
||||||
input: &mut Peekable<TokenIterator<'a>>,
|
input: &mut Peekable<TokenIterator<'a>>,
|
||||||
max_expr_depth: (usize, usize),
|
max_expr_depth: (usize, usize),
|
||||||
) -> Result<(Vec<Stmt>, HashMap<u64, FnDef>), ParseError> {
|
) -> Result<(Vec<Stmt>, Vec<FnDef>), ParseError> {
|
||||||
let mut statements = Vec::<Stmt>::new();
|
let mut statements = Vec::<Stmt>::new();
|
||||||
let mut functions = HashMap::<u64, FnDef>::new();
|
let mut functions = HashMap::with_hasher(StraightHasherBuilder);
|
||||||
let mut state = ParseState::new(max_expr_depth.0);
|
let mut state = ParseState::new(max_expr_depth.0);
|
||||||
|
|
||||||
while !input.peek().unwrap().0.is_eof() {
|
while !input.peek().unwrap().0.is_eof() {
|
||||||
// Collect all the function definitions
|
// Collect all the function definitions
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
{
|
{
|
||||||
let mut access = FnAccess::Public;
|
let (access, must_be_fn) = if match_token(input, Token::Private)? {
|
||||||
let mut must_be_fn = false;
|
(FnAccess::Private, true)
|
||||||
|
} else {
|
||||||
if match_token(input, Token::Private)? {
|
(FnAccess::Public, false)
|
||||||
access = FnAccess::Private;
|
};
|
||||||
must_be_fn = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
match input.peek().unwrap() {
|
match input.peek().unwrap() {
|
||||||
(Token::Fn, _) => {
|
(Token::Fn, _) => {
|
||||||
@ -2565,7 +2553,7 @@ fn parse_global_level<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok((statements, functions))
|
Ok((statements, functions.into_iter().map(|(_, v)| v).collect()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the parser on an input stream, returning an AST.
|
/// Run the parser on an input stream, returning an AST.
|
||||||
@ -2576,9 +2564,8 @@ pub fn parse<'a>(
|
|||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
max_expr_depth: (usize, usize),
|
max_expr_depth: (usize, usize),
|
||||||
) -> Result<AST, ParseError> {
|
) -> Result<AST, ParseError> {
|
||||||
let (statements, functions) = parse_global_level(input, max_expr_depth)?;
|
let (statements, lib) = parse_global_level(input, max_expr_depth)?;
|
||||||
|
|
||||||
let lib = functions.into_iter().map(|(_, v)| v).collect();
|
|
||||||
Ok(
|
Ok(
|
||||||
// Optimize AST
|
// Optimize AST
|
||||||
optimize_into_ast(engine, scope, statements, lib, optimization_level),
|
optimize_into_ast(engine, scope, statements, lib, optimization_level),
|
||||||
|
66
src/utils.rs
66
src/utils.rs
@ -11,7 +11,7 @@ use crate::stdlib::{
|
|||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
fmt,
|
fmt,
|
||||||
hash::{Hash, Hasher},
|
hash::{BuildHasher, Hash, Hasher},
|
||||||
iter::FromIterator,
|
iter::FromIterator,
|
||||||
mem,
|
mem,
|
||||||
mem::MaybeUninit,
|
mem::MaybeUninit,
|
||||||
@ -27,6 +27,48 @@ use crate::stdlib::collections::hash_map::DefaultHasher;
|
|||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use ahash::AHasher;
|
use ahash::AHasher;
|
||||||
|
|
||||||
|
/// A hasher that only takes one single `u64` and returns it as a hash key.
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics when hashing any data type other than a `u64`.
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
||||||
|
pub struct StraightHasher(u64);
|
||||||
|
|
||||||
|
impl Hasher for StraightHasher {
|
||||||
|
#[inline(always)]
|
||||||
|
fn finish(&self) -> u64 {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, bytes: &[u8]) {
|
||||||
|
let mut key = [0_u8; 8];
|
||||||
|
key.copy_from_slice(&bytes[..8]); // Panics if fewer than 8 bytes
|
||||||
|
self.0 = u64::from_le_bytes(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StraightHasher {
|
||||||
|
/// Create a `StraightHasher`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A hash builder for `StraightHasher`.
|
||||||
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash, Default)]
|
||||||
|
pub struct StraightHasherBuilder;
|
||||||
|
|
||||||
|
impl BuildHasher for StraightHasherBuilder {
|
||||||
|
type Hasher = StraightHasher;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn build_hasher(&self) -> Self::Hasher {
|
||||||
|
StraightHasher::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Calculate a `u64` hash key from a module-qualified function name and parameter types.
|
/// Calculate a `u64` hash key from a module-qualified function name and parameter types.
|
||||||
///
|
///
|
||||||
/// Module names are passed in via `&str` references from an iterator.
|
/// Module names are passed in via `&str` references from an iterator.
|
||||||
@ -108,6 +150,7 @@ pub struct StaticVec<T> {
|
|||||||
const MAX_STATIC_VEC: usize = 4;
|
const MAX_STATIC_VEC: usize = 4;
|
||||||
|
|
||||||
impl<T> Drop for StaticVec<T> {
|
impl<T> Drop for StaticVec<T> {
|
||||||
|
#[inline(always)]
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.clear();
|
self.clear();
|
||||||
}
|
}
|
||||||
@ -174,6 +217,7 @@ impl<T> FromIterator<T> for StaticVec<T> {
|
|||||||
|
|
||||||
impl<T> StaticVec<T> {
|
impl<T> StaticVec<T> {
|
||||||
/// Create a new `StaticVec`.
|
/// Create a new `StaticVec`.
|
||||||
|
#[inline(always)]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
@ -189,6 +233,7 @@ impl<T> StaticVec<T> {
|
|||||||
self.len = 0;
|
self.len = 0;
|
||||||
}
|
}
|
||||||
/// Extract a `MaybeUninit` into a concrete initialized type.
|
/// Extract a `MaybeUninit` into a concrete initialized type.
|
||||||
|
#[inline(always)]
|
||||||
fn extract(value: MaybeUninit<T>) -> T {
|
fn extract(value: MaybeUninit<T>) -> T {
|
||||||
unsafe { value.assume_init() }
|
unsafe { value.assume_init() }
|
||||||
}
|
}
|
||||||
@ -250,6 +295,7 @@ impl<T> StaticVec<T> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
/// Is data stored in fixed-size storage?
|
/// Is data stored in fixed-size storage?
|
||||||
|
#[inline(always)]
|
||||||
fn is_fixed_storage(&self) -> bool {
|
fn is_fixed_storage(&self) -> bool {
|
||||||
self.len <= MAX_STATIC_VEC
|
self.len <= MAX_STATIC_VEC
|
||||||
}
|
}
|
||||||
@ -359,10 +405,12 @@ impl<T> StaticVec<T> {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
/// Get the number of items in this `StaticVec`.
|
/// Get the number of items in this `StaticVec`.
|
||||||
|
#[inline(always)]
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.len
|
self.len
|
||||||
}
|
}
|
||||||
/// Is this `StaticVec` empty?
|
/// Is this `StaticVec` empty?
|
||||||
|
#[inline(always)]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.len == 0
|
self.len == 0
|
||||||
}
|
}
|
||||||
@ -605,41 +653,48 @@ pub struct ImmutableString(Shared<String>);
|
|||||||
impl Deref for ImmutableString {
|
impl Deref for ImmutableString {
|
||||||
type Target = String;
|
type Target = String;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsRef<String> for ImmutableString {
|
impl AsRef<String> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn as_ref(&self) -> &String {
|
fn as_ref(&self) -> &String {
|
||||||
&self.0
|
&self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Borrow<str> for ImmutableString {
|
impl Borrow<str> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn borrow(&self) -> &str {
|
fn borrow(&self) -> &str {
|
||||||
self.0.as_str()
|
self.0.as_str()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&str> for ImmutableString {
|
impl From<&str> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
Self(value.to_string().into())
|
Self(value.to_string().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<String> for ImmutableString {
|
impl From<String> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn from(value: String) -> Self {
|
fn from(value: String) -> Self {
|
||||||
Self(value.into())
|
Self(value.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Box<String>> for ImmutableString {
|
impl From<Box<String>> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn from(value: Box<String>) -> Self {
|
fn from(value: Box<String>) -> Self {
|
||||||
Self(value.into())
|
Self(value.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ImmutableString> for String {
|
impl From<ImmutableString> for String {
|
||||||
|
#[inline(always)]
|
||||||
fn from(value: ImmutableString) -> Self {
|
fn from(value: ImmutableString) -> Self {
|
||||||
value.into_owned()
|
value.into_owned()
|
||||||
}
|
}
|
||||||
@ -648,42 +703,49 @@ impl From<ImmutableString> for String {
|
|||||||
impl FromStr for ImmutableString {
|
impl FromStr for ImmutableString {
|
||||||
type Err = ();
|
type Err = ();
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
Ok(Self(s.to_string().into()))
|
Ok(Self(s.to_string().into()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIterator<char> for ImmutableString {
|
impl FromIterator<char> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
|
||||||
Self(iter.into_iter().collect::<String>().into())
|
Self(iter.into_iter().collect::<String>().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromIterator<&'a char> for ImmutableString {
|
impl<'a> FromIterator<&'a char> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
|
||||||
Self(iter.into_iter().cloned().collect::<String>().into())
|
Self(iter.into_iter().cloned().collect::<String>().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromIterator<&'a str> for ImmutableString {
|
impl<'a> FromIterator<&'a str> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
|
||||||
Self(iter.into_iter().collect::<String>().into())
|
Self(iter.into_iter().collect::<String>().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> FromIterator<String> for ImmutableString {
|
impl<'a> FromIterator<String> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
|
||||||
Self(iter.into_iter().collect::<String>().into())
|
Self(iter.into_iter().collect::<String>().into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ImmutableString {
|
impl fmt::Display for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Display::fmt(self.0.as_str(), f)
|
fmt::Display::fmt(self.0.as_str(), f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Debug for ImmutableString {
|
impl fmt::Debug for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Debug::fmt(self.0.as_str(), f)
|
fmt::Debug::fmt(self.0.as_str(), f)
|
||||||
}
|
}
|
||||||
@ -818,6 +880,7 @@ impl Add<char> for &ImmutableString {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl AddAssign<char> for ImmutableString {
|
impl AddAssign<char> for ImmutableString {
|
||||||
|
#[inline(always)]
|
||||||
fn add_assign(&mut self, rhs: char) {
|
fn add_assign(&mut self, rhs: char) {
|
||||||
self.make_mut().push(rhs);
|
self.make_mut().push(rhs);
|
||||||
}
|
}
|
||||||
@ -832,6 +895,7 @@ impl ImmutableString {
|
|||||||
}
|
}
|
||||||
/// Make sure that the `ImmutableString` is unique (i.e. no other outstanding references).
|
/// Make sure that the `ImmutableString` is unique (i.e. no other outstanding references).
|
||||||
/// Then return a mutable reference to the `String`.
|
/// Then return a mutable reference to the `String`.
|
||||||
|
#[inline(always)]
|
||||||
pub fn make_mut(&mut self) -> &mut String {
|
pub fn make_mut(&mut self) -> &mut String {
|
||||||
shared_make_mut(&mut self.0)
|
shared_make_mut(&mut self.0)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user