From fca140ef5560a29bfa97357eac26f11444ad1583 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 25 May 2020 17:01:39 +0800 Subject: [PATCH] Refine immutable strings. --- benches/eval_expression.rs | 51 ++++++++++++++++++++++++++++++++++++ src/any.rs | 5 +++- src/engine.rs | 5 ++-- src/fn_native.rs | 22 ++++++++++++++++ src/packages/string_basic.rs | 28 +++++++++++++------- src/packages/string_more.rs | 47 ++++++++++++++------------------- 6 files changed, 119 insertions(+), 39 deletions(-) diff --git a/benches/eval_expression.rs b/benches/eval_expression.rs index 8f46fb18..affb25bb 100644 --- a/benches/eval_expression.rs +++ b/benches/eval_expression.rs @@ -105,3 +105,54 @@ fn bench_eval_call(bench: &mut Bencher) { bench.iter(|| engine.eval::(script).unwrap()); } + +#[bench] +fn bench_eval_loop_number(bench: &mut Bencher) { + let script = r#" + let s = 0; + for x in range(0, 10000) { + s += 1; + } + "#; + + let mut engine = Engine::new(); + engine.set_optimization_level(OptimizationLevel::None); + + let ast = engine.compile(script).unwrap(); + + bench.iter(|| engine.consume_ast(&ast).unwrap()); +} + +#[bench] +fn bench_eval_loop_strings_build(bench: &mut Bencher) { + let script = r#" + let s = 0; + for x in range(0, 10000) { + s += "x"; + } + "#; + + let mut engine = Engine::new(); + engine.set_optimization_level(OptimizationLevel::None); + + let ast = engine.compile(script).unwrap(); + + bench.iter(|| engine.consume_ast(&ast).unwrap()); +} + +#[bench] +fn bench_eval_loop_strings_no_build(bench: &mut Bencher) { + let script = r#" + let s = "hello"; + for x in range(0, 10000) { + s += ""; + } + "#; + + let mut engine = Engine::new(); + engine.set_optimization_level(OptimizationLevel::None); + + let ast = engine.compile(script).unwrap(); + + bench.iter(|| engine.consume_ast(&ast).unwrap()); +} diff --git a/src/any.rs b/src/any.rs index 768c66bb..5a72e957 100644 --- a/src/any.rs +++ b/src/any.rs @@ -1,5 +1,6 @@ //! Helper module which defines the `Any` trait to to allow dynamic value handling. +use crate::fn_native::shared_unwrap; use crate::parser::{ImmutableString, INT}; use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast}; @@ -20,7 +21,9 @@ use crate::stdlib::{ boxed::Box, collections::HashMap, fmt, + rc::Rc, string::String, + sync::Arc, vec::Vec, }; @@ -585,7 +588,7 @@ impl Dynamic { /// Returns the name of the actual type if the cast fails. pub fn take_string(self) -> Result { match self.0 { - Union::Str(s) => Ok((*s).clone()), + Union::Str(s) => Ok(shared_unwrap(s).unwrap_or_else(|s| (*s).clone())), _ => Err(self.type_name()), } } diff --git a/src/engine.rs b/src/engine.rs index 64f7f0d8..9e134769 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1512,8 +1512,9 @@ impl Engine { let mut args: StaticVec<_> = arg_values.iter_mut().collect(); - if name == KEYWORD_EVAL && args.len() == 1 && args.get(0).is::() { - let hash_fn = calc_fn_hash(empty(), name, 1, once(TypeId::of::())); + if name == KEYWORD_EVAL && args.len() == 1 && args.get(0).is::() { + let hash_fn = + calc_fn_hash(empty(), name, 1, once(TypeId::of::())); if !self.has_override(lib, (hash_fn, *hash)) { // eval - only in function call style diff --git a/src/fn_native.rs b/src/fn_native.rs index 1eaab03a..1975a3c5 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -19,6 +19,28 @@ pub type Shared = Rc; #[cfg(feature = "sync")] pub type Shared = Arc; +pub fn shared_make_mut(value: &mut Shared) -> &mut T { + #[cfg(not(feature = "sync"))] + { + Rc::make_mut(value) + } + #[cfg(feature = "sync")] + { + Arc::make_mut(value) + } +} + +pub fn shared_unwrap(value: Shared) -> Result> { + #[cfg(not(feature = "sync"))] + { + Rc::try_unwrap(value) + } + #[cfg(feature = "sync")] + { + Arc::try_unwrap(value) + } +} + pub type FnCallArgs<'a> = [&'a mut Dynamic]; #[cfg(not(feature = "sync"))] diff --git a/src/packages/string_basic.rs b/src/packages/string_basic.rs index 18839aed..f7ae8930 100644 --- a/src/packages/string_basic.rs +++ b/src/packages/string_basic.rs @@ -1,5 +1,6 @@ use crate::def_package; use crate::engine::{FUNC_TO_STRING, KEYWORD_DEBUG, KEYWORD_PRINT}; +use crate::fn_native::shared_make_mut; use crate::module::FuncReturn; use crate::parser::{ImmutableString, INT}; @@ -41,8 +42,8 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin lib.set_fn_1(KEYWORD_PRINT, |_: ()| Ok("".to_string())); lib.set_fn_1(FUNC_TO_STRING, |_: ()| Ok("".to_string())); - lib.set_fn_1(KEYWORD_PRINT, |s: ImmutableString| Ok(s.clone())); - lib.set_fn_1(FUNC_TO_STRING, |s: ImmutableString| Ok(s.clone())); + lib.set_fn_1(KEYWORD_PRINT, |s: ImmutableString| Ok(s)); + lib.set_fn_1(FUNC_TO_STRING, |s: ImmutableString| Ok(s)); reg_op!(lib, KEYWORD_DEBUG, to_debug, INT, bool, (), char, ImmutableString); @@ -81,6 +82,10 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin lib.set_fn_2( "+", |s: ImmutableString, ch: char| { + if s.is_empty() { + return Ok(ch.to_string().into()); + } + let mut s = (*s).clone(); s.push(ch); Ok(s) @@ -89,23 +94,28 @@ def_package!(crate:BasicStringPackage:"Basic string utilities, including printin lib.set_fn_2( "+", |s:ImmutableString, s2:ImmutableString| { + if s.is_empty() { + return Ok(s2); + } else if s2.is_empty() { + return Ok(s); + } + let mut s = (*s).clone(); s.push_str(s2.as_str()); - Ok(s) + Ok(s.into()) }, ); lib.set_fn_2_mut("append", |s: &mut ImmutableString, ch: char| { - let mut copy = (**s).clone(); - copy.push(ch); - *s = copy.into(); + shared_make_mut(s).push(ch); Ok(()) }); lib.set_fn_2_mut( "append", |s: &mut ImmutableString, s2: ImmutableString| { - let mut copy = (**s).clone(); - copy.push_str(s2.as_str()); - *s = copy.into(); + if !s2.is_empty() { + shared_make_mut(s).push_str(s2.as_str()); + } + Ok(()) } ); diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index 0217fe63..666f9061 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -1,4 +1,5 @@ use crate::def_package; +use crate::fn_native::shared_make_mut; use crate::module::FuncReturn; use crate::parser::{ImmutableString, INT}; use crate::utils::StaticVec; @@ -46,23 +47,19 @@ fn sub_string(s: ImmutableString, start: INT, len: INT) -> FuncReturn FuncReturn<()> { - let mut copy = (**s).clone(); - - let offset = if copy.is_empty() || len <= 0 { - copy.clear(); - *s = copy.into(); + let offset = if s.is_empty() || len <= 0 { + shared_make_mut(s).clear(); return Ok(()); } else if start < 0 { 0 - } else if (start as usize) >= copy.chars().count() { - copy.clear(); - *s = copy.into(); + } else if (start as usize) >= s.chars().count() { + shared_make_mut(s).clear(); return Ok(()); } else { start as usize }; - let chars: StaticVec<_> = copy.chars().collect(); + let chars: StaticVec<_> = s.chars().collect(); let len = if offset + (len as usize) > chars.len() { chars.len() - offset @@ -70,12 +67,10 @@ fn crop_string(s: &mut ImmutableString, start: INT, len: INT) -> FuncReturn<()> len as usize }; - *s = chars - .iter() - .skip(offset) - .take(len) - .collect::() - .into(); + let copy = shared_make_mut(s); + copy.clear(); + copy.extend(chars.iter().skip(offset).take(len)); + Ok(()) } @@ -171,21 +166,17 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str }, ); lib.set_fn_1_mut("clear", |s: &mut ImmutableString| { - *s = "".to_string().into(); + shared_make_mut(s).clear(); Ok(()) }); lib.set_fn_2_mut("append", |s: &mut ImmutableString, ch: char| { - let mut copy = (**s).clone(); - copy.push(ch); - *s = copy.into(); + shared_make_mut(s).push(ch); Ok(()) }); lib.set_fn_2_mut( "append", |s: &mut ImmutableString, add: ImmutableString| { - let mut copy = (**s).clone(); - copy.push_str(add.as_str()); - *s = copy.into(); + shared_make_mut(s).push_str(add.as_str()); Ok(()) } ); @@ -205,10 +196,13 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str lib.set_fn_2_mut( "truncate", |s: &mut ImmutableString, len: INT| { - if len >= 0 { - *s = (**s).clone().chars().take(len as usize).collect::().into(); + if len > 0 { + let chars: StaticVec<_> = s.chars().collect(); + let copy = shared_make_mut(s); + copy.clear(); + copy.extend(chars.into_iter().take(len as usize)); } else { - *s = "".to_string().into(); + shared_make_mut(s).clear(); } Ok(()) }, @@ -216,11 +210,10 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str lib.set_fn_3_mut( "pad", |s: &mut ImmutableString, len: INT, ch: char| { - let mut copy = (**s).clone(); + let copy = shared_make_mut(s); for _ in 0..copy.chars().count() - len as usize { copy.push(ch); } - *s = copy.into(); Ok(()) }, );