Skip to content

Commit

Permalink
Merge pull request #836 from schungx/master
Browse files Browse the repository at this point in the history
Refine strings interner.
  • Loading branch information
schungx authored Feb 17, 2024
2 parents c8bac9a + 7cb0412 commit 161f7c1
Show file tree
Hide file tree
Showing 29 changed files with 989 additions and 562 deletions.
30 changes: 11 additions & 19 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,28 @@ Rhai Release Notes
Version 1.18.0
==============

Bug fixes
---------

* The position of an undefined operation call now points to the operator instead of the first operand.

Deprecated API's
----------------

* The plugin macros `export_fn`, `register_exported_fn!`, `set_exported_fn!` and `set_exported_global_fn!` are deprecated because they do not add value over existing direct API's.

New features
------------

* New options `Engine::set_max_strings_interned` and `Engine::max_strings_interned` are added to limit the maximum number of strings interned in the `Engine`'s string interner.

Enhancements
------------

* `FuncRegistration::in_global_namespace` and `FuncRegistration::in_internal_namespace` are added to avoid pulling in `FnNamespace`.
* Array/BLOB/string iterators are defined also within the `BasicIteratorPackage` in addition to the regular array/BLOB/string packages.
* `LexError::Runtime` is added for use with `Engine::on_parse_token`.
* Shared values under `sync` are now handled more elegantly -- instead of deadlocking and hanging indefinitely, it spins for a number of tries (waiting one second between each), then errors out.


Version 1.17.2
Expand All @@ -26,25 +37,6 @@ Bug fixes
* The engine no longer crashes when accessing a property or indexed item from a shared value returned from a variables resolver.


Version 1.18.0
==============

Bug fixes
---------

* The engine no longer crashes when accessing a property or indexed item from a shared value returned from a variables resolver.

Deprecated API's
----------------

* The plugin macros `export_fn`, `register_exported_fn!`, `set_exported_fn!` and `set_exported_global_fn!` are deprecated because they do not add value over existing direct API's.

Enhancements
------------

* `FuncRegistration::in_global_namespace` and `FuncRegistration::in_internal_namespace` are added to avoid pulling in `FnNamespace`.


