From 59a9469483054a8b11a88a5e5683b152afd3ac34 Mon Sep 17 00:00:00 2001 From: Gordon Williams Date: Tue, 29 Oct 2024 10:55:45 +0000 Subject: [PATCH] RegExp: add optimisation for RegExp that is simply checking if a string ends with something Speeds up .hash on Bangle.js --- ChangeLog | 1 + README_BuildProcess.md | 1 + src/jswrap_regexp.c | 47 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 49 insertions(+) diff --git a/ChangeLog b/ChangeLog index b0b5bb844..b13e1cd3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -53,6 +53,7 @@ E.nativeCall also checks to see if getting data as a flat string failed (could have caused segfault) Fix for regression after #2547 fix (left hand operand of maths with a valueOf method) X.on now allocates a new array for each new handler added, stops new handlers being called for the event that's currently being handled (#2559) + RegExp: add optimisation for RegExp that is simply checking if a string ends with something 2v24 : Bangle.js2: Add 'Bangle.touchRd()', 'Bangle.touchWr()' Bangle.js2: After Bangle.showTestScreen, put Bangle.js into a hard off state (not soft off) diff --git a/README_BuildProcess.md b/README_BuildProcess.md index 23f3e3363..f15536444 100644 --- a/README_BuildProcess.md +++ b/README_BuildProcess.md @@ -157,6 +157,7 @@ There are some specifically that are useful for cutting a few bytes out of the b * `ESPR_NO_SOFTWARE_I2C` - don't build in software I2C support * `ESPR_NO_BLUETOOTH_MESSAGES` - don't include text versions of Bluetooth error messages (just the error number) * `ESPR_LIMIT_DATE_RANGE` - limits the acceptable range for Date years (saves a few hundred bytes) +* `ESPR_NO_REGEX_OPTIMISE` - strips out some speed optimisations from the regex library These are set automatically when `SAVE_ON_FLASH` is set (see `jsutils.h`) diff --git a/src/jswrap_regexp.c b/src/jswrap_regexp.c index e5307413f..f7e8564e9 100644 --- a/src/jswrap_regexp.c +++ b/src/jswrap_regexp.c @@ -317,6 +317,35 @@ JsVar *jswrap_regexp_constructor(JsVar *str, JsVar *flags) { jsvObjectSetChild(r, "flags", flags); } jsvObjectSetChildAndUnLock(r, "lastIndex", jsvNewFromInteger(0)); +#ifndef ESPR_NO_REGEX_OPTIMISE + /* Quick shortcut - if we were using regex just to find the end of a string (eg just + normal chars and then $ at the end), do it with a single string compare which is faster. + We save `endsWith` here and then check in jswrap_regexp_exec */ + JsvStringIterator it; + jsvStringIteratorNew(&it,str,0); + char ch = 0; + bool noControlChars = true; + char buf[32]; + size_t bufc = 0; + while (jsvStringIteratorHasChar(&it)) { + bool wasSlash = ch=='\\'; + if (ch && strchr(".[]()|^*+$",ch)) noControlChars = false; + ch = jsvStringIteratorGetCharAndNext(&it); + if (wasSlash) { + if (!strchr(".\\",ch)) { + noControlChars = false; + ch = 0; + } + } + if (ch && (wasSlash || ch!='\\') && bufc(JsVarInt)jsvGetStringLength(str)) { jsvUnLock2(str,regex);