This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/qpid-proton.git
commit 48dc5688d5aa51d668434237c665685884f83ae5 Author: Andrew Stitcher <[email protected]> AuthorDate: Mon Jul 20 13:47:49 2026 -0400 PROTON-2954: Slim down pn_data_t memory use Reduce the per node memory cost from 72 bytes to 24 bytes (⅓ what it was) so that even complex AMQP values representions use much less memory. --- c/src/core/codec.c | 402 +++++++++++++++++++++++++-------------------------- c/src/core/data.h | 95 ++++++++++-- c/src/core/encoder.c | 146 +++++++++---------- 3 files changed, 353 insertions(+), 290 deletions(-) diff --git a/c/src/core/codec.c b/c/src/core/codec.c index 08ede0c6a..3745ab71b 100644 --- a/c/src/core/codec.c +++ b/c/src/core/codec.c @@ -75,12 +75,6 @@ const char *pn_type_name(pn_type_t type) return "<UNKNOWN>"; } -static inline void pni_atom_init(pn_atom_t *atom, pn_type_t type) -{ - memset(atom, 0, sizeof(pn_atom_t)); - atom->type = type; -} - // data static void pn_data_finalize(void *object) @@ -94,16 +88,16 @@ static void pn_data_finalize(void *object) static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node) { if (!node) return NULL; - if (node->atom.type != PN_DESCRIBED) return NULL; + if (node->type != PN_DESCRIBED) return NULL; pni_node_t *descriptor = pn_data_node(data, node->down); - if (!descriptor || descriptor->atom.type != PN_ULONG) { + if (!descriptor || descriptor->type != PN_ULONG) { return NULL; } - if (descriptor->atom.u.as_ulong >= FIELD_MIN && descriptor->atom.u.as_ulong <= FIELD_MAX) { - const pn_fields_t *f = &FIELDS[descriptor->atom.u.as_ulong-FIELD_MIN]; + if (descriptor->u.as_ulong >= FIELD_MIN && descriptor->u.as_ulong <= FIELD_MAX) { + const pn_fields_t *f = &FIELDS[descriptor->u.as_ulong-FIELD_MIN]; return (f->name_index!=0) ? f : NULL; } else { return NULL; @@ -272,7 +266,6 @@ static int pni_node_lindex(pn_data_t *data, pni_node_t *node) int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node) { pn_fixed_string_t *str = (pn_fixed_string_t *) ctx; - pn_atom_t *atom = (pn_atom_t *) &node->atom; pni_node_t *parent = pn_data_node(data, node->parent); const pn_fields_t *fields = pni_node_fields(data, parent); @@ -280,7 +273,7 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node) const pn_fields_t *grandfields = pni_node_fields(data, grandparent); if (grandfields) { - if (atom->type == PN_NULL) { + if (node->type == PN_NULL) { return 0; } pni_nid_t lindex = pni_node_lindex(data, node); @@ -292,13 +285,13 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node) } } - switch (atom->type) { + switch (node->type) { case PN_DESCRIBED: pn_fixed_string_addf(str, "@"); return 0; case PN_ARRAY: // XXX: need to fix for described arrays - pn_fixed_string_addf(str, "@%s[", pn_type_name(node->type)); + pn_fixed_string_addf(str, "@%s[", pn_type_name(node->u.as_array.type)); return 0; case PN_LIST: pn_fixed_string_addf(str, "["); @@ -306,25 +299,42 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node) case PN_MAP: pn_fixed_string_addf(str, "{"); return 0; - default: + default: { + pn_rwbytes_t buf = (data->buf) ? pn_buffer_memory(data->buf) : (pn_rwbytes_t){0}; + pn_atom_t tmp = {node->type}; + switch (node->type) { + case PN_BINARY: case PN_STRING: case PN_SYMBOL: + tmp.u.as_bytes = (pn_bytes_t){ node->u.as_bytes.size, buf.start + node->u.as_bytes.offset }; + break; + case PN_DECIMAL128: + memcpy(tmp.u.as_decimal128.bytes, buf.start + node->u.as_bytes.offset, 16); + break; + case PN_UUID: + memcpy(tmp.u.as_uuid.bytes, buf.start + node->u.as_bytes.offset, 16); + break; + default: + memcpy(&tmp.u, &node->u, sizeof(node->u)); + break; + } if (fields && node->prev == 0) { pn_fixed_string_addf(str, "%s", (const char *)FIELD_STRINGPOOL.STRING0+FIELD_NAME[fields->name_index]); pn_fixed_string_addf(str, "("); - pni_inspect_atom(atom, str); + pni_inspect_atom(&tmp, str); pn_fixed_string_addf(str, ")"); return 0; } else { - pni_inspect_atom(atom, str); + pni_inspect_atom(&tmp, str); return 0; } } + } } pni_node_t *pni_next_nonnull(pn_data_t *data, pni_node_t *node) { while (node) { node = pn_data_node(data, node->next); - if (node && node->atom.type != PN_NULL) { + if (node && node->type != PN_NULL) { return node; } } @@ -336,7 +346,7 @@ int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node) { pn_fixed_string_t *str = (pn_fixed_string_t *) ctx; - switch (node->atom.type) { + switch (node->type) { case PN_ARRAY: case PN_LIST: pn_fixed_string_addf(str, "]"); @@ -351,11 +361,11 @@ int pni_inspect_exit(void *ctx, pn_data_t *data, pni_node_t *node) pni_node_t *parent = pn_data_node(data, node->parent); pni_node_t *grandparent = parent ? pn_data_node(data, parent->parent) : NULL; const pn_fields_t *grandfields = pni_node_fields(data, grandparent); - if (!grandfields || node->atom.type != PN_NULL) { + if (!grandfields || node->type != PN_NULL) { if (node->next) { - if (parent && parent->atom.type == PN_MAP && (pni_node_lindex(data, node) % 2) == 0) { + if (parent && parent->type == PN_MAP && (pni_node_lindex(data, node) % 2) == 0) { pn_fixed_string_addf(str, "="); - } else if (parent && parent->atom.type == PN_DESCRIBED && node->prev == 0) { + } else if (parent && parent->type == PN_DESCRIBED && node->prev == 0) { pn_fixed_string_addf(str, " "); } else { if (!grandfields || pni_next_nonnull(data, node)) { @@ -497,54 +507,19 @@ static ssize_t pni_data_intern(pn_data_t *data, const char *start, size_t size) return offset; } -static pn_bytes_t *pni_data_bytes(pn_data_t *data, pni_node_t *node) -{ - switch (node->atom.type) { - case PN_BINARY: - case PN_STRING: - case PN_SYMBOL: - return &node->atom.u.as_bytes; - default: return NULL; - } -} - -static void pni_data_rebase(pn_data_t *data, char *base) +static int pni_data_intern_node(pn_data_t *data, pni_node_t *node, pn_bytes_t bytes) { - for (unsigned i = 0; i < data->size; i++) { - pni_node_t *node = &data->nodes[i]; - if (node->data) { - pn_bytes_t *bytes = pni_data_bytes(data, node); - bytes->start = base + node->data_offset; - } - } -} - -static int pni_data_intern_node(pn_data_t *data, pni_node_t *node) -{ - pn_bytes_t *bytes = pni_data_bytes(data, node); - if (!bytes) return 0; if (data->buf == NULL) { - // Heuristic to avoid growing small buffers too much - // size + 1 to allow for zero termination - size_t size = pn_max(bytes->size+1, PNI_INTERN_MINSIZE); + size_t size = pn_max(bytes.size+1, PNI_INTERN_MINSIZE); data->buf = pn_buffer(size); } - size_t oldcap = pn_buffer_capacity(data->buf); - ssize_t offset = pni_data_intern(data, bytes->start, bytes->size); + ssize_t offset = pni_data_intern(data, bytes.start, bytes.size); if (offset < 0) { pn_error_set(pni_data_error(data), PN_OUT_OF_MEMORY, "pn_data string buffer limit exceeded"); return offset; } - node->data = true; - node->data_offset = offset; - node->data_size = bytes->size; - pn_rwbytes_t buf = pn_buffer_memory(data->buf); - bytes->start = buf.start + offset; - - if (pn_buffer_capacity(data->buf) != oldcap) { - pni_data_rebase(data, buf.start); - } - + node->u.as_bytes.offset = (uint32_t) offset; + node->u.as_bytes.size = (uint32_t) bytes.size; return 0; } @@ -720,8 +695,8 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap) case 'T': /* Set type of open array */ { pni_node_t *parent = pn_data_node(data, data->parent); - if (parent->atom.type == PN_ARRAY) { - parent->type = (pn_type_t) va_arg(ap, int); + if (parent->type == PN_ARRAY) { + parent->u.as_array.type = (uint8_t) va_arg(ap, int); } else { return pn_error_format(pni_data_error(data), PN_ERR, "naked type"); } @@ -831,12 +806,12 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap) pni_node_t *parent = pn_data_node(data, data->parent); pni_node_t *current = pn_data_node(data, data->current); while (parent) { - if (parent->atom.type == PN_DESCRIBED && parent->children == 2) { - current->described = true; + if (parent->type == PN_DESCRIBED && parent->children == 2) { + current->u.as_list.described = true; pn_data_exit(data); current = pn_data_node(data, data->current); parent = pn_data_node(data, data->parent); - } else if (parent->atom.type == PN_NULL && parent->children == 1) { + } else if (parent->type == PN_NULL && parent->children == 1) { pn_data_exit(data); current = pn_data_node(data, data->current); current->down = 0; @@ -870,7 +845,7 @@ static bool pn_scan_next(pn_data_t *data, pn_type_t *type, bool suspend) return true; } else { pni_node_t *parent = pn_data_node(data, data->parent); - if (parent && parent->atom.type == PN_DESCRIBED) { + if (parent && parent->type == PN_DESCRIBED) { pn_data_exit(data); return pn_scan_next(data, type, suspend); } else { @@ -1222,7 +1197,7 @@ int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap) if (!suspend) { size_t old = pn_data_size(dst); pni_node_t *next = pni_data_peek(data); - if (next && next->atom.type != PN_NULL) { + if (next && next->type != PN_NULL) { pn_data_narrow(data); int err = pn_data_appendn(dst, data, 1); pn_data_widen(data); @@ -1243,8 +1218,8 @@ int pn_data_vscan(pn_data_t *data, const char *fmt, va_list ap) pn_atom_t *dst = va_arg(ap, pn_atom_t *); if (!suspend) { pni_node_t *next = pni_data_peek(data); - if (next && next->atom.type != PN_NULL) { - *dst = next->atom; + if (next && next->type != PN_NULL) { + *dst = pn_data_get_atom(data); } else { scanned = false; } @@ -1462,7 +1437,7 @@ pn_type_t pn_data_type(pn_data_t *data) { pni_node_t *node = pni_data_current(data); if (node) { - return node->atom.type; + return node->type; } else { return PN_INVALID; } @@ -1472,7 +1447,7 @@ pn_type_t pni_data_parent_type(pn_data_t *data) { pni_node_t *node = pn_data_node(data, data->parent); if (node) { - return node->atom.type; + return node->type; } else { return PN_INVALID; } @@ -1545,7 +1520,12 @@ void pn_data_dump(pn_data_t *data) { pni_node_t *node = &data->nodes[i]; pn_fixed_string_t str = pn_fixed_string(buf, sizeof(buf)); - pni_inspect_atom((pn_atom_t *) &node->atom, &str); + /* synthesise a tmp atom for debug display */ + pn_handle_t saved = pn_data_point(data); + data->current = pni_data_id(data, node); + pn_atom_t tmp = pn_data_get_atom(data); + pn_data_restore(data, saved); + pni_inspect_atom(&tmp, &str); pn_fixed_string_terminate(&str); printf("Node %u: prev=%" PN_ZU ", next=%" PN_ZU ", parent=%" PN_ZU ", down=%" PN_ZU ", children=%" PN_ZU ", type=%s (%s)\n", @@ -1554,7 +1534,7 @@ void pn_data_dump(pn_data_t *data) (size_t) node->parent, (size_t) node->down, (size_t) node->children, - pn_type_name(node->atom.type), buf); + pn_type_name(node->type), buf); } } @@ -1610,10 +1590,7 @@ static pni_node_t *pni_data_add(pn_data_t *data) node->down = 0; node->children = 0; - node->data = false; - node->described = false; - node->data_offset = 0; - node->data_size = 0; + memset(&node->u, 0, sizeof(node->u)); data->current = pni_data_id(data, node); return node; } @@ -1649,7 +1626,8 @@ int pn_data_put_list(pn_data_t *data) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_LIST; + node->type = PN_LIST; + node->u.as_list.described = false; return 0; } @@ -1657,7 +1635,7 @@ int pn_data_put_map(pn_data_t *data) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_MAP; + node->type = PN_MAP; return 0; } @@ -1665,23 +1643,23 @@ int pn_data_put_array(pn_data_t *data, bool described, pn_type_t type) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_ARRAY; - node->described = described; - node->type = type; + node->type = PN_ARRAY; + node->u.as_array.described = described; + node->u.as_array.type = (uint8_t) type; return 0; } void pni_data_set_array_type(pn_data_t *data, pn_type_t type) { pni_node_t *array = pni_data_current(data); - if (array) array->type = type; + if (array) array->u.as_array.type = (uint8_t) type; } int pn_data_put_described(pn_data_t *data) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_DESCRIBED; + node->type = PN_DESCRIBED; return 0; } @@ -1689,7 +1667,7 @@ int pn_data_put_null(pn_data_t *data) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - pni_atom_init(&node->atom, PN_NULL); + node->type = PN_NULL; return 0; } @@ -1697,8 +1675,8 @@ int pn_data_put_bool(pn_data_t *data, bool b) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_BOOL; - node->atom.u.as_bool = b; + node->type = PN_BOOL; + node->u.as_bool = b; return 0; } @@ -1706,8 +1684,8 @@ int pn_data_put_ubyte(pn_data_t *data, uint8_t ub) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_UBYTE; - node->atom.u.as_ubyte = ub; + node->type = PN_UBYTE; + node->u.as_ubyte = ub; return 0; } @@ -1715,8 +1693,8 @@ int pn_data_put_byte(pn_data_t *data, int8_t b) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_BYTE; - node->atom.u.as_byte = b; + node->type = PN_BYTE; + node->u.as_byte = b; return 0; } @@ -1724,8 +1702,8 @@ int pn_data_put_ushort(pn_data_t *data, uint16_t us) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_USHORT; - node->atom.u.as_ushort = us; + node->type = PN_USHORT; + node->u.as_ushort = us; return 0; } @@ -1733,8 +1711,8 @@ int pn_data_put_short(pn_data_t *data, int16_t s) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_SHORT; - node->atom.u.as_short = s; + node->type = PN_SHORT; + node->u.as_short = s; return 0; } @@ -1742,8 +1720,8 @@ int pn_data_put_uint(pn_data_t *data, uint32_t ui) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_UINT; - node->atom.u.as_uint = ui; + node->type = PN_UINT; + node->u.as_uint = ui; return 0; } @@ -1751,8 +1729,8 @@ int pn_data_put_int(pn_data_t *data, int32_t i) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_INT; - node->atom.u.as_int = i; + node->type = PN_INT; + node->u.as_int = i; return 0; } @@ -1760,8 +1738,8 @@ int pn_data_put_char(pn_data_t *data, pn_char_t c) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_CHAR; - node->atom.u.as_char = c; + node->type = PN_CHAR; + node->u.as_char = c; return 0; } @@ -1769,8 +1747,8 @@ int pn_data_put_ulong(pn_data_t *data, uint64_t ul) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_ULONG; - node->atom.u.as_ulong = ul; + node->type = PN_ULONG; + node->u.as_ulong = ul; return 0; } @@ -1778,8 +1756,8 @@ int pn_data_put_long(pn_data_t *data, int64_t l) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_LONG; - node->atom.u.as_long = l; + node->type = PN_LONG; + node->u.as_long = l; return 0; } @@ -1787,8 +1765,8 @@ int pn_data_put_timestamp(pn_data_t *data, pn_timestamp_t t) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_TIMESTAMP; - node->atom.u.as_timestamp = t; + node->type = PN_TIMESTAMP; + node->u.as_timestamp = t; return 0; } @@ -1796,8 +1774,8 @@ int pn_data_put_float(pn_data_t *data, float f) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_FLOAT; - node->atom.u.as_float = f; + node->type = PN_FLOAT; + node->u.as_float = f; return 0; } @@ -1805,8 +1783,8 @@ int pn_data_put_double(pn_data_t *data, double d) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_DOUBLE; - node->atom.u.as_double = d; + node->type = PN_DOUBLE; + node->u.as_double = d; return 0; } @@ -1814,8 +1792,8 @@ int pn_data_put_decimal32(pn_data_t *data, pn_decimal32_t d) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_DECIMAL32; - node->atom.u.as_decimal32 = d; + node->type = PN_DECIMAL32; + node->u.as_decimal32 = d; return 0; } @@ -1823,8 +1801,8 @@ int pn_data_put_decimal64(pn_data_t *data, pn_decimal64_t d) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_DECIMAL64; - node->atom.u.as_decimal64 = d; + node->type = PN_DECIMAL64; + node->u.as_decimal64 = d; return 0; } @@ -1832,59 +1810,70 @@ int pn_data_put_decimal128(pn_data_t *data, pn_decimal128_t d) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_DECIMAL128; - memmove(node->atom.u.as_decimal128.bytes, d.bytes, 16); - return 0; + node->type = PN_DECIMAL128; + return pni_data_intern_node(data, node, (pn_bytes_t){16, (const char*)d.bytes}); } int pn_data_put_uuid(pn_data_t *data, pn_uuid_t u) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_UUID; - memmove(node->atom.u.as_uuid.bytes, u.bytes, 16); - return 0; + node->type = PN_UUID; + return pni_data_intern_node(data, node, (pn_bytes_t){16, (const char*)u.bytes}); } int pn_data_put_binary(pn_data_t *data, pn_bytes_t bytes) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_BINARY; - node->atom.u.as_bytes = bytes; - return pni_data_intern_node(data, node); + node->type = PN_BINARY; + return pni_data_intern_node(data, node, bytes); } int pn_data_put_string(pn_data_t *data, pn_bytes_t string) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_STRING; - node->atom.u.as_bytes = string; - return pni_data_intern_node(data, node); + node->type = PN_STRING; + return pni_data_intern_node(data, node, string); } int pn_data_put_symbol(pn_data_t *data, pn_bytes_t symbol) { pni_node_t *node = pni_data_add(data); if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom.type = PN_SYMBOL; - node->atom.u.as_bytes = symbol; - return pni_data_intern_node(data, node); + node->type = PN_SYMBOL; + return pni_data_intern_node(data, node, symbol); } int pn_data_put_atom(pn_data_t *data, pn_atom_t atom) { - pni_node_t *node = pni_data_add(data); - if (node == NULL) return PN_OUT_OF_MEMORY; - node->atom = atom; - return pni_data_intern_node(data, node); + switch (atom.type) { + case PN_BINARY: return pn_data_put_binary(data, atom.u.as_bytes); + case PN_STRING: return pn_data_put_string(data, atom.u.as_bytes); + case PN_SYMBOL: return pn_data_put_symbol(data, atom.u.as_bytes); + case PN_DECIMAL128: return pn_data_put_decimal128(data, atom.u.as_decimal128); + case PN_UUID: return pn_data_put_uuid(data, atom.u.as_uuid); + default: { + pni_node_t *node = pni_data_add(data); + if (node == NULL) return PN_OUT_OF_MEMORY; + node->type = atom.type; + memcpy(&node->u, &atom.u, sizeof(node->u)); + return 0; + } + } +} + +static inline pn_bytes_t pni_node_bytes(pn_data_t *data, pni_node_t *node) +{ + pn_rwbytes_t buf = pn_buffer_memory(data->buf); + return (pn_bytes_t){ node->u.as_bytes.size, buf.start + node->u.as_bytes.offset }; } size_t pn_data_get_list(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_LIST) { + if (node && node->type == PN_LIST) { return node->children; } else { return 0; @@ -1894,7 +1883,7 @@ size_t pn_data_get_list(pn_data_t *data) size_t pn_data_get_map(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_MAP) { + if (node && node->type == PN_MAP) { return node->children; } else { return 0; @@ -1904,8 +1893,8 @@ size_t pn_data_get_map(pn_data_t *data) size_t pn_data_get_array(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_ARRAY) { - if (node->described) { + if (node && node->type == PN_ARRAY) { + if (node->u.as_array.described) { return node->children - 1; } else { return node->children; @@ -1918,8 +1907,8 @@ size_t pn_data_get_array(pn_data_t *data) bool pn_data_is_array_described(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_ARRAY) { - return node->described; + if (node && node->type == PN_ARRAY) { + return node->u.as_array.described; } else { return false; } @@ -1928,8 +1917,8 @@ bool pn_data_is_array_described(pn_data_t *data) pn_type_t pn_data_get_array_type(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_ARRAY) { - return node->type; + if (node && node->type == PN_ARRAY) { + return node->u.as_array.type; } else { return PN_INVALID; } @@ -1938,20 +1927,20 @@ pn_type_t pn_data_get_array_type(pn_data_t *data) bool pn_data_is_described(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - return node && node->atom.type == PN_DESCRIBED; + return node && node->type == PN_DESCRIBED; } bool pn_data_is_null(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - return node && node->atom.type == PN_NULL; + return node && node->type == PN_NULL; } bool pn_data_get_bool(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_BOOL) { - return node->atom.u.as_bool; + if (node && node->type == PN_BOOL) { + return node->u.as_bool; } else { return false; } @@ -1960,8 +1949,8 @@ bool pn_data_get_bool(pn_data_t *data) uint8_t pn_data_get_ubyte(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_UBYTE) { - return node->atom.u.as_ubyte; + if (node && node->type == PN_UBYTE) { + return node->u.as_ubyte; } else { return 0; } @@ -1970,8 +1959,8 @@ uint8_t pn_data_get_ubyte(pn_data_t *data) int8_t pn_data_get_byte(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_BYTE) { - return node->atom.u.as_byte; + if (node && node->type == PN_BYTE) { + return node->u.as_byte; } else { return 0; } @@ -1980,8 +1969,8 @@ int8_t pn_data_get_byte(pn_data_t *data) uint16_t pn_data_get_ushort(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_USHORT) { - return node->atom.u.as_ushort; + if (node && node->type == PN_USHORT) { + return node->u.as_ushort; } else { return 0; } @@ -1990,8 +1979,8 @@ uint16_t pn_data_get_ushort(pn_data_t *data) int16_t pn_data_get_short(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_SHORT) { - return node->atom.u.as_short; + if (node && node->type == PN_SHORT) { + return node->u.as_short; } else { return 0; } @@ -2000,8 +1989,8 @@ int16_t pn_data_get_short(pn_data_t *data) uint32_t pn_data_get_uint(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_UINT) { - return node->atom.u.as_uint; + if (node && node->type == PN_UINT) { + return node->u.as_uint; } else { return 0; } @@ -2010,8 +1999,8 @@ uint32_t pn_data_get_uint(pn_data_t *data) int32_t pn_data_get_int(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_INT) { - return node->atom.u.as_int; + if (node && node->type == PN_INT) { + return node->u.as_int; } else { return 0; } @@ -2020,8 +2009,8 @@ int32_t pn_data_get_int(pn_data_t *data) pn_char_t pn_data_get_char(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_CHAR) { - return node->atom.u.as_char; + if (node && node->type == PN_CHAR) { + return node->u.as_char; } else { return 0; } @@ -2030,8 +2019,8 @@ pn_char_t pn_data_get_char(pn_data_t *data) uint64_t pn_data_get_ulong(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_ULONG) { - return node->atom.u.as_ulong; + if (node && node->type == PN_ULONG) { + return node->u.as_ulong; } else { return 0; } @@ -2040,8 +2029,8 @@ uint64_t pn_data_get_ulong(pn_data_t *data) int64_t pn_data_get_long(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_LONG) { - return node->atom.u.as_long; + if (node && node->type == PN_LONG) { + return node->u.as_long; } else { return 0; } @@ -2050,8 +2039,8 @@ int64_t pn_data_get_long(pn_data_t *data) pn_timestamp_t pn_data_get_timestamp(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_TIMESTAMP) { - return node->atom.u.as_timestamp; + if (node && node->type == PN_TIMESTAMP) { + return node->u.as_timestamp; } else { return 0; } @@ -2060,8 +2049,8 @@ pn_timestamp_t pn_data_get_timestamp(pn_data_t *data) float pn_data_get_float(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_FLOAT) { - return node->atom.u.as_float; + if (node && node->type == PN_FLOAT) { + return node->u.as_float; } else { return 0; } @@ -2070,8 +2059,8 @@ float pn_data_get_float(pn_data_t *data) double pn_data_get_double(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_DOUBLE) { - return node->atom.u.as_double; + if (node && node->type == PN_DOUBLE) { + return node->u.as_double; } else { return 0; } @@ -2080,8 +2069,8 @@ double pn_data_get_double(pn_data_t *data) pn_decimal32_t pn_data_get_decimal32(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_DECIMAL32) { - return node->atom.u.as_decimal32; + if (node && node->type == PN_DECIMAL32) { + return node->u.as_decimal32; } else { return 0; } @@ -2090,8 +2079,8 @@ pn_decimal32_t pn_data_get_decimal32(pn_data_t *data) pn_decimal64_t pn_data_get_decimal64(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_DECIMAL64) { - return node->atom.u.as_decimal64; + if (node && node->type == PN_DECIMAL64) { + return node->u.as_decimal64; } else { return 0; } @@ -2100,30 +2089,28 @@ pn_decimal64_t pn_data_get_decimal64(pn_data_t *data) pn_decimal128_t pn_data_get_decimal128(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_DECIMAL128) { - return node->atom.u.as_decimal128; - } else { - pn_decimal128_t t = {{0}}; - return t; + pn_decimal128_t t = {{0}}; + if (node && node->type == PN_DECIMAL128) { + memcpy(t.bytes, pni_node_bytes(data, node).start, 16); } + return t; } pn_uuid_t pn_data_get_uuid(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_UUID) { - return node->atom.u.as_uuid; - } else { - pn_uuid_t t = {{0}}; - return t; + pn_uuid_t t = {{0}}; + if (node && node->type == PN_UUID) { + memcpy(t.bytes, pni_node_bytes(data, node).start, 16); } + return t; } pn_bytes_t pn_data_get_binary(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_BINARY) { - return node->atom.u.as_bytes; + if (node && node->type == PN_BINARY) { + return pni_node_bytes(data, node); } else { pn_bytes_t t = {0}; return t; @@ -2133,8 +2120,8 @@ pn_bytes_t pn_data_get_binary(pn_data_t *data) pn_bytes_t pn_data_get_string(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_STRING) { - return node->atom.u.as_bytes; + if (node && node->type == PN_STRING) { + return pni_node_bytes(data, node); } else { pn_bytes_t t = {0}; return t; @@ -2144,8 +2131,8 @@ pn_bytes_t pn_data_get_string(pn_data_t *data) pn_bytes_t pn_data_get_symbol(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->atom.type == PN_SYMBOL) { - return node->atom.u.as_bytes; + if (node && node->type == PN_SYMBOL) { + return pni_node_bytes(data, node); } else { pn_bytes_t t = {0}; return t; @@ -2155,10 +2142,10 @@ pn_bytes_t pn_data_get_symbol(pn_data_t *data) pn_bytes_t pn_data_get_bytes(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && (node->atom.type == PN_BINARY || - node->atom.type == PN_STRING || - node->atom.type == PN_SYMBOL)) { - return node->atom.u.as_bytes; + if (node && (node->type == PN_BINARY || + node->type == PN_STRING || + node->type == PN_SYMBOL)) { + return pni_node_bytes(data, node); } else { pn_bytes_t t = {0}; return t; @@ -2168,12 +2155,25 @@ pn_bytes_t pn_data_get_bytes(pn_data_t *data) pn_atom_t pn_data_get_atom(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node) { - return *((pn_atom_t *) &node->atom); - } else { - pn_atom_t t = {PN_NULL, {0,}}; - return t; + if (!node) { + return (pn_atom_t){PN_NULL}; + } + pn_atom_t t = {node->type}; + switch (node->type) { + case PN_BINARY: case PN_STRING: case PN_SYMBOL: + t.u.as_bytes = pni_node_bytes(data, node); + break; + case PN_DECIMAL128: + memcpy(t.u.as_decimal128.bytes, pni_node_bytes(data, node).start, 16); + break; + case PN_UUID: + memcpy(t.u.as_uuid.bytes, pni_node_bytes(data, node).start, 16); + break; + default: + memcpy(&t.u, &node->u, sizeof(t.u)); + break; } + return t; } int pn_data_copy(pn_data_t *data, pn_data_t *src) diff --git a/c/src/core/data.h b/c/src/core/data.h index 8b1f5a61e..946bb086d 100644 --- a/c/src/core/data.h +++ b/c/src/core/data.h @@ -31,21 +31,88 @@ typedef uint16_t pni_nid_t; #define PNI_NID_MAX ((pni_nid_t)-1) #define PNI_INTERN_MINSIZE 64 +/* + * Value payload for a pni_node_t. + * + * BINARY/STRING/SYMBOL/DECIMAL128/UUID nodes store their data in the intern + * buffer (data->buf); as_bytes.offset and as_bytes.size locate the bytes. + * DECIMAL128 and UUID always have as_bytes.size == 16. + * + * PN_ARRAY nodes use as_array: element type, whether the array has a + * descriptor child (described), and encoder scratch (start, small). + * + * PN_LIST nodes use as_list: whether the list is the body of a described + * value (controls trailing-null elision during encoding), and encoder + * scratch (start, small). + * + * PN_MAP nodes use as_map: encoder scratch (start, small). + * + * All other types (NULL, DESCRIBED) carry no payload; only the type tag + * on pni_node_t is meaningful. + */ +typedef union { + bool as_bool; + uint8_t as_ubyte; + int8_t as_byte; + uint16_t as_ushort; + int16_t as_short; + uint32_t as_uint; + int32_t as_int; + uint32_t as_char; /* pn_char_t is typedef'd uint32_t */ + uint64_t as_ulong; + int64_t as_long; + int64_t as_timestamp; /* pn_timestamp_t is typedef'd int64_t */ + float as_float; + double as_double; + uint32_t as_decimal32; + uint64_t as_decimal64; + struct { + uint32_t offset; /* byte offset into data->buf */ + uint32_t size; /* byte count (always 16 for decimal128/uuid) */ + } as_bytes; + struct { + uint32_t start; /* encoder scratch: output offset of size field */ + bool described; /* true if first child is a descriptor */ + uint8_t type; /* element type (pn_type_t fits in uint8_t: values 1-25) */ + /* 2 implicit padding bytes */ + } as_array; + struct { + uint32_t start; /* encoder scratch: output offset of size field */ + bool described; /* true if body of a described composite */ + /* 3 implicit padding bytes */ + } as_list; + struct { + uint32_t start; /* encoder scratch: output offset of size field */ + /* 4 implicit padding bytes */ + } as_map; +} pni_node_payload_t; + +/* + * Layout (64-bit): 24 bytes. + * + * offset 0 type (4) value type tag + * offset 4 next (2) sibling link + * offset 6 prev (2) sibling link + * offset 8 down (2) + * offset 10 parent (2) + * offset 12 children (2) + * offset 14 <2 implicit alignment bytes before u> + * offset 16 u (8) value payload (8-byte aligned) + * + * Note that there is still a bit of possibility to reduce this further: + * The type takes 4 bytes, but need only take 1; there is 2 bytes of padding still; + * I'm pretty sure that we could do away with one of the navigation links (having down + * and children seems redundant). However unless we can get it to 16 bytes there is + * little point as it must be 8 byte aligned anyway (because of the int64_t in the union). + */ typedef struct { - size_t start; - size_t data_offset; - size_t data_size; - pn_atom_t atom; - pn_type_t type; - pni_nid_t next; - pni_nid_t prev; - pni_nid_t down; - pni_nid_t parent; - pni_nid_t children; - // for arrays - bool described; - bool data; - bool small; + pn_type_t type; + pni_nid_t next; + pni_nid_t prev; + pni_nid_t down; + pni_nid_t parent; + pni_nid_t children; + pni_node_payload_t u; } pni_node_t; struct pn_data_t { diff --git a/c/src/core/encoder.c b/c/src/core/encoder.c index 97af8de16..b312fc4fb 100644 --- a/c/src/core/encoder.c +++ b/c/src/core/encoder.c @@ -84,61 +84,61 @@ static uint8_t pn_type2code(pn_encoder_t *encoder, pn_type_t type) static uint8_t pn_node2code(pn_encoder_t *encoder, pni_node_t *node) { - switch (node->atom.type) { + switch (node->type) { case PN_LONG: - if (-128 <= node->atom.u.as_long && node->atom.u.as_long <= 127) { + if (-128 <= node->u.as_long && node->u.as_long <= 127) { return PNE_SMALLLONG; } else { return PNE_LONG; } case PN_INT: - if (-128 <= node->atom.u.as_int && node->atom.u.as_int <= 127) { + if (-128 <= node->u.as_int && node->u.as_int <= 127) { return PNE_SMALLINT; } else { return PNE_INT; } case PN_ULONG: - if (node->atom.u.as_ulong == 0) { + if (node->u.as_ulong == 0) { return PNE_ULONG0; - } else if (node->atom.u.as_ulong < 256) { + } else if (node->u.as_ulong < 256) { return PNE_SMALLULONG; } else { return PNE_ULONG; } case PN_UINT: - if (node->atom.u.as_uint == 0) { + if (node->u.as_uint == 0) { return PNE_UINT0; - } else if (node->atom.u.as_uint < 256) { + } else if (node->u.as_uint < 256) { return PNE_SMALLUINT; } else { return PNE_UINT; } case PN_BOOL: - if (node->atom.u.as_bool) { + if (node->u.as_bool) { return PNE_TRUE; } else { return PNE_FALSE; } case PN_STRING: - if (node->atom.u.as_bytes.size < 256) { + if (node->u.as_bytes.size < 256) { return PNE_STR8_UTF8; } else { return PNE_STR32_UTF8; } case PN_SYMBOL: - if (node->atom.u.as_bytes.size < 256) { + if (node->u.as_bytes.size < 256) { return PNE_SYM8; } else { return PNE_SYM32; } case PN_BINARY: - if (node->atom.u.as_bytes.size < 256) { + if (node->u.as_bytes.size < 256) { return PNE_VBIN8; } else { return PNE_VBIN32; } default: - return pn_type2code(encoder, node->atom.type); + return pn_type2code(encoder, node->type); } } @@ -225,23 +225,23 @@ static inline void pn_encoder_writev32(pn_encoder_t *encoder, const pn_bytes_t * /* True if node is an element of an array - not the descriptor. */ static bool pn_is_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) { - return (parent && parent->atom.type == PN_ARRAY) /* In array */ - && !(parent->described && !node->prev); /* Not the descriptor */ + return (parent && parent->type == PN_ARRAY) /* In array */ + && !(parent->u.as_array.described && !node->prev); /* Not the descriptor */ } /** True if node is the first element of an array, not the descriptor. *@pre pn_is_in_array(data, parent, node) */ static bool pn_is_first_in_array(pn_data_t *data, pni_node_t *parent, pni_node_t *node) { - if (!node->prev) return !parent->described; /* First node */ - return parent->described && (!pn_data_node(data, node->prev)->prev); + if (!node->prev) return !parent->u.as_array.described; /* First node */ + return parent->u.as_array.described && (!pn_data_node(data, node->prev)->prev); } /** True if node is in a described list - not the descriptor. * - In this case we can omit trailing nulls */ static bool pn_is_in_described_list(pn_data_t *data, pni_node_t *parent, pni_node_t *node) { - return parent && parent->atom.type == PN_LIST && parent->described; + return parent && parent->type == PN_LIST && parent->u.as_list.described; } typedef union { @@ -256,13 +256,12 @@ static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node) { pn_encoder_t *encoder = (pn_encoder_t *) ctx; pni_node_t *parent = pn_data_node(data, node->parent); - pn_atom_t *atom = &node->atom; uint8_t code; conv_t c; /** In an array we don't write the code before each element, only the first. */ if (pn_is_in_array(data, parent, node)) { - code = pn_type2code(encoder, parent->type); + code = pn_type2code(encoder, parent->u.as_array.type); if (pn_is_first_in_array(data, parent, node)) { pn_encoder_writef8(encoder, code); } @@ -285,53 +284,57 @@ static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node) } } + pn_rwbytes_t buf = (data->buf) ? pn_buffer_memory(data->buf) : (pn_rwbytes_t){0}; switch (code) { case PNE_DESCRIPTOR: case PNE_NULL: case PNE_TRUE: case PNE_FALSE: return 0; - case PNE_BOOLEAN: pn_encoder_writef8(encoder, atom->u.as_bool); return 0; - case PNE_UBYTE: pn_encoder_writef8(encoder, atom->u.as_ubyte); return 0; - case PNE_BYTE: pn_encoder_writef8(encoder, atom->u.as_byte); return 0; - case PNE_USHORT: pn_encoder_writef16(encoder, atom->u.as_ushort); return 0; - case PNE_SHORT: pn_encoder_writef16(encoder, atom->u.as_short); return 0; + case PNE_BOOLEAN: pn_encoder_writef8(encoder, node->u.as_bool); return 0; + case PNE_UBYTE: pn_encoder_writef8(encoder, node->u.as_ubyte); return 0; + case PNE_BYTE: pn_encoder_writef8(encoder, node->u.as_byte); return 0; + case PNE_USHORT: pn_encoder_writef16(encoder, node->u.as_ushort); return 0; + case PNE_SHORT: pn_encoder_writef16(encoder, node->u.as_short); return 0; case PNE_UINT0: return 0; - case PNE_SMALLUINT: pn_encoder_writef8(encoder, atom->u.as_uint); return 0; - case PNE_UINT: pn_encoder_writef32(encoder, atom->u.as_uint); return 0; - case PNE_SMALLINT: pn_encoder_writef8(encoder, atom->u.as_int); return 0; - case PNE_INT: pn_encoder_writef32(encoder, atom->u.as_int); return 0; - case PNE_UTF32: pn_encoder_writef32(encoder, atom->u.as_char); return 0; + case PNE_SMALLUINT: pn_encoder_writef8(encoder, node->u.as_uint); return 0; + case PNE_UINT: pn_encoder_writef32(encoder, node->u.as_uint); return 0; + case PNE_SMALLINT: pn_encoder_writef8(encoder, node->u.as_int); return 0; + case PNE_INT: pn_encoder_writef32(encoder, node->u.as_int); return 0; + case PNE_UTF32: pn_encoder_writef32(encoder, node->u.as_char); return 0; case PNE_ULONG0: return 0; - case PNE_ULONG: pn_encoder_writef64(encoder, atom->u.as_ulong); return 0; - case PNE_SMALLULONG: pn_encoder_writef8(encoder, atom->u.as_ulong); return 0; - case PNE_LONG: pn_encoder_writef64(encoder, atom->u.as_long); return 0; - case PNE_SMALLLONG: pn_encoder_writef8(encoder, atom->u.as_long); return 0; - case PNE_MS64: pn_encoder_writef64(encoder, atom->u.as_timestamp); return 0; - case PNE_FLOAT: c.f = atom->u.as_float; pn_encoder_writef32(encoder, c.i); return 0; - case PNE_DOUBLE: c.d = atom->u.as_double; pn_encoder_writef64(encoder, c.l); return 0; - case PNE_DECIMAL32: pn_encoder_writef32(encoder, atom->u.as_decimal32); return 0; - case PNE_DECIMAL64: pn_encoder_writef64(encoder, atom->u.as_decimal64); return 0; - case PNE_DECIMAL128: pn_encoder_writef128(encoder, atom->u.as_decimal128.bytes); return 0; - case PNE_UUID: pn_encoder_writef128(encoder, atom->u.as_uuid.bytes); return 0; - case PNE_VBIN8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0; - case PNE_VBIN32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0; - case PNE_STR8_UTF8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0; - case PNE_STR32_UTF8: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0; - case PNE_SYM8: pn_encoder_writev8(encoder, &atom->u.as_bytes); return 0; - case PNE_SYM32: pn_encoder_writev32(encoder, &atom->u.as_bytes); return 0; + case PNE_ULONG: pn_encoder_writef64(encoder, node->u.as_ulong); return 0; + case PNE_SMALLULONG: pn_encoder_writef8(encoder, node->u.as_ulong); return 0; + case PNE_LONG: pn_encoder_writef64(encoder, node->u.as_long); return 0; + case PNE_SMALLLONG: pn_encoder_writef8(encoder, node->u.as_long); return 0; + case PNE_MS64: pn_encoder_writef64(encoder, node->u.as_timestamp); return 0; + case PNE_FLOAT: c.f = node->u.as_float; pn_encoder_writef32(encoder, c.i); return 0; + case PNE_DOUBLE: c.d = node->u.as_double; pn_encoder_writef64(encoder, c.l); return 0; + case PNE_DECIMAL32: pn_encoder_writef32(encoder, node->u.as_decimal32); return 0; + case PNE_DECIMAL64: pn_encoder_writef64(encoder, node->u.as_decimal64); return 0; + case PNE_DECIMAL128: pn_encoder_writef128(encoder, (buf.start + node->u.as_bytes.offset)); return 0; + case PNE_UUID: pn_encoder_writef128(encoder, (buf.start + node->u.as_bytes.offset)); return 0; + case PNE_VBIN8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + node->u.as_bytes.offset}; pn_encoder_writev8(encoder, &b); return 0; } + case PNE_VBIN32: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + node->u.as_bytes.offset}; pn_encoder_writev32(encoder, &b); return 0; } + case PNE_STR8_UTF8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + node->u.as_bytes.offset}; pn_encoder_writev8(encoder, &b); return 0; } + case PNE_STR32_UTF8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + node->u.as_bytes.offset}; pn_encoder_writev32(encoder, &b); return 0; } + case PNE_SYM8: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + node->u.as_bytes.offset}; pn_encoder_writev8(encoder, &b); return 0; } + case PNE_SYM32: { pn_bytes_t b = {node->u.as_bytes.size, buf.start + node->u.as_bytes.offset}; pn_encoder_writev32(encoder, &b); return 0; } case PNE_ARRAY32: - node->start = encoder->position; - node->small = false; + node->u.as_array.start = (uint32_t) encoder->position; // we'll backfill the size on exit encoder->position += 4; - pn_encoder_writef32(encoder, node->described ? node->children - 1 : node->children); - if (node->described) + pn_encoder_writef32(encoder, node->u.as_array.described ? node->children - 1 : node->children); + if (node->u.as_array.described) pn_encoder_writef8(encoder, 0); return 0; case PNE_LIST32: + node->u.as_list.start = (uint32_t) encoder->position; + // we'll backfill the size later + encoder->position += 4; + pn_encoder_writef32(encoder, node->children); + return 0; case PNE_MAP32: - node->start = encoder->position; - node->small = false; + node->u.as_map.start = (uint32_t) encoder->position; // we'll backfill the size later encoder->position += 4; pn_encoder_writef32(encoder, node->children); @@ -350,43 +353,36 @@ static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node) // Special case 0 length list, but not as element in an array pni_node_t *parent = pn_data_node(data, node->parent); - if (node->atom.type==PN_LIST && node->children-encoder->null_count==0 && !pn_is_in_array(data, parent, node)) { - encoder->position = node->start-1; // position of list opcode + if (node->type==PN_LIST && node->children-encoder->null_count==0 && !pn_is_in_array(data, parent, node)) { + encoder->position = node->u.as_list.start - 1; // position of list opcode pn_encoder_writef8(encoder, PNE_LIST0); encoder->null_count = 0; return 0; } - switch (node->atom.type) { + switch (node->type) { case PN_ARRAY: - if ((node->described && node->children == 1) || (!node->described && node->children == 0)) { - pn_encoder_writef8(encoder, pn_type2code(encoder, node->type)); + if ((node->u.as_array.described && node->children == 1) || (!node->u.as_array.described && node->children == 0)) { + pn_encoder_writef8(encoder, pn_type2code(encoder, node->u.as_array.type)); } PN_FALLTHROUGH; case PN_LIST: - case PN_MAP: + case PN_MAP: { pos = encoder->position; - encoder->position = node->start; - if (node->small) { - // backfill size - size_t size = pos - node->start - 1; - pn_encoder_writef8(encoder, size); - // Adjust count - if (encoder->null_count) { - pn_encoder_writef8(encoder, node->children-encoder->null_count); - } - } else { - // backfill size - size_t size = pos - node->start - 4; - pn_encoder_writef32(encoder, size); - // Adjust count - if (encoder->null_count) { - pn_encoder_writef32(encoder, node->children-encoder->null_count); - } + /* start is at the same offset in as_array/as_list/as_map — use as_list uniformly */ + uint32_t start = node->u.as_list.start; + encoder->position = start; + // backfill size + size_t size = pos - start - 4; + pn_encoder_writef32(encoder, size); + // Adjust count + if (encoder->null_count) { + pn_encoder_writef32(encoder, node->children-encoder->null_count); } encoder->position = pos; encoder->null_count = 0; return 0; + } default: return 0; } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
