From 37a4da6adba5f992760e7bda657704cb5ec3dc4b Mon Sep 17 00:00:00 2001 From: Michael Wallner Date: Wed, 12 Jan 2022 11:02:03 +0100 Subject: [PATCH] improve buffer writer --- ion.c | 3 +- ion_private.h | 65 ++++++++++++++++++++++++++-------------- tests/Writer/Buffer.phpt | 18 ++++++++--- 3 files changed, 57 insertions(+), 29 deletions(-) diff --git a/ion.c b/ion.c index 40c7ea1..28d5a5c 100644 --- a/ion.c +++ b/ion.c @@ -1624,8 +1624,7 @@ static ZEND_METHOD(ion_Writer_Buffer_Writer, getBuffer) ZEND_PARSE_PARAMETERS_NONE(); - smart_str_0(&obj->buffer.str.s); - RETVAL_STR_COPY(obj->buffer.str.s); + RETVAL_STR(php_ion_writer_buffer_copy(obj)); } static ZEND_METHOD(ion_Writer_Buffer_Writer, resetBuffer) { diff --git a/ion_private.h b/ion_private.h index 1f40eb4..aea7c7d 100644 --- a/ion_private.h +++ b/ion_private.h @@ -1364,15 +1364,20 @@ LOCAL void php_ion_writer_stream_init(php_ion_writer *obj, php_ion_writer_option obj->stream.buf.value = emalloc(obj->stream.buf.length); } -LOCAL void php_ion_writer_buffer_init(php_ion_writer *obj) +LOCAL void php_ion_writer_buffer_offer(php_ion_writer *obj) { - smart_str_alloc(&obj->buffer.str, 0, false); if (obj->buffer.usr) { obj->buffer.usr->curr = (BYTE *) &obj->buffer.str.s->val[obj->buffer.str.s->len]; obj->buffer.usr->limit = obj->buffer.usr->curr + obj->buffer.str.a - obj->buffer.str.s->len; } } +LOCAL void php_ion_writer_buffer_init(php_ion_writer *obj) +{ + smart_str_alloc(&obj->buffer.str, 0, false); + php_ion_writer_buffer_offer(obj); +} + LOCAL void php_ion_writer_buffer_reset(php_ion_writer *obj) { smart_str_free(&obj->buffer.str); @@ -1380,34 +1385,50 @@ LOCAL void php_ion_writer_buffer_reset(php_ion_writer *obj) php_ion_writer_buffer_init(obj); } +LOCAL zend_string *php_ion_writer_buffer_copy(php_ion_writer *obj) +{ + if (obj->buffer.usr) { + // ensure that brain-dead ion_stream interface calls us again + obj->buffer.usr->curr = NULL; + obj->buffer.usr->limit = NULL; + } + smart_str_0(&obj->buffer.str); + return zend_string_copy(obj->buffer.str.s); +} + +LOCAL void php_ion_writer_buffer_separate(php_ion_writer *obj, bool grow) +{ + // see zend_string_separate and smart_str_erealloc + zend_string *old_str = obj->buffer.str.s; + zend_string *new_str = zend_string_alloc(obj->buffer.str.a << grow, false); + memcpy(new_str->val, old_str->val, new_str->len = old_str->len); + zend_string_release(old_str); + obj->buffer.str.s = new_str; +} + LOCAL void php_ion_writer_buffer_grow(php_ion_writer *obj) { - if (GC_REFCOUNT(obj->buffer.str.s) > 1) { - zend_string *keep = obj->buffer.str.s; - obj->buffer.str.s = NULL; - smart_str_alloc(&obj->buffer.str, obj->buffer.str.a << 1, 0); - memcpy(obj->buffer.str.s->val, keep->val, keep->len + 1); - obj->buffer.str.s->len = keep->len; - zend_string_release(keep); - } else { - smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1); + if (obj->buffer.usr && obj->buffer.usr->curr) { + obj->buffer.str.s->len = obj->buffer.usr->curr - (BYTE *) obj->buffer.str.s->val; + } + if (obj->buffer.usr && obj->buffer.usr->curr && obj->buffer.usr->curr == obj->buffer.usr->limit) { + if (UNEXPECTED(GC_REFCOUNT(obj->buffer.str.s) > 1)) { + php_ion_writer_buffer_separate(obj, true); + } else { + smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1); + } + } else if (UNEXPECTED(GC_REFCOUNT(obj->buffer.str.s) > 1)) { + php_ion_writer_buffer_separate(obj, false); } + php_ion_writer_buffer_offer(obj); } + LOCAL iERR php_ion_writer_buffer_handler(struct _ion_user_stream *user) { php_ion_writer *writer = (php_ion_writer *) user->handler_state; writer->buffer.usr = user; - - if (user->curr) { - writer->buffer.str.s->len = user->curr - (BYTE *) writer->buffer.str.s->val; - if (user->limit == user->curr) { - php_ion_writer_buffer_grow(writer); - } - } - user->curr = (BYTE *) &writer->buffer.str.s->val[writer->buffer.str.s->len]; - user->limit = user->curr + writer->buffer.str.a - writer->buffer.str.s->len; - + php_ion_writer_buffer_grow(writer); return IERR_OK; } @@ -1428,8 +1449,6 @@ LOCAL void php_ion_writer_options_init_shared_imports(php_ion_writer_options *op ION_COLLECTION_NEXT(cur, ptr); if (*ptr) { ION_CHECK(ion_writer_options_add_shared_imports_symbol_tables(&opt->opt, ptr, 1)); - } else { - break; } } } diff --git a/tests/Writer/Buffer.phpt b/tests/Writer/Buffer.phpt index 4eebf31..d977b50 100644 --- a/tests/Writer/Buffer.phpt +++ b/tests/Writer/Buffer.phpt @@ -7,27 +7,37 @@ TEST writeTypedNull(ion\Type::Int); +$w->flush(); +var_dump($w->getBuffer()); +$ref=$w->getBuffer(); +// realloc for ($i = 0; $i < 100; ++$i) $w->writeTypedNull(ion\Type::Int); $w->flush(); -echo $w->getBuffer(),"\n"; +var_dump($ref, $w->getBuffer()); $w->resetBuffer(); var_dump($w->getBuffer()); $w->writeSymbol("bar"); $w->flush(); var_dump($w->getBuffer()); + $w->resetBuffer(); +$ref=$w->getBuffer(); // realloc for ($i = 0; $i < 100; ++$i) $w->writeTypedNull(ion\Type::Int); $w->flush(); -echo $w->getBuffer(),"\n"; +echo $ref,"----",$w->getBuffer(),"\n"; ?> DONE --EXPECTF-- TEST -null.int%r( null.int)*%r +string(89) "null.int%r( null.int){9}%r" +string(89) "null.int%r( null.int){9}%r" +string(989) "null.int%r( null.int){109}%r" string(0) "" string(4) " bar" - null.int%r( null.int)*%r +---- null.int%r( null.int){99}%r DONE -- 2.30.2