[njs] Added String.prototype.trimStrart() and String.prototype.trimEnd().

Valentin Bartenev vbart at nginx.com
Sun Jul 28 10:19:19 UTC 2019


details:   https://hg.nginx.org/njs/rev/258b1e34ca0f
branches:  
changeset: 1079:258b1e34ca0f
user:      Valentin Bartenev <vbart at nginx.com>
date:      Sun Jul 28 13:19:03 2019 +0300
description:
Added String.prototype.trimStrart() and String.prototype.trimEnd().

diffstat:

 njs/njs_string.c         |  248 ++++++++++++++++++++++++----------------------
 njs/test/njs_unit_test.c |   12 +-
 nxt/nxt_string.h         |   19 +++
 nxt/nxt_utf8.h           |   37 +++++++
 4 files changed, 189 insertions(+), 127 deletions(-)

diffs (424 lines):

diff -r ac39f4c902b5 -r 258b1e34ca0f njs/njs_string.c
--- a/njs/njs_string.c	Sun Jul 28 13:17:13 2019 +0300
+++ b/njs/njs_string.c	Sun Jul 28 13:19:03 2019 +0300
@@ -10,6 +10,10 @@
 #include <string.h>
 
 
+#define NJS_TRIM_START  1
+#define NJS_TRIM_END    2
+
+
 typedef struct {
     u_char                     *start;
     size_t                     size;
@@ -68,6 +72,8 @@ static njs_ret_t njs_string_bytes_from_s
     const njs_value_t *args, nxt_uint_t nargs);
 static njs_ret_t njs_string_starts_or_ends_with(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, nxt_bool_t starts);
