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 55c98c724d1f5e9141dfc2e7b5e121683449f526 Author: Andrew Stitcher <[email protected]> AuthorDate: Tue Jul 21 02:16:31 2026 -0400 PROTON-2958: Implement small encoding in pn_data_t for lists/maps/arrays We do this by shifting back the content if we detect it is small enough at the point where we would go and back fill the size. A major limitation of this approach is that arrays have to contain identical typecodes so we assume that everything in one cannot be shortened to avoid a mix of typecodes. --- c/src/core/encoder.c | 52 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 8 deletions(-) diff --git a/c/src/core/encoder.c b/c/src/core/encoder.c index b2a6c4136..502a3a86f 100644 --- a/c/src/core/encoder.c +++ b/c/src/core/encoder.c @@ -382,15 +382,51 @@ static int pni_encoder_exit(void *ctx, pn_data_t *data, pni_node_t *node) pos = encoder->position; /* 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, pni_node_get_children(node)-encoder->null_count); + + /* content_size: bytes written after the 8-byte *32 header (size+count fields) */ + size_t content_size = pos - start - 8; + uint32_t effective_count = pni_node_get_children(node) - encoder->null_count; + /* Use *8 encoding when content and count both fit in a byte. + * Excluded cases: + * - described arrays (constructor byte sequence is more complex) + * - any compound that is itself an element of an array: all elements in + * an array share the constructor type code (e.g. PNE_LIST32), so each + * element must be encoded in the *32 format the constructor declared. */ + bool can_be_small = content_size <= 255 && effective_count <= 255 + && !(node->type == PN_ARRAY_DESCRIBED) + && !pn_is_in_array(data, parent, node); + if (can_be_small) { + /* Slide only when all *32 content bytes were actually written into the + * buffer. If content overflowed (pos > encoder->size) the bytes past + * the end were never written; memmove would read uninitialised memory, + * and claiming a smaller position would fool pn_encoder_encode into + * reporting success with corrupt bytes. In the overflow case keep the + * large position so the caller retries with a bigger buffer; on the + * retry the full content will fit and the slide will execute correctly. + * The size-pass (encoder->output == NULL) has no buffer limit so the + * slide always executes there, giving the correct smaller size. */ + if (!encoder->output || start + 8 + content_size <= encoder->size) { + if (encoder->output) { + encoder->output[start - 1] -= 0x10; + encoder->output[start] = (uint8_t)(1 + content_size); + encoder->output[start + 1] = (uint8_t)effective_count; + memmove(encoder->output + start + 2, encoder->output + start + 8, content_size); + } + encoder->position = start + 2 + content_size; + } else { + /* Overflow: report the large position so pn_encoder_encode detects it */ + encoder->position = pos; + } + } else { + /* Backfill the 32-bit size field; size includes the 4-byte count field */ + encoder->position = start; + pn_encoder_writef32(encoder, pos - start - 4); + /* Adjust count field if trailing nulls were elided */ + if (encoder->null_count) { + pn_encoder_writef32(encoder, effective_count); + } + encoder->position = pos; } - encoder->position = pos; encoder->null_count = 0; return 0; } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
