changeset 2592:8fda8e1f75b5

Improved String.prototype.concat() with scalar values.
author Vadim Zhestikov <v.zhestikov@f5.com>
date Thu, 03 Jul 2025 14:14:43 -0700
parents deb802c9b713
children 29eadf7b6f65
files src/njs_string.c src/test/njs_unit_test.c
diffstat 2 files changed, 75 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/src/njs_string.c	Mon Jul 07 22:40:45 2025 -0700
+++ b/src/njs_string.c	Thu Jul 03 14:14:43 2025 -0700
@@ -608,7 +608,9 @@
     njs_int_t          ret;
     njs_uint_t         i;
     njs_string_prop_t  string;
-    char               buf[512], tmp[NJS_DTOA_MAX_LEN];
+    char               buf[512];
+
+#define NJS_SZ_LAST    64
 
     if (njs_is_null_or_undefined(&args[0])) {
         njs_type_error(vm, "\"this\" argument is null or undefined");
@@ -620,6 +622,7 @@
 
     np = buf;
     np_end = buf + sizeof(buf);
+    *np = 0;
 
     for (i = 0; i < nargs; i++) {
         if (njs_is_number(&args[i])) {
@@ -640,20 +643,42 @@
                 }
 
             } else {
-                if (njs_fast_path(np < np_end - NJS_DTOA_MAX_LEN)) {
-                    sz = njs_dtoa(num, np + sizeof(uint8_t));
-
-                    *np = (uint8_t) sz;
-                    np += sizeof(uint8_t) + sz;
-
-                } else {
-                    sz = njs_dtoa(num, tmp);
+                sz = njs_dtoa(num, np + sizeof(uint8_t));
+
+                if (*np == 0) {
+                    if (np + sizeof(uint8_t) + sz
+                        < np_end - NJS_DTOA_MAX_LEN - sizeof(uint8_t))
+                    {
+                        *np = (uint8_t) sz;
+                        np += sizeof(uint8_t) + sz;
+                        *np = 0;
+
+                    } else {
+                        *np = NJS_SZ_LAST;
+                    }
                 }
 
                 size += sz;
                 length += sz;
             }
 
+        } else if (njs_is_boolean(&args[i])) {
+            if (njs_is_true(&args[i])) {
+                size += njs_length("true");
+                length += njs_length("true");
+            } else {
+                size += njs_length("false");
+                length += njs_length("false");
+            }
+
+        } else if (njs_is_null(&args[i])) {
+            size += njs_length("null");
+            length += njs_length("null");
+
+        } else if (njs_is_undefined(&args[i])) {
+            size += njs_length("undefined");
+            length += njs_length("undefined");
+
         } else {
             if (!njs_is_string(&args[i])) {
                 ret = njs_value_to_string(vm, &args[i], &args[i]);
@@ -693,10 +718,10 @@
                 }
 
             } else {
-                if (njs_fast_path(np < np_end - NJS_DTOA_MAX_LEN)) {
-                    length = *np++;
-                    p = njs_cpymem(p, np, length);
-                    np += length;
+                if (*np != NJS_SZ_LAST) {
+                    sz = *np++;
+                    p = njs_cpymem(p, np, sz);
+                    np += sz;
 
                 } else {
                     sz = njs_dtoa(num, (char *) p);
@@ -704,6 +729,19 @@
                 }
             }
 
+        } else if (njs_is_boolean(&args[i])) {
+            if (njs_is_true(&args[i])) {
+                p = njs_cpymem(p, "true", njs_length("true"));
+            } else {
+                p = njs_cpymem(p, "false", njs_length("false"));
+            }
+
+        } else if (njs_is_null(&args[i])) {
+            p = njs_cpymem(p, "null", njs_length("null"));
+
+        } else if (njs_is_undefined(&args[i])) {
+            p = njs_cpymem(p, "undefined", njs_length("undefined"));
+
         } else {
             njs_string_prop(vm, &string, &args[i]);
 
--- a/src/test/njs_unit_test.c	Mon Jul 07 22:40:45 2025 -0700
+++ b/src/test/njs_unit_test.c	Thu Jul 03 14:14:43 2025 -0700
@@ -11003,6 +11003,30 @@
                  "f.apply(123, {})"),
       njs_str("123") },
 
+    { njs_str("'Hello'.concat(' ', 'World')"),
+      njs_str("Hello World") },
+
+    { njs_str("'Value: '.concat(42, ' and ', 3.14)"),
+      njs_str("Value: 42 and 3.14") },
+
+    { njs_str("'Flags: '.concat(true, ' and ', false)"),
+      njs_str("Flags: true and false") },
+
+    { njs_str("'Values: '.concat(null, ' and ', undefined)"),
+      njs_str("Values: null and undefined") },
+
+    { njs_str("'Mixed: '.concat(123, ' ', true, ' ', null, ' ', undefined)"),
+      njs_str("Mixed: 123 true null undefined") },
+
+    { njs_str("'Special: '.concat(NaN, ' ', Infinity, ' ', -Infinity)"),
+      njs_str("Special: NaN Infinity -Infinity") },
+
+    { njs_str("'Numbers: '.concat(1234567890, ' ', 0.123456789, ' ', 1.23e-10)"),
+      njs_str("Numbers: 1234567890 0.123456789 1.23e-10") },
+
+    { njs_str("'Zero: '.concat(0, ' ', -0)"),
+      njs_str("Zero: 0 0") },
+
     { njs_str("(function(index, ...rest){ return rest[index];})"
               ".apply({}, [1022].concat(Array(1023).fill(1).map((v,i)=>i.toString(16))))"),
       njs_str("3fe") },