+static njs_ret_t njs_string_trim(njs_vm_t *vm, njs_value_t *value,
+    nxt_uint_t mode);
 static njs_ret_t njs_string_prototype_pad(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, nxt_bool_t pad_start);
 static njs_ret_t njs_string_match_multiple(njs_vm_t *vm, njs_value_t *args,
@@ -2356,158 +2362,138 @@ static njs_ret_t
 njs_string_prototype_trim(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
+    return njs_string_trim(vm, &args[0], NJS_TRIM_START|NJS_TRIM_END);
+}
+
+
+static njs_ret_t
+njs_string_prototype_trim_start(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    return njs_string_trim(vm, &args[0], NJS_TRIM_START);
+}
+
+
+static njs_ret_t
+njs_string_prototype_trim_end(njs_vm_t *vm, njs_value_t *args,
+    nxt_uint_t nargs, njs_index_t unused)
+{
+    return njs_string_trim(vm, &args[0], NJS_TRIM_END);
+}
+
+
+static njs_ret_t
+njs_string_trim(njs_vm_t *vm, njs_value_t *value, nxt_uint_t mode)
+{
     uint32_t           u, trim, length;
     const u_char       *p, *prev, *start, *end;
     njs_string_prop_t  string;
 
     trim = 0;
 
-    njs_string_prop(&string, &args[0]);
-
-    p = string.start;
+    njs_string_prop(&string, value);
+
+    start = string.start;
     end = string.start + string.size;
 
     if (string.length == 0 || string.length == string.size) {
         /* Byte or ASCII string. */
 
-        while (p < end) {
-
-            switch (*p) {
-            case 0x09:  /* <TAB>  */
-            case 0x0A:  /* <LF>   */
-            case 0x0B:  /* <VT>   */
-            case 0x0C:  /* <FF>   */
-            case 0x0D:  /* <CR>   */
-            case 0x20:  /* <SP>   */
-            case 0xA0:  /* <NBSP> */
-                trim++;
-                p++;
-                continue;
-
-            default:
-                start = p;
-                p = end;
-
-                for ( ;; ) {
-                    p--;
-
-                    switch (*p) {
-                    case 0x09:  /* <TAB>  */
-                    case 0x0A:  /* <LF>   */
-                    case 0x0B:  /* <VT>   */
-                    case 0x0C:  /* <FF>   */
-                    case 0x0D:  /* <CR>   */
-                    case 0x20:  /* <SP>   */
-                    case 0xA0:  /* <NBSP> */
-                        trim++;
-                        continue;
-
-                    default:
-                        p++;
-                        goto done;
-                    }
+        if (mode & NJS_TRIM_START) {
+            for ( ;; ) {
+                if (start == end) {
+                    goto empty;
+                }
+
+                if (nxt_is_whitespace(*start)) {
+                    start++;
+                    trim++;
+                    continue;
                 }
+
+                break;
+            }
+        }
+
+        if (mode & NJS_TRIM_END) {
+            for ( ;; ) {
+                if (start == end) {
+                    goto empty;
+                }
+
+                end--;
+
+                if (nxt_is_whitespace(*end)) {
+                    trim++;
+                    continue;
+                }
+
+                end++;
+                break;
             }
         }
 
     } else {
         /* UTF-8 string. */
 
-        while (p < end) {
-            prev = p;
-            u = nxt_utf8_decode(&p, end);
-
-            switch (u) {
-            case 0x0009:  /* <TAB>  */
-            case 0x000A:  /* <LF>   */
-            case 0x000B:  /* <VT>   */
-            case 0x000C:  /* <FF>   */
-            case 0x000D:  /* <CR>   */
-            case 0x0020:  /* <SP>   */
-            case 0x00A0:  /* <NBSP> */
-            case 0x1680:
-            case 0x2000:
-            case 0x2001:
-            case 0x2002:
-            case 0x2003:
-            case 0x2004:
-            case 0x2005:
-            case 0x2006:
-            case 0x2007:
-            case 0x2008:
-            case 0x2009:
-            case 0x200A:
-            case 0x2028:  /* <LS>   */
-            case 0x2029:  /* <PS>   */
-            case 0x202F:
-            case 0x205F:
-            case 0x3000:
-            case 0xFEFF:  /* <BOM>  */
-                trim++;
-                continue;
-
-            default:
-                start = prev;
-                prev = end;
-
-                for ( ;; ) {
-                    prev = nxt_utf8_prev(prev);
-                    p = prev;
-                    u = nxt_utf8_decode(&p, end);
-
-                    switch (u) {
-                    case 0x0009:  /* <TAB>  */
-                    case 0x000A:  /* <LF>   */
-                    case 0x000B:  /* <VT>   */
-                    case 0x000C:  /* <FF>   */
-                    case 0x000D:  /* <CR>   */
-                    case 0x0020:  /* <SP>   */
-                    case 0x00A0:  /* <NBSP> */
-                    case 0x1680:
-                    case 0x2000:
-                    case 0x2001:
-                    case 0x2002:
-                    case 0x2003:
-                    case 0x2004:
-                    case 0x2005:
-                    case 0x2006:
-                    case 0x2007:
-                    case 0x2008:
-                    case 0x2009:
-                    case 0x200A:
-                    case 0x2028:  /* <LS>   */
-                    case 0x2029:  /* <PS>   */
-                    case 0x202F:
-                    case 0x205F:
-                    case 0x3000:
-                    case 0xFEFF:  /* <BOM>  */
-                        trim++;
-                        continue;
-
-                    default:
-                        goto done;
-                    }
+        if (mode & NJS_TRIM_START) {
+            for ( ;; ) {
+                if (start == end) {
+                    goto empty;
+                }
+
+                p = start;
+                u = nxt_utf8_decode(&start, end);
+
+                if (nxt_utf8_is_whitespace(u)) {
+                    trim++;
+                    continue;
                 }
+
+                start = p;
+                break;
+            }
+        }
+
+        if (mode & NJS_TRIM_END) {
+            prev = end;
+
+            for ( ;; ) {
+                if (start == prev) {
+                    goto empty;
+                }
+
+                prev = nxt_utf8_prev(prev);
+                p = prev;
+                u = nxt_utf8_decode(&p, end);
+
+                if (nxt_utf8_is_whitespace(u)) {
+                    trim++;
+                    continue;
+                }
+
+                end = p;
+                break;
             }
         }
     }
 
-    vm->retval = njs_string_empty;
-
-    return NXT_OK;
-
-done:
-
     if (trim == 0) {
         /* GC: retain. */
-        vm->retval = args[0];
+        vm->retval = *value;
 
         return NXT_OK;
     }
 
     length = (string.length != 0) ? string.length - trim : 0;
 
-    return njs_string_new(vm, &vm->retval, start, p - start, length);
+    return njs_string_new(vm, &vm->retval, start, end - start, length);
+
+empty:
+
+    vm->retval = njs_string_empty;
+
+    return NXT_OK;
 }
 
 
@@ -4250,6 +4236,26 @@ static const njs_object_prop_t  njs_stri
         .configurable = 1,
     },
 
+    /* ES10. */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("trimStart"),
+        .value = njs_native_function(njs_string_prototype_trim_start,
+                                     NJS_STRING_OBJECT_ARG),
+        .writable = 1,
+        .configurable = 1,
+    },
+
+    /* ES10. */
+    {
+        .type = NJS_METHOD,
+        .name = njs_string("trimEnd"),
+        .value = njs_native_function(njs_string_prototype_trim_end,
+                                     NJS_STRING_OBJECT_ARG),
+        .writable = 1,
+        .configurable = 1,
+    },
+
     /* ES6. */
     {
         .type = NJS_METHOD,
diff -r ac39f4c902b5 -r 258b1e34ca0f njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Sun Jul 28 13:17:13 2019 +0300
+++ b/njs/test/njs_unit_test.c	Sun Jul 28 13:19:03 2019 +0300
@@ -5623,7 +5623,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("304,453,456,459,498,1012,7838,8486,8490,8491") },
 #endif
 
-    { nxt_string("'abc'.trim()"),
+    { nxt_string("'abc'.trimStart().trim().trimEnd()"),
       nxt_string("abc") },
 
     { nxt_string("''.trim()"),
@@ -5632,22 +5632,22 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("'    '.trim()"),
       nxt_string("") },
 
-    { nxt_string("'abc  '.trim()"),
+    { nxt_string("'abc  '.trimEnd()"),
       nxt_string("abc") },
 
-    { nxt_string("'   abc'.trim()"),
+    { nxt_string("'   abc'.trimStart()"),
       nxt_string("abc") },
 
     { nxt_string("'   abc  '.trim()"),
       nxt_string("abc") },
 
-    { nxt_string("'абв  '.trim()"),
+    { nxt_string("'абв  '.trimEnd()"),
       nxt_string("абв") },
 
-    { nxt_string("'   абв'.trim()"),
+    { nxt_string("'   абв'.trimStart()"),
       nxt_string("абв") },
 
-    { nxt_string("'   абв  '.trim()"),
+    { nxt_string("'   абв  '.trimStart().trimEnd()"),
       nxt_string("абв") },
 
     { nxt_string("'\\u2029abc\\uFEFF\\u2028'.trim()"),
diff -r ac39f4c902b5 -r 258b1e34ca0f nxt/nxt_string.h
--- a/nxt/nxt_string.h	Sun Jul 28 13:17:13 2019 +0300
+++ b/nxt/nxt_string.h	Sun Jul 28 13:19:03 2019 +0300
@@ -41,6 +41,25 @@ nxt_upper_case(u_char c)
 }
 
 
+nxt_inline nxt_bool_t
+nxt_is_whitespace(u_char c)
+{
+    switch (c) {
+    case 0x09:  /* <TAB>  */
+    case 0x0A:  /* <LF>   */
+    case 0x0B:  /* <VT>   */
+    case 0x0C:  /* <FF>   */
+    case 0x0D:  /* <CR>   */
+    case 0x20:  /* <SP>   */
+    case 0xA0:  /* <NBSP> */
+        return 1;
+
+    default:
+        return 0;
+    }
+}
+
+
 nxt_inline u_char *
 nxt_strlchr(u_char *p, u_char *last, u_char c)
 {
diff -r ac39f4c902b5 -r 258b1e34ca0f nxt/nxt_utf8.h
--- a/nxt/nxt_utf8.h	Sun Jul 28 13:17:13 2019 +0300
+++ b/nxt/nxt_utf8.h	Sun Jul 28 13:19:03 2019 +0300
@@ -122,4 +122,41 @@ nxt_utf8_copy(u_char *dst, const u_char 
     ((u < 0x80) ? 1 : ((u < 0x0800) ? 2 : 3))
 
 
+nxt_inline nxt_bool_t
+nxt_utf8_is_whitespace(uint32_t c)
+{
+    switch (c) {
+    case 0x0009:  /* <TAB>  */
+    case 0x000A:  /* <LF>   */
+    case 0x000B:  /* <VT>   */
+    case 0x000C:  /* <FF>   */
+    case 0x000D:  /* <CR>   */
+    case 0x0020:  /* <SP>   */
+    case 0x00A0:  /* <NBSP> */
+    case 0x1680:
+    case 0x2000:
+    case 0x2001:
+    case 0x2002:
+    case 0x2003:
+    case 0x2004:
+    case 0x2005:
+    case 0x2006:
+    case 0x2007:
+    case 0x2008:
+    case 0x2009:
+    case 0x200A:
+    case 0x2028:  /* <LS>   */
+    case 0x2029:  /* <PS>   */
+    case 0x202F:
+    case 0x205F:
+    case 0x3000:
+    case 0xFEFF:  /* <BOM>  */
+        return 1;
+
+    default:
+        return 0;
+    }
+}
+
+
 #endif /* _NXT_UTF8_H_INCLUDED_ */


More information about the nginx-devel mailing list