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 717d1bde2dc95fc1b259b9b5eaaec1647e73b4fd Author: Andrew Stitcher <[email protected]> AuthorDate: Mon Aug 17 19:27:53 2026 -0400 PROTON-2954: Further reduce pn_data_t memory use Reduced the per node memory use to 16 bytes from 24 bytes. This is a 4.5 times reductions over the original 72 bytes. This now mitigates significantly the maximum node storage that could occur to 1MiB. Practically the intern buffer storage should always be limited by the size of the raw protocol bytes that are being decoded. Achieved by: - Moving navigation links into the specific node type that uses them. - Removing members that could be computed. - Using spare packing space for the base type of an AMQP array. - Splitting arrays into regular and arrays of described types. Surprisingly this hasn't made the code significantly more complex and has simplified a few things. --- c/src/core/codec.c | 156 ++++++++++++++++++++++----------------- c/src/core/data.h | 202 ++++++++++++++++++++++++++++++++++++++++++--------- c/src/core/decoder.c | 4 +- c/src/core/encoder.c | 39 ++++++---- 4 files changed, 288 insertions(+), 113 deletions(-) diff --git a/c/src/core/codec.c b/c/src/core/codec.c index 3745ab71b..75cc49e04 100644 --- a/c/src/core/codec.c +++ b/c/src/core/codec.c @@ -40,9 +40,16 @@ #include "logger_private.h" #include "memory.h" +// Convert internal types to external API types +static inline pn_type_t pni_type_external(uint8_t internal_type) +{ + if (internal_type == PN_ARRAY_DESCRIBED) return PN_ARRAY; + return internal_type; +} + const char *pn_type_name(pn_type_t type) { - switch (type) + switch ((uint8_t)type) { case PN_NULL: return "PN_NULL"; case PN_BOOL: return "PN_BOOL"; @@ -67,6 +74,7 @@ const char *pn_type_name(pn_type_t type) case PN_SYMBOL: return "PN_SYMBOL"; case PN_DESCRIBED: return "PN_DESCRIBED"; case PN_ARRAY: return "PN_ARRAY"; + case PN_ARRAY_DESCRIBED: return "PN_ARRAY_DESCRIBED"; case PN_LIST: return "PN_LIST"; case PN_MAP: return "PN_MAP"; default: break; @@ -90,7 +98,7 @@ static const pn_fields_t *pni_node_fields(pn_data_t *data, pni_node_t *node) if (!node) return NULL; if (node->type != PN_DESCRIBED) return NULL; - pni_node_t *descriptor = pn_data_node(data, node->down); + pni_node_t *descriptor = pn_data_node(data, node->u.as_described.down); if (!descriptor || descriptor->type != PN_ULONG) { return NULL; @@ -291,7 +299,7 @@ int pni_inspect_enter(void *ctx, pn_data_t *data, pni_node_t *node) return 0; case PN_ARRAY: // XXX: need to fix for described arrays - pn_fixed_string_addf(str, "@%s[", pn_type_name(node->u.as_array.type)); + pn_fixed_string_addf(str, "@%s[", pn_type_name(node->array_type)); return 0; case PN_LIST: pn_fixed_string_addf(str, "["); @@ -568,6 +576,7 @@ static int pni_normalize_multiple(pn_data_t *data, pn_data_t *src) { return err; } +static int pni_data_put_deferred(pn_data_t *data, pn_type_t type); /* Format codes: code: AMQP-type (arguments) @@ -652,7 +661,7 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap) break; case 'Z': /* encode binary, must not be NULL */ { - // For maximum portability, caller must pass these as two separate args, not a single struct + // For maximum portability, caller must pass these as two separate args, not a single struct size_t size = va_arg(ap, size_t); char *start = va_arg(ap, char *); err = pn_data_put_binary(data, pn_bytes(size, start)); @@ -660,7 +669,7 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap) break; case 'z': /* encode binary or null if pointer is NULL */ { - // For maximum portability, caller must pass these as two separate args, not a single struct + // For maximum portability, caller must pass these as two separate args, not a single struct size_t size = va_arg(ap, size_t); char *start = va_arg(ap, char *); if (start) { @@ -689,14 +698,14 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap) break; case 'D': /* The next 2 args are the descriptor, value for a described value. */ - err = pn_data_put_described(data); + err = pni_data_put_deferred(data, PN_DESCRIBED); pn_data_enter(data); break; case 'T': /* Set type of open array */ { pni_node_t *parent = pn_data_node(data, data->parent); if (parent->type == PN_ARRAY) { - parent->u.as_array.type = (uint8_t) va_arg(ap, int); + parent->array_type = (uint8_t) va_arg(ap, int); } else { return pn_error_format(pni_data_error(data), PN_ERR, "naked type"); } @@ -734,7 +743,7 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap) break; case '?': if (!va_arg(ap, int)) { - err = pn_data_put_null(data); + err = pni_data_put_deferred(data, PN_NULL); if (err) return err; pn_data_enter(data); } @@ -804,22 +813,27 @@ int pn_data_vfill(pn_data_t *data, const char *fmt, va_list ap) if (err) return err; pni_node_t *parent = pn_data_node(data, data->parent); - pni_node_t *current = pn_data_node(data, data->current); while (parent) { - 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->type == PN_NULL && parent->children == 1) { - pn_data_exit(data); - current = pn_data_node(data, data->current); - current->down = 0; - current->children = 0; - parent = pn_data_node(data, data->parent); - } else { - break; + if (parent->type == PN_DEFER) { + if (parent->u.as_deferred.type == PN_DESCRIBED && parent->u.as_deferred.children_count == 2) { + pn_data_exit(data); + parent = pn_data_node(data, data->parent); + pni_node_t *current = pn_data_node(data, data->current); + pni_nid_t down = current->u.as_deferred.down; + uint16_t count = current->u.as_deferred.children_count; + current->type = PN_DESCRIBED; + current->u.as_described.down = down; + current->u.as_described.children_count = count; + continue; + } else if (parent->u.as_deferred.type == PN_NULL && parent->u.as_deferred.children_count == 1) { + pn_data_exit(data); + parent = pn_data_node(data, data->parent); + pni_node_t *current = pn_data_node(data, data->current); + current->type = PN_NULL; + continue; + } } + break; } } @@ -1288,9 +1302,9 @@ static pni_node_t *pni_data_new(pn_data_t *data) return NULL; } pni_node_t *node = pn_data_node(data, ++(data->size)); + node->type = PN_NULL; node->next = 0; - node->down = 0; - node->children = 0; + node->array_type = 0; return node; } @@ -1352,7 +1366,7 @@ static pni_node_t *pni_data_peek(pn_data_t *data) pni_node_t *parent = pn_data_node(data, data->parent); if (parent) { - return pn_data_node(data, parent->down); + return pn_data_node(data, pni_node_get_down(parent)); } return NULL; @@ -1366,8 +1380,8 @@ bool pn_data_next(pn_data_t *data) if (current) { next = current->next; - } else if (parent && parent->down) { - next = parent->down; + } else if (parent && pni_node_get_down(parent)) { + next = pni_node_get_down(parent); } else if (!parent && data->size) { next = 1; } else { @@ -1406,8 +1420,8 @@ int pni_data_traverse(pn_data_t *data, if (err) return err; size_t next = 0; - if (node->down) { - next = node->down; + if (pni_node_get_down(node)) { + next = pni_node_get_down(node); } else if (node->next) { err = exit(ctx, data, node); if (err) return err; @@ -1437,7 +1451,7 @@ pn_type_t pn_data_type(pn_data_t *data) { pni_node_t *node = pni_data_current(data); if (node) { - return node->type; + return pni_type_external(node->type); } else { return PN_INVALID; } @@ -1457,7 +1471,7 @@ size_t pn_data_siblings(pn_data_t *data) { pni_node_t *node = pn_data_node(data, data->parent); if (node) { - return node->children; + return pni_node_get_children(node); } else { return 0; } @@ -1532,8 +1546,8 @@ void pn_data_dump(pn_data_t *data) i + 1, (size_t) node->prev, (size_t) node->next, (size_t) node->parent, - (size_t) node->down, - (size_t) node->children, + (size_t) pni_node_get_down(node), + (size_t) pni_node_get_children(node), pn_type_name(node->type), buf); } } @@ -1558,15 +1572,15 @@ static pni_node_t *pni_data_add(pn_data_t *data) current->next = pni_data_id(data, node); node->parent = data->parent; if (parent) { - if (!parent->down) { - parent->down = pni_data_id(data, node); + if (!pni_node_get_down(parent)) { + pni_node_set_down(parent, pni_data_id(data, node)); } - parent->children++; + pni_node_inc_children(parent); } } } else if (parent) { - if (parent->down) { - node = pn_data_node(data, parent->down); + if (pni_node_get_down(parent)) { + node = pn_data_node(data, pni_node_get_down(parent)); } else { node = pni_data_new(data); if (!node) return NULL; @@ -1575,8 +1589,8 @@ static pni_node_t *pni_data_add(pn_data_t *data) parent = pn_data_node(data, data->parent); node->prev = 0; node->parent = data->parent; - parent->down = pni_data_id(data, node); - parent->children++; + pni_node_set_down(parent, pni_data_id(data, node)); + pni_node_inc_children(parent); } } else if (data->size) { node = pn_data_node(data, 1); @@ -1588,8 +1602,6 @@ static pni_node_t *pni_data_add(pn_data_t *data) node->parent = 0; } - node->down = 0; - node->children = 0; memset(&node->u, 0, sizeof(node->u)); data->current = pni_data_id(data, node); return node; @@ -1622,12 +1634,22 @@ ssize_t pn_data_decode(pn_data_t *data, const char *bytes, size_t size) return r; } +static int pni_data_put_deferred(pn_data_t *data, pn_type_t type) +{ + pni_node_t *node = pni_data_add(data); + if (node == NULL) return PN_OUT_OF_MEMORY; + node->type = PN_DEFER; + node->u.as_deferred.type = (uint8_t) type; + return 0; +} + 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->type = PN_LIST; - node->u.as_list.described = false; + node->u.as_list.down = 0; + node->u.as_list.children_count = 0; return 0; } @@ -1636,6 +1658,8 @@ 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->type = PN_MAP; + node->u.as_map.down = 0; + node->u.as_map.children_count = 0; return 0; } @@ -1643,16 +1667,19 @@ 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->type = PN_ARRAY; - node->u.as_array.described = described; - node->u.as_array.type = (uint8_t) type; + node->type = described ? PN_ARRAY_DESCRIBED : PN_ARRAY; + node->array_type = (uint8_t)type; + node->u.as_array.down = 0; + node->u.as_array.children_count = 0; 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->u.as_array.type = (uint8_t) type; + if (array) { + array->array_type = (uint8_t)type; + } } int pn_data_put_described(pn_data_t *data) @@ -1660,6 +1687,8 @@ 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->type = PN_DESCRIBED; + node->u.as_described.down = 0; + node->u.as_described.children_count = 0; return 0; } @@ -1874,7 +1903,7 @@ size_t pn_data_get_list(pn_data_t *data) { pni_node_t *node = pni_data_current(data); if (node && node->type == PN_LIST) { - return node->children; + return node->u.as_list.children_count; } else { return 0; } @@ -1884,7 +1913,7 @@ size_t pn_data_get_map(pn_data_t *data) { pni_node_t *node = pni_data_current(data); if (node && node->type == PN_MAP) { - return node->children; + return node->u.as_map.children_count; } else { return 0; } @@ -1893,32 +1922,28 @@ 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->type == PN_ARRAY) { - if (node->u.as_array.described) { - return node->children - 1; - } else { - return node->children; - } - } else { - return 0; + if (!node) return 0; + + if (node->type == PN_ARRAY_DESCRIBED) { + return node->u.as_array.children_count - 1; // Descriptor doesn't count + } + if (node->type == PN_ARRAY) { + return node->u.as_array.children_count; } + return 0; } bool pn_data_is_array_described(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->type == PN_ARRAY) { - return node->u.as_array.described; - } else { - return false; - } + return node && node->type == PN_ARRAY_DESCRIBED; } pn_type_t pn_data_get_array_type(pn_data_t *data) { pni_node_t *node = pni_data_current(data); - if (node && node->type == PN_ARRAY) { - return node->u.as_array.type; + if (node && (node->type == PN_ARRAY || node->type == PN_ARRAY_DESCRIBED)) { + return node->array_type; } else { return PN_INVALID; } @@ -2158,7 +2183,8 @@ pn_atom_t pn_data_get_atom(pn_data_t *data) if (!node) { return (pn_atom_t){PN_NULL}; } - pn_atom_t t = {node->type}; + + pn_atom_t t = {pni_type_external(node->type)}; switch (node->type) { case PN_BINARY: case PN_STRING: case PN_SYMBOL: t.u.as_bytes = pni_node_bytes(data, node); diff --git a/c/src/core/data.h b/c/src/core/data.h index 946bb086d..4dee470e9 100644 --- a/c/src/core/data.h +++ b/c/src/core/data.h @@ -31,6 +31,9 @@ typedef uint16_t pni_nid_t; #define PNI_NID_MAX ((pni_nid_t)-1) #define PNI_INTERN_MINSIZE 64 +#define PN_ARRAY_DESCRIBED 26 // Internal type: described array +#define PN_DEFER 27 // Internal type: node used only in pn_data_fill/vfill + /* * Value payload for a pni_node_t. * @@ -71,50 +74,68 @@ typedef union { 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; + pni_nid_t down; // offset 0: 2 bytes + pni_nid_t children_count; // offset 2: 2 bytes + uint8_t type; /* deferred type */ + } as_deferred; + + // Compound types include navigation + struct { + pni_nid_t down; // offset 0: 2 bytes + pni_nid_t children_count; // offset 2: 2 bytes + uint32_t start; // offset 4: 4 bytes + } as_array; // 8 bytes + + struct { + pni_nid_t down; // offset 0: 2 bytes + pni_nid_t children_count; // offset 2: 2 bytes + uint32_t start; // offset 4: 4 bytes + } as_list; // 8 bytes + 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; + pni_nid_t down; // offset 0: 2 bytes + pni_nid_t children_count; // offset 2: 2 bytes + uint32_t start; // offset 4: 4 bytes + } as_map; // 8 bytes + struct { - uint32_t start; /* encoder scratch: output offset of size field */ - /* 4 implicit padding bytes */ - } as_map; + pni_nid_t down; // offset 0: 2 bytes + pni_nid_t children_count; // offset 2: 2 bytes + } as_described; // 4 bytes (union is 8) } pni_node_payload_t; /* - * Layout (64-bit): 24 bytes. + * Layout (64-bit): 16 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) + * offset 0 type (1) internal value type tag + * offset 1 array_type (1) array element type (when applicable) + * offset 2 next (2) sibling link + * offset 4 prev (2) sibling link + * offset 6 parent (2) parent link + * offset 8 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). + * Compound types (PN_ARRAY, PN_LIST, PN_MAP, PN_DESCRIBED) store down/children + * in their union structure. Scalar types have no children, so down/children are + * not needed for them. */ typedef struct { - 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; + uint8_t type; // offset 0: 1 byte + uint8_t array_type; // offset 1: 1 byte + pni_nid_t next; // offset 2: 2 bytes + pni_nid_t prev; // offset 4: 2 bytes + pni_nid_t parent; // offset 6: 2 bytes + pni_node_payload_t u; // offset 8: 8 bytes (8-byte aligned) } pni_node_t; +#ifdef __cplusplus +static_assert(sizeof(pni_node_t) == 16, "pni_node_t must be 16 bytes"); +static_assert(sizeof(pni_node_payload_t) == 8, "union must be 8 bytes"); +#else +/* C99 compile-time size assertions */ +typedef char pni_node_size_check[sizeof(pni_node_t) == 16 ? 1 : -1]; +typedef char pni_payload_size_check[sizeof(pni_node_payload_t) == 8 ? 1 : -1]; +#endif + struct pn_data_t { pni_node_t *nodes; pn_buffer_t *buf; @@ -146,6 +167,121 @@ static inline pni_node_t * pn_data_node(pn_data_t *data, pni_nid_t nd) return nd ? (data->nodes + nd - 1) : NULL; } +static inline pni_nid_t pni_node_get_down(pni_node_t *node) +{ + if (!node) return 0; + switch (node->type) { + case PN_ARRAY: + case PN_ARRAY_DESCRIBED: + return node->u.as_array.down; + case PN_LIST: + return node->u.as_list.down; + case PN_MAP: + return node->u.as_map.down; + case PN_DESCRIBED: + return node->u.as_described.down; + case PN_DEFER: + return node->u.as_deferred.down; + default: + return 0; // Scalar types have no children + } +} + +static inline void pni_node_set_down(pni_node_t *node, pni_nid_t down) +{ + if (!node) return; + switch (node->type) { + case PN_ARRAY: + case PN_ARRAY_DESCRIBED: + node->u.as_array.down = down; + break; + case PN_LIST: + node->u.as_list.down = down; + break; + case PN_MAP: + node->u.as_map.down = down; + break; + case PN_DESCRIBED: + node->u.as_described.down = down; + break; + case PN_DEFER: + node->u.as_deferred.down = down; + break; + default: + break; // Scalar types - do nothing + } +} + +static inline pni_nid_t pni_node_get_children(pni_node_t *node) +{ + if (!node) return 0; + switch (node->type) { + case PN_ARRAY: + case PN_ARRAY_DESCRIBED: + return node->u.as_array.children_count; + case PN_LIST: + return node->u.as_list.children_count; + case PN_MAP: + return node->u.as_map.children_count; + case PN_DESCRIBED: + return node->u.as_described.children_count; + case PN_DEFER: + return node->u.as_deferred.children_count; + default: + return 0; + } +} + +static inline void pni_node_set_children(pni_node_t *node, pni_nid_t count) +{ + if (!node) return; + switch (node->type) { + case PN_ARRAY: + case PN_ARRAY_DESCRIBED: + node->u.as_array.children_count = count; + break; + case PN_LIST: + node->u.as_list.children_count = count; + break; + case PN_MAP: + node->u.as_map.children_count = count; + break; + case PN_DESCRIBED: + node->u.as_described.children_count = count; + break; + case PN_DEFER: + node->u.as_deferred.children_count = count; + break; + default: + break; + } +} + +static inline void pni_node_inc_children(pni_node_t *node) +{ + if (!node) return; + switch (node->type) { + case PN_ARRAY: + case PN_ARRAY_DESCRIBED: + node->u.as_array.children_count++; + break; + case PN_LIST: + node->u.as_list.children_count++; + break; + case PN_MAP: + node->u.as_map.children_count++; + break; + case PN_DESCRIBED: + node->u.as_described.children_count++; + break; + case PN_DEFER: + node->u.as_deferred.children_count++; + break; + default: + break; + } +} + int pni_data_traverse(pn_data_t *data, int (*enter)(void *ctx, pn_data_t *data, pni_node_t *node), int (*exit)(void *ctx, pn_data_t *data, pni_node_t *node), diff --git a/c/src/core/decoder.c b/c/src/core/decoder.c index fbda81495..64d471fe8 100644 --- a/c/src/core/decoder.c +++ b/c/src/core/decoder.c @@ -23,6 +23,7 @@ #include <proton/codec.h> #include "encodings.h" #include "decoder.h" +#include "data.h" #include <string.h> @@ -455,7 +456,8 @@ static int pni_decoder_decode_type(pn_decoder_t *decoder, pn_data_t *data, uint8 return 0; } - if (pni_data_parent_type(data) != PN_ARRAY) { + pn_type_t parent_type = pni_data_parent_type(data); + if (parent_type != PN_ARRAY && parent_type != PN_ARRAY_DESCRIBED) { err = pn_data_put_described(data); if (err) return err; diff --git a/c/src/core/encoder.c b/c/src/core/encoder.c index b312fc4fb..b2a6c4136 100644 --- a/c/src/core/encoder.c +++ b/c/src/core/encoder.c @@ -137,6 +137,8 @@ static uint8_t pn_node2code(pn_encoder_t *encoder, pni_node_t *node) } else { return PNE_VBIN32; } + case PN_ARRAY_DESCRIBED: + return PNE_ARRAY32; default: return pn_type2code(encoder, node->type); } @@ -225,23 +227,29 @@ 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->type == PN_ARRAY) /* In array */ - && !(parent->u.as_array.described && !node->prev); /* Not the descriptor */ + if (!parent) return false; + if (parent->type == PN_ARRAY) return true; + if (parent->type == PN_ARRAY_DESCRIBED) return node->prev != 0; + return false; } /** 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->u.as_array.described; /* First node */ - return parent->u.as_array.described && (!pn_data_node(data, node->prev)->prev); + if (!node->prev) return parent->type != PN_ARRAY_DESCRIBED; + return (parent->type == PN_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->type == PN_LIST && parent->u.as_list.described; + if (!parent || parent->type != PN_LIST) return false; + pni_node_t *grandparent = pn_data_node(data, parent->parent); + if (!grandparent || grandparent->type != PN_DESCRIBED) return false; + // List is the body (value) if it's the second child (has prev sibling) + return parent->prev != 0; } typedef union { @@ -261,7 +269,7 @@ static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node) /** 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->u.as_array.type); + code = pn_type2code(encoder, parent->array_type); if (pn_is_first_in_array(data, parent, node)) { pn_encoder_writef8(encoder, code); } @@ -323,21 +331,22 @@ static int pni_encoder_enter(void *ctx, pn_data_t *data, pni_node_t *node) node->u.as_array.start = (uint32_t) encoder->position; // we'll backfill the size on exit encoder->position += 4; - pn_encoder_writef32(encoder, node->u.as_array.described ? node->children - 1 : node->children); - if (node->u.as_array.described) + bool described = (node->type == PN_ARRAY_DESCRIBED); + pn_encoder_writef32(encoder, described ? node->u.as_array.children_count - 1 : node->u.as_array.children_count); + if (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); + pn_encoder_writef32(encoder, node->u.as_list.children_count); return 0; case PNE_MAP32: node->u.as_map.start = (uint32_t) encoder->position; // we'll backfill the size later encoder->position += 4; - pn_encoder_writef32(encoder, node->children); + pn_encoder_writef32(encoder, node->u.as_map.children_count); return 0; default: return pn_error_format(pn_data_error(data), PN_ERR, "unrecognized encoding: %u", code); @@ -353,7 +362,7 @@ 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->type==PN_LIST && node->children-encoder->null_count==0 && !pn_is_in_array(data, parent, node)) { + if (node->type==PN_LIST && node->u.as_list.children_count-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; @@ -362,8 +371,10 @@ static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node) switch (node->type) { case PN_ARRAY: - 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)); + case PN_ARRAY_DESCRIBED: + if ((node->type == PN_ARRAY_DESCRIBED && node->u.as_array.children_count == 1) || + (node->type == PN_ARRAY && node->u.as_array.children_count == 0)) { + pn_encoder_writef8(encoder, pn_type2code(encoder, node->array_type)); } PN_FALLTHROUGH; case PN_LIST: @@ -377,7 +388,7 @@ static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node) pn_encoder_writef32(encoder, size); // Adjust count if (encoder->null_count) { - pn_encoder_writef32(encoder, node->children-encoder->null_count); + pn_encoder_writef32(encoder, pni_node_get_children(node)-encoder->null_count); } encoder->position = pos; encoder->null_count = 0; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
