mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
perf: JsString 缓存 UTF-16 length,字符串 length 访问改 O(1)
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
//! 闭包共享 cell (`Cell`)。
|
||||
|
||||
use crate::value::JsValue;
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
|
||||
/// 堆分配的 JS 字符串值。
|
||||
///
|
||||
@@ -14,12 +15,24 @@ use crate::value::JsValue;
|
||||
#[derive(Debug)]
|
||||
pub struct JsString {
|
||||
pub data: String,
|
||||
/// JS 语义的字符串长度(UTF-16 code unit 数)懒缓存。
|
||||
///
|
||||
/// 构造是热路径(拼接/格式化),长度查询少见,故不预付 O(n) 扫描;首次
|
||||
/// `utf16_len()` 访问时计算一次。以 sentinel + `AtomicU32` 实现:perm 字符串
|
||||
/// 可被多线程 VM 共享读,计算幂等,relaxed 序即可。
|
||||
utf16_len: AtomicU32,
|
||||
}
|
||||
|
||||
/// `utf16_len` 未计算的哨兵值(有效长度不可能为 u32::MAX)。
|
||||
const UTF16_LEN_UNSET: u32 = u32::MAX;
|
||||
|
||||
impl JsString {
|
||||
/// 用 UTF-8 数据构造字符串。
|
||||
pub fn new(data: String) -> Self {
|
||||
Self { data }
|
||||
Self {
|
||||
data,
|
||||
utf16_len: AtomicU32::new(UTF16_LEN_UNSET),
|
||||
}
|
||||
}
|
||||
|
||||
/// 字符串的字节长度(非字符数)。
|
||||
@@ -27,6 +40,17 @@ impl JsString {
|
||||
self.data.len()
|
||||
}
|
||||
|
||||
/// JS 字符串长度(UTF-16 code unit 数)。首次访问计算并缓存,此后 O(1)。
|
||||
pub fn utf16_len(&self) -> u32 {
|
||||
let cached = self.utf16_len.load(Ordering::Relaxed);
|
||||
if cached != UTF16_LEN_UNSET {
|
||||
return cached;
|
||||
}
|
||||
let len = self.data.encode_utf16().count() as u32;
|
||||
self.utf16_len.store(len, Ordering::Relaxed);
|
||||
len
|
||||
}
|
||||
|
||||
/// 是否为空字符串。
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.data.is_empty()
|
||||
|
||||
@@ -47,8 +47,8 @@ impl Vm {
|
||||
if val.is_string() {
|
||||
let length_si = self.kernel_core.perm_interner().intern("length").0;
|
||||
if prop_name_si == length_si {
|
||||
// SAFETY: val 是字符串值。
|
||||
let len = unsafe { (*val.as_string_ptr()).data.encode_utf16().count() };
|
||||
// SAFETY: val 是字符串值。utf16_len 构造时缓存,O(1) 读取。
|
||||
let len = unsafe { (*val.as_string_ptr()).utf16_len() };
|
||||
return Ok(Some(JsValue::int(len as i32)));
|
||||
}
|
||||
let proto_ptr = self.session.builtin_world().string_proto.as_ptr() as *mut JsObject;
|
||||
|
||||
Reference in New Issue
Block a user