[njs] Introduced generic string builder API.

Dmitry Volyntsev xeioex at nginx.com
Wed Dec 11 12:58:28 UTC 2019


details:   https://hg.nginx.org/njs/rev/5ba9145d9b0c
branches:  
changeset: 1282:5ba9145d9b0c
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Wed Dec 11 15:30:26 2019 +0300
description:
Introduced generic string builder API.

diffstat:

 auto/sources             |    1 +
 src/njs_chb.c            |  242 ++++++++++++++++++++++++
 src/njs_chb.h            |  114 +++++++++++
 src/njs_json.c           |  464 +++++++++++++---------------------------------
 src/njs_main.h           |    1 +
 src/njs_vm.c             |   68 +-----
 src/test/njs_unit_test.c |  146 ++++++++++++++
 7 files changed, 649 insertions(+), 387 deletions(-)

diffs (truncated from 1548 to 1000 lines):

diff -r 3bef40125db2 -r 5ba9145d9b0c auto/sources
--- a/auto/sources	Wed Nov 27 14:02:04 2019 +0000
+++ b/auto/sources	Wed Dec 11 15:30:26 2019 +0300
@@ -20,6 +20,7 @@ NJS_LIB_SRCS=" \
    src/njs_malloc.c \
    src/njs_mp.c \
    src/njs_sprintf.c \
+   src/njs_chb.c \
    src/njs_value.c \
    src/njs_vm.c \
    src/njs_vmcode.c \
diff -r 3bef40125db2 -r 5ba9145d9b0c src/njs_chb.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/njs_chb.c	Wed Dec 11 15:30:26 2019 +0300
@@ -0,0 +1,242 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+
+#include <njs_main.h>
+
+
+#define NJS_CHB_MIN_SIZE       256
+
+
+void
+njs_chb_append0(njs_chb_t *chain, const char *msg, size_t len)
+{
+    u_char  *p;
+
+    if (len != 0 && !chain->error) {
+        p = njs_chb_reserve(chain, len);
+        if (njs_slow_path(p == NULL)) {
+            return;
+        }
+
+        memcpy(p, msg, len);
+
+        njs_chb_written(chain, len);
+    }
+}
+
+
+u_char *
+njs_chb_reserve(njs_chb_t *chain, size_t size)
+{
+    njs_chb_node_t  *n;
+
+    if (njs_slow_path(size == 0)) {
+        return NULL;
+    }
+
+    n = chain->last;
+
+    if (njs_fast_path(n != NULL && njs_chb_node_room(n) >= size)) {
+        return n->pos;
+    }
+
+    if (size < NJS_CHB_MIN_SIZE) {
+        size = NJS_CHB_MIN_SIZE;
+    }
+
+    n = njs_mp_alloc(chain->pool, sizeof(njs_chb_node_t) + size);
+    if (njs_slow_path(n == NULL)) {
+        chain->error = 1;
+        return NULL;
+    }
+
+    n->next = NULL;
+    n->start = (u_char *) n + sizeof(njs_chb_node_t);
+    n->pos = n->start;
+    n->end = n->pos + size;
+
+    if (chain->last != NULL) {
+        chain->last->next = n;
+
+    } else {
+        chain->nodes = n;
+    }
+
+    chain->last = n;
+
+    return n->start;
+}
+
+
+void
+njs_chb_vsprintf(njs_chb_t *chain, size_t size, const char *fmt, va_list args)
+{
+    u_char  *start, *end;
+
+    start = njs_chb_reserve(chain, size);
+    if (njs_slow_path(start == NULL)) {
+        return;
+    }
+
+    end = njs_vsprintf(start, start + size, fmt, args);
+
+    njs_chb_written(chain, end - start);
+}
+
+
+void
+njs_chb_sprintf(njs_chb_t *chain, size_t size, const char* fmt, ...)
+{
+    va_list  args;
+
+    va_start(args, fmt);
+
+    njs_chb_vsprintf(chain, size, fmt, args);
+
+    va_end(args);
+}
+
+
+/*
+ * Drains size bytes from the beginning of the chain.
+ */
+void
+njs_chb_drain(njs_chb_t *chain, size_t drain)
+{
+    njs_chb_node_t  *n;
+
+    n = chain->nodes;
+
+    while (n != NULL) {
+        if (njs_chb_node_size(n) > drain) {
+            n->start += drain;
+            return;
+        }
+
+        drain -= njs_chb_node_size(n);
+        chain->nodes = n->next;
+
+        njs_mp_free(chain->pool, n);
+        n = chain->nodes;
+    }
+
+    chain->last = NULL;
+}
+
+
+/*
+ * Drops size bytes from the end of the chain.
+ */
+void
+njs_chb_drop(njs_chb_t *chain, size_t drop)
+{
+    size_t          size;
+    njs_chb_node_t  *n, *next;
+
+    n = chain->last;
+
+    if (njs_fast_path(n != NULL && (njs_chb_node_size(n) > drop))) {
+        n->pos -= drop;
+        return;
+    }
+
+    n = chain->nodes;
+    size = njs_chb_size(chain);
+
+    if (drop >= size) {
+        njs_chb_destroy(chain);
+        njs_chb_init(chain, chain->pool);
+        return;
+    }
+
+    while (n != NULL) {
+        size -= njs_chb_node_size(n);
+
+        if (size <= drop) {
+            chain->last = n;
+            chain->last->pos -= drop - size;
+
+            n = chain->last->next;
+            chain->last->next = NULL;
+
+            break;
+        }
+
+        n = n->next;
+    }
+
+    while (n != NULL) {
+        next = n->next;
+        njs_mp_free(chain->pool, n);
+        n = next;
+    }
+}
+
+
+njs_int_t
+njs_chb_join(njs_chb_t *chain, njs_str_t *str)
+{
+    u_char          *start;
+    size_t          size;
+    njs_chb_node_t  *n;
+
+    if (chain->error) {
+        return NJS_DECLINED;
+    }
+
+    n = chain->nodes;
+
+    if (n == NULL) {
+        str->length = 0;
+        str->start = NULL;
+        return NJS_OK;
+    }
+
+    size = njs_chb_size(chain);
+
+    start = njs_mp_alloc(chain->pool, size);
+    if (njs_slow_path(start == NULL)) {
+        return NJS_ERROR;
+    }
+
+    n = chain->nodes;
+    str->length = size;
+    str->start = start;
+
+    njs_chb_join_to(chain, start);
+
+    return NJS_OK;
+}
+
+
+void
+njs_chb_join_to(njs_chb_t *chain, u_char *dst)
+{
+    njs_chb_node_t  *n;
+
+    n = chain->nodes;
+
+    while (n != NULL) {
+        dst = njs_cpymem(dst, n->start, njs_chb_node_size(n));
+        n = n->next;
+    }
+}
+
+
+void
+njs_chb_destroy(njs_chb_t *chain)
+{
+    njs_chb_node_t  *n, *next;
+
+    n = chain->nodes;
+
+    while (n != NULL) {
+        next = n->next;
+        njs_mp_free(chain->pool, n);
+        n = next;
+    }
+}
diff -r 3bef40125db2 -r 5ba9145d9b0c src/njs_chb.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/njs_chb.h	Wed Dec 11 15:30:26 2019 +0300
@@ -0,0 +1,114 @@
+
+/*
+ * Copyright (C) Dmitry Volyntsev
+ * Copyright (C) NGINX, Inc.
+ */
+
+#ifndef _NJS_CHB_H_INCLUDED_
+#define _NJS_CHB_H_INCLUDED_
+
+
+typedef struct njs_chb_node_s njs_chb_node_t;
+
+struct njs_chb_node_s {
+    njs_chb_node_t          *next;
+    u_char                  *start;
+    u_char                  *pos;
+    u_char                  *end;
+};
+
+typedef struct {
+    njs_bool_t              error;
+    njs_mp_t                *pool;
+    njs_chb_node_t          *nodes;
+    njs_chb_node_t          *last;
+} njs_chb_t;
+
+
+void njs_chb_append0(njs_chb_t *chain, const char *msg, size_t len);
+void njs_chb_vsprintf(njs_chb_t *chain, size_t size, const char *fmt,
+    va_list args);
+void njs_chb_sprintf(njs_chb_t *chain, size_t size, const char* fmt, ...);
+u_char *njs_chb_reserve(njs_chb_t *chain, size_t size);
+void njs_chb_drain(njs_chb_t *chain, size_t drop);
+void njs_chb_drop(njs_chb_t *chain, size_t drop);
+njs_int_t njs_chb_join(njs_chb_t *chain, njs_str_t *str);
+void njs_chb_join_to(njs_chb_t *chain, u_char *dst);
+void njs_chb_destroy(njs_chb_t *chain);
+
+
+#define njs_chb_append(chain, msg, len)                                      \
+    njs_chb_append0(chain, (const char *) msg, len)
+
+#define njs_chb_append_literal(chain, literal)                               \
+    njs_chb_append0(chain, literal, njs_length(literal))
+
+#define njs_chb_append_str(chain, str)                                       \
+    njs_chb_append0(chain, (const char *) (str)->start, (str)->length)
+
+
+#define njs_chb_node_size(n) (size_t) ((n)->pos - (n)->start)
+#define njs_chb_node_room(n) (size_t) ((n)->end - (n)->pos)
+
+
+njs_inline void
+njs_chb_init(njs_chb_t *chain, njs_mp_t *pool)
+{
+    chain->error = 0;
+    chain->pool = pool;
+    chain->nodes = NULL;
+    chain->last = NULL;
+}
+
+
+njs_inline size_t
+njs_chb_size(njs_chb_t *chain)
+{
+    size_t          size;
+    njs_chb_node_t  *n;
+
+    n = chain->nodes;
+
+    size = 0;
+
+    while (n != NULL) {
+        size += njs_chb_node_size(n);
+        n = n->next;
+    }
+
+    return size;
+}
+
+
+njs_inline ssize_t
+njs_chb_utf8_length(njs_chb_t *chain)
+{
+    ssize_t         len, length;
+    njs_chb_node_t  *n;
+
+    n = chain->nodes;
+
+    length = 0;
+
+    while (n != NULL) {
+        len = njs_utf8_length(n->start, njs_chb_node_size(n));
+        if (njs_slow_path(len < 0)) {
+            return len;
+        }
+
+        length += len;
+        n = n->next;
+    }
+
+    return length;
+}
+
+
+njs_inline void
+njs_chb_written(njs_chb_t *chain, size_t bytes)
+{
+    chain->last->pos += bytes;
+}
+
+
+#endif /* _NJS_JSON_H_INCLUDED_ */
diff -r 3bef40125db2 -r 5ba9145d9b0c src/njs_json.c
--- a/src/njs_json.c	Wed Nov 27 14:02:04 2019 +0000
+++ b/src/njs_json.c	Wed Dec 11 15:30:26 2019 +0300
@@ -44,23 +44,10 @@ typedef struct {
 } njs_json_parse_t;
 
 