Version 1.17.1
==============

Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ categories = ["no-std", "embedded", "wasm", "parser-implementations"]
[dependencies]
smallvec = { version = "1.7.0", default-features = false, features = ["union", "const_new", "const_generics"] }
thin-vec = { version = "0.2.13", default-features = false }
ahash = { version = "0.8.2", default-features = false, features = ["compile-time-rng"] }
ahash = { version = "0.8.2,<=0.8.7", default-features = false, features = ["compile-time-rng"] } # `ahash` bumps MSRV to 1.72 from 0.8.8 onwards
num-traits = { version = "0.2.0", default-features = false }
once_cell = { version = "1.7.0", default-features = false, features = ["race"] }
bitflags = { version = "2.0.0", default-features = false }
Expand Down
29 changes: 10 additions & 19 deletions src/api/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
use crate::func::native::locked_write;
use crate::parser::{ParseResult, ParseState};
use crate::types::StringsInterner;
use crate::{Engine, OptimizationLevel, Scope, AST};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
Expand Down Expand Up @@ -220,15 +219,11 @@ impl Engine {
) -> ParseResult<AST> {
let (stream, tc) = self.lex(scripts.as_ref());

let mut interner;
let mut guard;
let interned_strings = if let Some(ref interner) = self.interned_strings {
guard = locked_write(interner);
&mut *guard
} else {
interner = StringsInterner::new();
&mut interner
};
let guard = &mut self
.interned_strings
.as_ref()
.and_then(|interner| locked_write(interner));
let interned_strings = guard.as_deref_mut();

let input = &mut stream.peekable();
let lib = &mut <_>::default();
Expand Down Expand Up @@ -304,15 +299,11 @@ impl Engine {
let scripts = [script];
let (stream, t) = self.lex(&scripts);

let mut interner;
let mut guard;
let interned_strings = if let Some(ref interner) = self.interned_strings {
guard = locked_write(interner);
&mut *guard
} else {
interner = StringsInterner::new();
&mut interner
};
let guard = &mut self
.interned_strings
.as_ref()
.and_then(|interner| locked_write(interner));
let interned_strings = guard.as_deref_mut();

let input = &mut stream.peekable();
let lib = &mut <_>::default();
Expand Down
6 changes: 3 additions & 3 deletions src/api/custom_syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,8 @@ impl Expression<'_> {
pub fn get_string_value(&self) -> Option<&str> {
match self.0 {
#[cfg(not(feature = "no_module"))]
Expr::Variable(x, ..) if !x.1.is_empty() => None,
Expr::Variable(x, ..) => Some(&x.3),
Expr::Variable(x, ..) if !x.2.is_empty() => None,
Expr::Variable(x, ..) => Some(&x.1),
#[cfg(not(feature = "no_function"))]
Expr::ThisPtr(..) => Some(crate::engine::KEYWORD_THIS),
Expr::StringConstant(x, ..) => Some(x),
Expand Down Expand Up @@ -138,7 +138,7 @@ impl Expression<'_> {

Expr::CharConstant(x, ..) => reify! { *x => Option<T> },
Expr::StringConstant(x, ..) => reify! { x.clone() => Option<T> },
Expr::Variable(x, ..) => reify! { x.3.clone() => Option<T> },
Expr::Variable(x, ..) => reify! { x.1.clone() => Option<T> },
Expr::BoolConstant(x, ..) => reify! { *x => Option<T> },
Expr::Unit(..) => reify! { () => Option<T> },

Expand Down
15 changes: 5 additions & 10 deletions src/api/eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ use crate::eval::{Caches, GlobalRuntimeState};
use crate::func::native::locked_write;
use crate::parser::ParseState;
use crate::types::dynamic::Variant;
use crate::types::StringsInterner;
use crate::{Dynamic, Engine, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
Expand Down Expand Up @@ -115,15 +114,11 @@ impl Engine {
) -> RhaiResultOf<T> {
let scripts = [script];
let ast = {
let mut interner;
let mut guard;
let interned_strings = if let Some(ref interner) = self.interned_strings {
guard = locked_write(interner);
&mut *guard
} else {
interner = StringsInterner::new();
&mut interner
};
let guard = &mut self
.interned_strings
.as_ref()
.and_then(|interner| locked_write(interner));
let interned_strings = guard.as_deref_mut();

let (stream, tc) = self.lex(&scripts);

Expand Down
11 changes: 8 additions & 3 deletions src/api/formatting.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Module that provide formatting services to the [`Engine`].
use crate::func::locked_write;
use crate::packages::iter_basic::{BitRange, CharsStream, StepRange};
use crate::parser::{ParseResult, ParseState};
use crate::types::StringsInterner;
use crate::{
Engine, ExclusiveRange, FnPtr, ImmutableString, InclusiveRange, Position, RhaiError,
SmartString, ERR,
Expand Down Expand Up @@ -264,11 +264,16 @@ impl Engine {

tc.borrow_mut().compressed = Some(String::new());
stream.state.last_token = Some(SmartString::new_const());
let mut interner = StringsInterner::new();

let guard = &mut self
.interned_strings
.as_ref()
.and_then(|interner| locked_write(interner));
let interned_strings = guard.as_deref_mut();

let input = &mut stream.peekable();
let lib = &mut <_>::default();
let mut state = ParseState::new(None, &mut interner, input, tc, lib);
let mut state = ParseState::new(None, interned_strings, input, tc, lib);

let mut _ast = self.parse(
&mut state,
Expand Down
20 changes: 9 additions & 11 deletions src/api/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::func::native::locked_write;
use crate::parser::{ParseSettingFlags, ParseState};
use crate::tokenizer::Token;
use crate::types::dynamic::Union;
use crate::types::StringsInterner;
use crate::{Dynamic, Engine, LexError, Map, RhaiResultOf};
use std::fmt::Write;
#[cfg(feature = "no_std")]
Expand Down Expand Up @@ -118,15 +117,11 @@ impl Engine {
);

let ast = {
let mut interner;
let mut guard;
let interned_strings = if let Some(ref interner) = self.interned_strings {
guard = locked_write(interner);
&mut *guard
} else {
interner = StringsInterner::new();
&mut interner
};
let guard = &mut self
.interned_strings
.as_ref()
.and_then(|interner| locked_write(interner));
let interned_strings = guard.as_deref_mut();

let input = &mut stream.peekable();
let lib = &mut <_>::default();
Expand Down Expand Up @@ -221,7 +216,10 @@ fn format_dynamic_as_json(result: &mut String, value: &Dynamic) {
*result += "]";
}
#[cfg(not(feature = "no_closure"))]
Union::Shared(ref v, _, _) => format_dynamic_as_json(result, &crate::func::locked_read(v)),
Union::Shared(ref v, _, _) => {
let value = &*crate::func::locked_read(v).unwrap();
format_dynamic_as_json(result, value)
}
_ => write!(result, "{value:?}").unwrap(),
}
}
2 changes: 2 additions & 0 deletions src/api/limits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ pub mod default_limits {
/// Not available under `no_function`.
#[cfg(not(feature = "no_function"))]
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
/// Maximum number of strings interned.
pub const MAX_STRINGS_INTERNED: usize = 1024;

Check warning on line 39 in src/api/limits.rs

View workflow job for this annotation

GitHub Actions / NoStdBuild (ubuntu-latest, --profile unix, false)

constant `MAX_STRINGS_INTERNED` is never used

Check warning on line 39 in src/api/limits.rs

View workflow job for this annotation

GitHub Actions / NoStdBuild (windows-latest, --profile windows, true)

constant `MAX_STRINGS_INTERNED` is never used
}

/// A type containing all the limits imposed by the [`Engine`].
Expand Down
27 changes: 27 additions & 0 deletions src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ pub mod definitions;

pub mod deprecated;

use crate::func::{locked_read, locked_write};
use crate::types::StringsInterner;
use crate::{Dynamic, Engine, Identifier};

#[cfg(feature = "no_std")]
Expand All @@ -46,9 +48,34 @@ pub mod default_limits {

/// Maximum number of parameters in functions with [`Dynamic`][crate::Dynamic] support.
pub const MAX_DYNAMIC_PARAMETERS: usize = 16;
/// Maximum number of strings interned.
pub const MAX_STRINGS_INTERNED: usize = 256;
}

impl Engine {
/// Set the maximum number of strings to be interned.
#[inline(always)]
pub fn set_max_strings_interned(&mut self, max: usize) -> &mut Self {
if max == 0 {
self.interned_strings = None;
} else if let Some(ref interner) = self.interned_strings {
if let Some(mut guard) = locked_write(interner) {
guard.set_max(max);
}
} else {
self.interned_strings = Some(StringsInterner::new(max).into());
}
self
}
/// The maximum number of strings to be interned.
#[inline(always)]
#[must_use]
pub fn max_strings_interned(&self) -> usize {
self.interned_strings.as_ref().map_or(0, |interner| {
locked_read(interner).map_or(0, |guard| guard.max())
})
}

/// The module resolution service used by the [`Engine`].
///
/// Not available under `no_module`.
Expand Down
15 changes: 5 additions & 10 deletions src/api/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
use crate::eval::Caches;
use crate::func::native::locked_write;
use crate::parser::ParseState;
use crate::types::StringsInterner;
use crate::{Engine, RhaiResultOf, Scope, AST};
#[cfg(feature = "no_std")]
use std::prelude::v1::*;
Expand Down Expand Up @@ -61,15 +60,11 @@ impl Engine {
let ast = {
let (stream, tc) = self.lex(&scripts);

let mut interner;
let mut guard;
let interned_strings = if let Some(ref interner) = self.interned_strings {
guard = locked_write(interner);
&mut *guard
} else {
interner = StringsInterner::new();
&mut interner
};
let guard = &mut self
.interned_strings
.as_ref()
.and_then(|interner| locked_write(interner));
let interned_strings = guard.as_deref_mut();

let input = &mut stream.peekable();
let lib = &mut <_>::default();
Expand Down
Loading

0 comments on commit 161f7c1

Please sign in to comment.