From ae6e9d467a9739314ea7bcb17ca62355235479c6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Mon, 2 Dec 2024 12:44:34 +0800 Subject: [PATCH] Optimize string slice --- CHANGELOG.md | 9 ++++++++ src/eval/chaining.rs | 49 +++++++++++++++++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c3d31d2ae..d42838556 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,15 @@ Rhai Release Notes ================== +Version 1.21.0 +============== + +Enhancements +------------ + +* If a string slice refers to the entire string, the slice is not cloned but returned as-is. + + Version 1.20.0 ============== diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index d58dded33..07e5d698c 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -311,6 +311,7 @@ impl Engine { #[cfg(not(feature = "no_index"))] Dynamic(Union::Str(s, ..)) => { + // Numeric index - character match idx.as_int() { Ok(index) => { let (ch, offset) = if index >= 0 { @@ -362,11 +363,29 @@ impl Engine { index: offset, }) } + + // Range index on empty string - empty slice + Err(typ) + if (typ == std::any::type_name::() + || typ == std::any::type_name::()) + && s.is_empty() => + { + let value = s.clone().into(); + Ok(Target::StringSlice { + source: target, + value, + start: 0, + end: 0, + exclusive: true, + }) + } + + // Range index - slice Err(typ) if typ == std::any::type_name::() => { // val_str[range] - let idx = idx.read_lock::().unwrap(); - let range = &*idx; + let range = idx.read_lock::().unwrap().clone(); let chars_count = s.chars().count(); + let start = if range.start >= 0 { range.start as usize } else { @@ -383,12 +402,16 @@ impl Engine { .unwrap_or(0) }; - let take = if end > start { end - start } else { 0 }; - let value = s.chars().skip(start).take(take).collect::(); + let value = if start == 0 && end >= chars_count { + s.clone().into() + } else { + let take = if end > start { end - start } else { 0 }; + s.chars().skip(start).take(take).collect::().into() + }; Ok(Target::StringSlice { source: target, - value: value.into(), + value, start, end, exclusive: true, @@ -396,9 +419,9 @@ impl Engine { } Err(typ) if typ == std::any::type_name::() => { // val_str[range] - let idx = idx.read_lock::().unwrap(); - let range = &*idx; + let range = idx.read_lock::().unwrap().clone(); let chars_count = s.chars().count(); + let start = if *range.start() >= 0 { *range.start() as usize } else { @@ -415,17 +438,23 @@ impl Engine { .unwrap_or(0) }; - let take = if end > start { end - start + 1 } else { 0 }; - let value = s.chars().skip(start).take(take).collect::(); + let value = if start == 0 && end >= chars_count - 1 { + s.clone().into() + } else { + let take = if end > start { end - start + 1 } else { 0 }; + s.chars().skip(start).take(take).collect::().into() + }; Ok(Target::StringSlice { source: target, - value: value.into(), + value, start, end, exclusive: false, }) } + + // Unsupported index type Err(typ) => Err(self.make_type_mismatch_err::(typ, idx_pos)), } }