-typedef struct njs_chb_node_s njs_chb_node_t;
-
-struct njs_chb_node_s {
-    njs_chb_node_t             *next;
-    u_char                     *start;
-    u_char                     *pos;
-    u_char                     *end;
-};
-
-
 typedef struct {
     njs_value_t                retval;
 
     njs_vm_t                   *vm;
-    njs_mp_t                   *pool;
-    njs_chb_node_t             *nodes;
-    njs_chb_node_t             *last;
 
     njs_uint_t                 depth;
     njs_json_state_t           states[NJS_JSON_MAX_DEPTH];
@@ -104,33 +91,15 @@ static njs_int_t njs_json_stringify_repl
 static njs_int_t njs_json_stringify_array(njs_vm_t *vm,
     njs_json_stringify_t *stringify);
 
-static njs_int_t njs_json_append_value(njs_json_stringify_t *stringify,
-    const njs_value_t *value);
-static njs_int_t njs_json_append_string(njs_json_stringify_t *stringify,
-    const njs_value_t *value, char quote);
-static njs_int_t njs_json_append_number(njs_json_stringify_t *stringify,
-    const njs_value_t *value);
+static void njs_json_append_value(njs_chb_t *chain, const njs_value_t *value);
+static void njs_json_append_string(njs_chb_t *chain, const njs_value_t *value,
+    char quote);
+static void njs_json_append_number(njs_chb_t *chain, const njs_value_t *value);
 
 static njs_object_t *njs_json_wrap_value(njs_vm_t *vm, njs_value_t *wrapper,
     const njs_value_t *value);
 
 
-#define NJS_JSON_BUF_MIN_SIZE       128
-
-#define njs_json_buf_written(stringify, bytes)                              \
-    (stringify)->last->pos += (bytes);
-
-#define njs_json_buf_node_size(n) (size_t) ((n)->pos - (n)->start)
-#define njs_json_buf_node_room(n) (size_t) ((n)->end - (n)->pos)
-
-static njs_int_t njs_json_buf_append(njs_json_stringify_t *stringify,
-    const char *msg, size_t len);
-static u_char *njs_json_buf_reserve(njs_json_stringify_t *stringify,
-    size_t size);
-static njs_int_t njs_json_buf_pullup(njs_json_stringify_t *stringify,
-    njs_str_t *str);
-
-
 static const njs_object_prop_t  njs_json_object_properties[];
 
 
@@ -224,10 +193,7 @@ njs_json_stringify(njs_vm_t *vm, njs_val
     stringify = &json_stringify;
 
     stringify->vm = vm;
-    stringify->pool = vm->mem_pool;
     stringify->depth = 0;
-    stringify->nodes = NULL;
-    stringify->last = NULL;
     stringify->keys_type = NJS_ENUM_STRING;
 
     replacer = njs_arg(args, nargs, 2);
@@ -1129,43 +1095,24 @@ njs_json_pop_stringify_state(njs_json_st
      || ((value)->type >= NJS_REGEXP))
 
 
-#define njs_json_stringify_append(str, len)                                   \
-    ret = njs_json_buf_append(stringify, (char *) str, len);                  \
-    if (ret != NJS_OK) {                                                      \
-        goto memory_error;                                                    \
-    }
-
-
 #define njs_json_stringify_indent(times)                                      \
     if (stringify->space.length != 0) {                                       \
-        njs_json_stringify_append("\n", 1);                                   \
+        njs_chb_append(&chain,"\n", 1);                                       \
         for (i = 0; i < (njs_int_t) (times) - 1; i++) {                       \
-            njs_json_stringify_append(stringify->space.start,                 \
-                                      stringify->space.length);               \
+            njs_chb_append_str(&chain, &stringify->space);                    \
         }                                                                     \
     }
 
-#define njs_json_stringify_append_value(value)                                \
-    ret = njs_json_append_value(stringify, value);                            \
-    if (njs_slow_path(ret != NJS_OK)) {                                       \
-        if (ret == NJS_DECLINED) {                                            \
-            return NJS_ERROR;                                                 \
-        }                                                                     \
-                                                                              \
-        goto memory_error;                                                    \
-    }
-
-
 static njs_int_t
 njs_json_stringify_iterator(njs_vm_t *vm, njs_json_stringify_t *stringify,
     njs_value_t *object)
 {
-    u_char            *start;
+    u_char            *p;
     size_t            size;
+    njs_chb_t         chain;
     ssize_t           length;
     njs_int_t         i;
     njs_int_t         ret;
-    njs_str_t         str;
     njs_value_t       *key, *value, wrapper;
     njs_object_t      *obj;
     njs_json_state_t  *state;
@@ -1180,17 +1127,19 @@ njs_json_stringify_iterator(njs_vm_t *vm
         goto memory_error;
     }
 
+    njs_chb_init(&chain, vm->mem_pool);
+
     for ( ;; ) {
         switch (state->type) {
         case NJS_JSON_OBJECT:
             if (state->index == 0) {
-                njs_json_stringify_append("{", 1);
+                njs_chb_append_literal(&chain,"{");
                 njs_json_stringify_indent(stringify->depth);
             }
 
             if (state->index >= state->keys->length) {
                 njs_json_stringify_indent(stringify->depth - 1);
-                njs_json_stringify_append("}", 1);
+                njs_chb_append_literal(&chain,"}");
 
                 state = njs_json_pop_stringify_state(stringify);
                 if (state == NULL) {
@@ -1226,15 +1175,15 @@ njs_json_stringify_iterator(njs_vm_t *vm
             }
 
             if (state->written) {
-                njs_json_stringify_append(",", 1);
+                njs_chb_append_literal(&chain,",");
                 njs_json_stringify_indent(stringify->depth);
             }
 
             state->written = 1;
-            njs_json_append_string(stringify, key, '\"');
-            njs_json_stringify_append(":", 1);
+            njs_json_append_string(&chain, key, '\"');
+            njs_chb_append_literal(&chain,":");
             if (stringify->space.length != 0) {
-                njs_json_stringify_append(" ", 1);
+                njs_chb_append_literal(&chain," ");
             }
 
             if (njs_json_is_object(value)) {
@@ -1246,19 +1195,19 @@ njs_json_stringify_iterator(njs_vm_t *vm
                 break;
             }
 
-            njs_json_stringify_append_value(value);
+            njs_json_append_value(&chain, value);
 
             break;
 
         case NJS_JSON_ARRAY:
             if (state->index == 0) {
-                njs_json_stringify_append("[", 1);
+                njs_chb_append_literal(&chain,"[");
                 njs_json_stringify_indent(stringify->depth);
             }
 
             if (state->index >= njs_array_len(&state->value)) {
                 njs_json_stringify_indent(stringify->depth - 1);
-                njs_json_stringify_append("]", 1);
+                njs_chb_append_literal(&chain,"]");
 
                 state = njs_json_pop_stringify_state(stringify);
                 if (state == NULL) {
@@ -1269,7 +1218,7 @@ njs_json_stringify_iterator(njs_vm_t *vm
             }
 
             if (state->written) {
-                njs_json_stringify_append(",", 1);
+                njs_chb_append_literal(&chain,",");
                 njs_json_stringify_indent(stringify->depth);
             }
 
@@ -1296,7 +1245,7 @@ njs_json_stringify_iterator(njs_vm_t *vm
             }
 
             state->written = 1;
-            njs_json_stringify_append_value(value);
+            njs_json_append_value(&chain, value);
 
             break;
         }
@@ -1304,43 +1253,40 @@ njs_json_stringify_iterator(njs_vm_t *vm
 
 done:
 
-    ret = njs_json_buf_pullup(stringify, &str);
-    if (njs_slow_path(ret != NJS_OK)) {
-        goto memory_error;
-    }
-
     /*
      * The value to stringify is wrapped as '{"": value}'.
-     * An empty object means empty result.
+     * Stripping the wrapper's data.
      */
-    if (str.length <= njs_length("{\n\n}")) {
+
+    njs_chb_drain(&chain, njs_length("{\"\":"));
+    njs_chb_drop(&chain, njs_length("}"));
+
+    if (stringify->space.length != 0) {
+        njs_chb_drain(&chain, njs_length("\n "));
+        njs_chb_drop(&chain, njs_length("\n"));
+    }
+
+    size = njs_chb_size(&chain);
+    if (njs_slow_path(size == 0)) {
         njs_set_undefined(&vm->retval);
         goto release;
     }
 
-    /* Stripping the wrapper's data. */
-
-    start = str.start + njs_length("{\"\":");
-    size = str.length - njs_length("{\"\":}");
-
-    if (stringify->space.length != 0) {
-        start += njs_length("\n ");
-        size -= njs_length("\n \n");
-    }
-
-    length = njs_utf8_length(start, size);
+    length = njs_chb_utf8_length(&chain);
     if (njs_slow_path(length < 0)) {
         length = 0;
     }
 
-    ret = njs_string_new(vm, &vm->retval, start, size, length);
-    if (njs_slow_path(ret != NJS_OK)) {
+    p = njs_string_alloc(vm, &vm->retval, size, length);
+    if (njs_slow_path(p == NULL)) {
         goto memory_error;
     }
 
+    njs_chb_join_to(&chain, p);
+
 release:
 
-    njs_mp_free(vm->mem_pool, str.start);
+    njs_chb_destroy(&chain);
 
     return NJS_OK;
 
@@ -1521,8 +1467,8 @@ njs_json_stringify_array(njs_vm_t *vm, n
 }
 
 
-static njs_int_t
-njs_json_append_value(njs_json_stringify_t *stringify, const njs_value_t *value)
+static void
+njs_json_append_value(njs_chb_t *chain, const njs_value_t *value)
 {
     switch (value->type) {
     case NJS_OBJECT_STRING:
@@ -1530,14 +1476,16 @@ njs_json_append_value(njs_json_stringify
         /* Fall through. */
 
     case NJS_STRING:
-        return njs_json_append_string(stringify, value, '\"');
+        njs_json_append_string(chain, value, '\"');
+        break;
 
     case NJS_OBJECT_NUMBER:
         value = njs_object_value(value);
         /* Fall through. */
 
     case NJS_NUMBER:
-        return njs_json_append_number(stringify, value);
+        njs_json_append_number(chain, value);
+        break;
 
     case NJS_OBJECT_BOOLEAN:
         value = njs_object_value(value);
@@ -1545,26 +1493,27 @@ njs_json_append_value(njs_json_stringify
 
     case NJS_BOOLEAN:
         if (njs_is_true(value)) {
-            return njs_json_buf_append(stringify, "true", 4);
+            njs_chb_append_literal(chain, "true");
 
         } else {
-            return njs_json_buf_append(stringify, "false", 5);
+            njs_chb_append_literal(chain, "false");
         }
 
+        break;
+
     case NJS_UNDEFINED:
     case NJS_NULL:
     case NJS_SYMBOL:
     case NJS_INVALID:
     case NJS_FUNCTION:
     default:
-        return njs_json_buf_append(stringify, "null", 4);
+        njs_chb_append_literal(chain, "null");
     }
 }
 
 
-static njs_int_t
-njs_json_append_string(njs_json_stringify_t *stringify,
-    const njs_value_t *value, char quote)
+static void
+njs_json_append_string(njs_chb_t *chain, const njs_value_t *value, char quote)
 {
     u_char             c, *dst, *dst_end;
     size_t             length;
@@ -1580,12 +1529,12 @@ njs_json_append_string(njs_json_stringif
     end = p + str.size;
     length = str.length;
 
-    dst = njs_json_buf_reserve(stringify, 64);
+    dst = njs_chb_reserve(chain, length + 2);
     if (njs_slow_path(dst == NULL)) {
-        return NJS_ERROR;
+        return;
     }
 
-    dst_end = dst + 64;
+    dst_end = dst + length + 2;
 
     *dst++ = quote;
 
@@ -1651,26 +1600,25 @@ njs_json_append_string(njs_json_stringif
         }
 
         if (dst_end - dst <= 6) {
-            njs_json_buf_written(stringify, dst - stringify->last->pos);
-
-            dst = njs_json_buf_reserve(stringify, 64);
+            njs_chb_written(chain, dst - chain->last->pos);
+
+            dst = njs_chb_reserve(chain, 64);
             if (njs_slow_path(dst == NULL)) {
-                return NJS_ERROR;
+                return;
             }
 
             dst_end = dst + 64;
         }
     }
 
-    njs_json_buf_written(stringify, dst - stringify->last->pos);
-
-    return njs_json_buf_append(stringify, &quote, 1);
+    njs_chb_written(chain, dst - chain->last->pos);
+
+    njs_chb_append(chain, &quote, 1);
 }
 
 
-static njs_int_t
-njs_json_append_number(njs_json_stringify_t *stringify,
-    const njs_value_t *value)
+static void
+njs_json_append_number(njs_chb_t *chain, const njs_value_t *value)
 {
     u_char  *p;
     size_t  size;
@@ -1679,20 +1627,18 @@ njs_json_append_number(njs_json_stringif
     num = njs_number(value);
 
     if (isnan(num) || isinf(num)) {
-        return njs_json_buf_append(stringify, "null", 4);
+        njs_chb_append_literal(chain, "null");
 
     } else {
-        p = njs_json_buf_reserve(stringify, 64);
+        p = njs_chb_reserve(chain, 64);
         if (njs_slow_path(p == NULL)) {
-            return NJS_ERROR;
+            return;
         }
 
         size = njs_dtoa(num, (char *) p);
 
-        njs_json_buf_written(stringify, size);
+        njs_chb_written(chain, size);
     }
-
-    return NJS_OK;
 }
 
 
@@ -1737,117 +1683,6 @@ njs_json_wrap_value(njs_vm_t *vm, njs_va
 }
 
 
-static njs_int_t
-njs_json_buf_append(njs_json_stringify_t *stringify, const char *msg,
-    size_t len)
-{
-    u_char  *p;
-
-    if (len != 0) {
-        p = njs_json_buf_reserve(stringify, len);
-        if (njs_slow_path(p == NULL)) {
-            return NJS_ERROR;
-        }
-
-        memcpy(p, msg, len);
-
-        njs_json_buf_written(stringify, len);
-    }
-
-    return NJS_OK;
-}
-
-
-static u_char *
-njs_json_buf_reserve(njs_json_stringify_t *stringify, size_t size)
-{
-    njs_chb_node_t  *n;
-
-    if (njs_slow_path(size == 0)) {
-        return NULL;
-    }
-
-    n = stringify->last;
-
-    if (njs_fast_path(n != NULL && njs_json_buf_node_room(n) >= size)) {
-        return n->pos;
-    }
-
-    if (size < NJS_JSON_BUF_MIN_SIZE) {
-        size = NJS_JSON_BUF_MIN_SIZE;
-    }
-
-    n = njs_mp_alloc(stringify->pool, sizeof(njs_chb_node_t) + size);
-    if (njs_slow_path(n == NULL)) {
-        return NULL;
-    }
-
-    n->next = NULL;
-    n->start = (u_char *) n + sizeof(njs_chb_node_t);
-    n->pos = n->start;
-    n->end = n->pos + size;
-
-    if (stringify->last != NULL) {
-        stringify->last->next = n;
-
-    } else {
-        stringify->nodes = n;
-    }
-
-    stringify->last = n;
-
-    return n->start;
-}
-
-
-static njs_int_t
-njs_json_buf_pullup(njs_json_stringify_t *stringify, njs_str_t *str)
-{
-    u_char          *start;
-    size_t          size;
-    njs_chb_node_t  *n;
-
-    n = stringify->nodes;
-
-    if (n == NULL) {
-        str->length = 0;
-        str->start = NULL;
-        return NJS_OK;
-    }
-
-    if (n->next == NULL) {
-        str->length = njs_json_buf_node_size(n);
-        str->start = n->start;
-        return NJS_OK;
-    }
-
-    size = 0;
-
-    while (n != NULL) {
-        size += njs_json_buf_node_size(n);
-        n = n->next;
-    }
-
-    start = njs_mp_alloc(stringify->pool, size);
-    if (njs_slow_path(start == NULL)) {
-        return NJS_ERROR;
-    }
-
-    n = stringify->nodes;
-    str->length = size;
-    str->start = start;
-
-    while (n != NULL) {
-        size = njs_json_buf_node_size(n);
-        memcpy(start, n->start, size);
-        start += size;
-        n = n->next;
-    }
-
-    return NJS_OK;
-}
-
-
 static const njs_object_prop_t  njs_json_object_properties[] =
 {
     {
@@ -1881,22 +1716,13 @@ const njs_object_init_t  njs_json_object
 };
 
 
-#define njs_dump(str)                                                         \
-    ret = njs_json_buf_append(stringify, str, njs_length(str));               \
-    if (njs_slow_path(ret != NJS_OK)) {                                       \
-        goto memory_error;                                                    \
-    }
-
-
 static njs_int_t
-njs_dump_value(njs_json_stringify_t *stringify, const njs_value_t *value,
-    njs_uint_t console)
+njs_dump_value(njs_json_stringify_t *stringify, njs_chb_t *chain,
+    const njs_value_t *value, njs_uint_t console)
 {
-    u_char       *p;
+    njs_str_t    str;
     njs_int_t    ret;
-    njs_str_t    str;
     njs_value_t  str_val;
-    u_char       buf[32];
 
     njs_int_t   (*to_string)(njs_vm_t *, njs_value_t *, const njs_value_t *);
 
@@ -1904,26 +1730,20 @@ njs_dump_value(njs_json_stringify_t *str
     case NJS_OBJECT_STRING:
         value = njs_object_value(value);
 
-        njs_string_get(value, &str);
-
-        njs_dump("[String: ");
-
-        ret = njs_json_append_string(stringify, value, '\'');
-        if (njs_slow_path(ret != NJS_OK)) {
-            goto memory_error;
-        }
-
-        njs_dump("]");
+        njs_chb_append_literal(chain, "[String: ");
+        njs_json_append_string(chain, value, '\'');
+        njs_chb_append_literal(chain, "]");
         break;
 
     case NJS_STRING:
         njs_string_get(value, &str);
 
         if (!console || stringify->depth != 0) {
-            return njs_json_append_string(stringify, value, '\'');
+            njs_json_append_string(chain, value, '\'');
+            return NJS_OK;
         }
 
-        return njs_json_buf_append(stringify, (char *) str.start, str.length);
+        njs_chb_append_str(chain, &str);
 
         break;
 
@@ -1936,15 +1756,7 @@ njs_dump_value(njs_json_stringify_t *str
         }
 
         njs_string_get(&str_val, &str);
-
-        njs_dump("[Symbol: ");
-
-        ret = njs_json_buf_append(stringify, (char *) str.start, str.length);
-        if (njs_slow_path(ret != NJS_OK)) {
-            goto memory_error;
-        }
-
-        njs_dump("]");
+        njs_chb_sprintf(chain, 16 + str.length, "[Symbol: %V]", &str);
 
         break;
 
@@ -1955,11 +1767,7 @@ njs_dump_value(njs_json_stringify_t *str
         }
 
         njs_string_get(&str_val, &str);
-
-        ret = njs_json_buf_append(stringify, (char *) str.start, str.length);
-        if (njs_slow_path(ret != NJS_OK)) {
-            goto memory_error;
-        }
+        njs_chb_append_str(chain, &str);
 
         break;
 
@@ -1970,7 +1778,7 @@ njs_dump_value(njs_json_stringify_t *str
                           && signbit(njs_number(value))))
         {
 
-            njs_dump("[Number: -0]");
+            njs_chb_append_literal(chain, "[Number: -0]");
             break;
         }


More information about the nginx-devel mailing list