seriously simplify the buffer writer by not accepting a ref to a buffer
authorMichael Wallner <mike@php.net>
Tue, 11 Jan 2022 21:08:17 +0000 (22:08 +0100)
committerMichael Wallner <mike@php.net>
Tue, 11 Jan 2022 21:08:17 +0000 (22:08 +0100)
ion.c
ion.stub.php
ion_arginfo.h
ion_private.h
tests/Symbol/Table/Local.phpt
tests/Symbol/Table/Shared.phpt
tests/Writer/Buffer.phpt

diff --git a/ion.c b/ion.c
index 5712668a20b182523fe76d144f1c3ae647210142..3cd4684d82ab84f1c08b4e99b8cdb9dfff1cc27c 100644 (file)
--- a/ion.c
+++ b/ion.c
@@ -1615,17 +1615,12 @@ static ZEND_METHOD(ion_Writer_Buffer_Writer, __construct)
        php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
        PTR_CHECK(obj);
 
-       zval *ref;
-       ZEND_PARSE_PARAMETERS_START(1, 2)
-               Z_PARAM_ZVAL(ref)
+       ZEND_PARSE_PARAMETERS_START(0, 1)
                Z_PARAM_OPTIONAL
                Z_PARAM_OBJ_OF_CLASS_OR_NULL(obj->opt, ce_Writer_Options)
        ZEND_PARSE_PARAMETERS_END();
 
        obj->type = BUFFER_WRITER;
-       ZVAL_COPY(&obj->buffer.val, ref);
-       zval_dtor(Z_REFVAL_P(ref));
-
        php_ion_writer_ctor(obj);
 }
 static ZEND_METHOD(ion_Writer_Buffer_Writer, getBuffer)
@@ -1635,7 +1630,16 @@ static ZEND_METHOD(ion_Writer_Buffer_Writer, getBuffer)
 
        ZEND_PARSE_PARAMETERS_NONE();
 
-       RETVAL_STR(zend_string_dup(obj->buffer.str.s, 0));
+       RETVAL_STR_COPY(obj->buffer.str.s);
+}
+static ZEND_METHOD(ion_Writer_Buffer_Writer, resetBuffer)
+{
+       php_ion_writer *obj = php_ion_obj(writer, Z_OBJ_P(ZEND_THIS));
+       OBJ_CHECK(obj);
+
+       ZEND_PARSE_PARAMETERS_NONE();
+
+       php_ion_writer_buffer_reset(obj);
 }
 static ZEND_METHOD(ion_Writer_Stream_Writer, __construct)
 {
index cc9f28892a8a9d40de6104a92099ef8e4c9f02b2..7818dde981e403198b45754e5e72935e38deb68b 100644 (file)
@@ -511,20 +511,17 @@ abstract class Writer implements \ion\Writer {
 namespace ion\Writer;
 interface Buffer extends \ion\Writer {
     public function getBuffer() : string;
+    public function resetBuffer() : void;
 }
 
 namespace ion\Writer\Buffer;
 class Writer extends \ion\Writer\Writer implements \ion\Writer\Buffer {
-    /** @param ref $buffer */
     public function __construct(
-        ?string &$buffer,
         ?\ion\Writer\Options $options = null,
     ) {}
 
-    /**
-     * @return string a _copy_ of $buffer passed to the constructor
-     */
     public function getBuffer() : string {}
+    public function resetBuffer() : void {}
 }
 
 namespace ion\Writer;
index bfd758e5975d3b739a731f2d9dd6c5a01258d1f9..5015b690788c3574b2d93f359b3c03eaf4118752 100644 (file)
@@ -1,5 +1,5 @@
 /* This is a generated file, edit the .stub.php file instead.
- * Stub hash: 8cd99962a32b5321624d6cb043fb60ff13f93738 */
+ * Stub hash: aafe212ff9dd7fd15753fa5b6a3c127a51073241 */
 
 ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_ion_Symbol_Table_PHP, 0, 0, ion\\Symbol\\Table, 0)
 ZEND_END_ARG_INFO()
@@ -495,13 +495,16 @@ ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Writer_Buffer_getBuffer arginfo_class_ion_Symbol_Enum_toString
 
-ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Writer_Buffer_Writer___construct, 0, 0, 1)
-       ZEND_ARG_TYPE_INFO(1, buffer, IS_STRING, 1)
+#define arginfo_class_ion_Writer_Buffer_resetBuffer arginfo_class_ion_Reader_Reader_rewind
+
+ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Writer_Buffer_Writer___construct, 0, 0, 0)
        ZEND_ARG_OBJ_INFO_WITH_DEFAULT_VALUE(0, options, ion\\Writer\\Options, 1, "null")
 ZEND_END_ARG_INFO()
 
 #define arginfo_class_ion_Writer_Buffer_Writer_getBuffer arginfo_class_ion_Symbol_Enum_toString
 
+#define arginfo_class_ion_Writer_Buffer_Writer_resetBuffer arginfo_class_ion_Reader_Reader_rewind
+
 #define arginfo_class_ion_Writer_Stream_getStream arginfo_class_ion_Symbol_Table_Local___construct
 
 ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ion_Writer_Stream_Writer___construct, 0, 0, 1)
@@ -636,6 +639,7 @@ static ZEND_METHOD(ion_Writer_Writer, writeOne);
 static ZEND_METHOD(ion_Writer_Writer, writeAll);
 static ZEND_METHOD(ion_Writer_Buffer_Writer, __construct);
 static ZEND_METHOD(ion_Writer_Buffer_Writer, getBuffer);
+static ZEND_METHOD(ion_Writer_Buffer_Writer, resetBuffer);
 static ZEND_METHOD(ion_Writer_Stream_Writer, __construct);
 static ZEND_METHOD(ion_Writer_Stream_Writer, getStream);
 static ZEND_METHOD(ion_Serializer_PHP, __construct);
@@ -960,6 +964,7 @@ static const zend_function_entry class_ion_Writer_Writer_methods[] = {
 
 static const zend_function_entry class_ion_Writer_Buffer_methods[] = {
        ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer_Buffer, getBuffer, arginfo_class_ion_Writer_Buffer_getBuffer, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
+       ZEND_ABSTRACT_ME_WITH_FLAGS(ion_Writer_Buffer, resetBuffer, arginfo_class_ion_Writer_Buffer_resetBuffer, ZEND_ACC_PUBLIC|ZEND_ACC_ABSTRACT)
        ZEND_FE_END
 };
 
@@ -967,6 +972,7 @@ static const zend_function_entry class_ion_Writer_Buffer_methods[] = {
 static const zend_function_entry class_ion_Writer_Buffer_Writer_methods[] = {
        ZEND_ME(ion_Writer_Buffer_Writer, __construct, arginfo_class_ion_Writer_Buffer_Writer___construct, ZEND_ACC_PUBLIC)
        ZEND_ME(ion_Writer_Buffer_Writer, getBuffer, arginfo_class_ion_Writer_Buffer_Writer_getBuffer, ZEND_ACC_PUBLIC)
+       ZEND_ME(ion_Writer_Buffer_Writer, resetBuffer, arginfo_class_ion_Writer_Buffer_Writer_resetBuffer, ZEND_ACC_PUBLIC)
        ZEND_FE_END
 };
 
index b168f900ea3b3a2e8f9624ec91242bdd882d837e..928b82665e5745c67f4f072c2b71b9ce02ccc1d1 100644 (file)
@@ -11,6 +11,7 @@
 */
 
 #include "php.h"
+#include "ext/standard/php_var.h"
 #include "ext/date/php_date.h"
 
 #if PHP_DEBUG
@@ -1333,7 +1334,6 @@ typedef struct php_ion_writer {
        } type;
        union {
                struct {
-                       zval val;
                        smart_str str;
                } buffer;
                struct {
@@ -1360,18 +1360,6 @@ LOCAL iERR php_ion_writer_stream_handler(struct _ion_user_stream *user)
        return IERR_OK;
 }
 
-#define REF_STR() do { \
-       ZVAL_NEW_STR(ref, obj->buffer.str.s); \
-       GC_ADDREF(obj->buffer.str.s); \
-} while (0)
-
-#define NEW_REF_STR() do {\
-       if (Z_STR_P(ref) != obj->buffer.str.s) { \
-               zval_ptr_dtor(ref); \
-               REF_STR(); \
-       } \
-} while(0)
-
 LOCAL void php_ion_writer_stream_init(php_ion_writer *obj, php_ion_writer_options *opt)
 {
        PTR_CHECK(obj->stream.ptr);
@@ -1380,46 +1368,34 @@ LOCAL void php_ion_writer_stream_init(php_ion_writer *obj, php_ion_writer_option
        obj->stream.buf.length = opt ? opt->opt.allocation_page_size : 0x1000;
        obj->stream.buf.value = emalloc(obj->stream.buf.length);
 }
+
 LOCAL void php_ion_writer_buffer_init(php_ion_writer *obj)
 {
-       zval *ref = &obj->buffer.val;
-       ZVAL_DEREF(ref);
+       smart_str_alloc(&obj->buffer.str, 0, 0);
+       smart_str_0(&obj->buffer.str);
+}
 
+LOCAL void php_ion_writer_buffer_reset(php_ion_writer *obj)
+{
+       smart_str_free(&obj->buffer.str);
+       memset(&obj->buffer.str, 0, sizeof(obj->buffer.str));
        smart_str_alloc(&obj->buffer.str, 0, 0);
        smart_str_0(&obj->buffer.str);
-       REF_STR();
 }
 
 LOCAL void php_ion_writer_buffer_grow(php_ion_writer *obj)
 {
-       zval *ref = &obj->buffer.val;
-       ZVAL_DEREF(ref);
-
-       switch (GC_REFCOUNT(obj->buffer.str.s)) {
-       case 2:
-               // nothing to do
-               break;
-       case 1:
-               // we've been separated
-               GC_ADDREF(obj->buffer.str.s);
-               break;
-       default:
-               // we have to separate
-               fprintf(stderr, "SEPARATE\n");
-               obj->buffer.str.s = zend_string_dup(obj->buffer.str.s, 0);
-               break;
-       }
-
-       zend_string *old = obj->buffer.str.s;
-       GC_DELREF(old);
-       smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1);
-       if (old == obj->buffer.str.s) {
-               GC_ADDREF(old);
-       } else if(old == Z_STR_P(ref)) {
-               ZVAL_NULL(ref);
+       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;
+               smart_str_0(&obj->buffer.str);
+               zend_string_release(keep);
+       } else {
+               smart_str_erealloc(&obj->buffer.str, obj->buffer.str.a << 1);
        }
-
-       NEW_REF_STR();
 }
 
 LOCAL iERR php_ion_writer_buffer_handler(struct _ion_user_stream *user)
@@ -1512,7 +1488,6 @@ LOCAL void php_ion_writer_dtor(php_ion_writer *obj)
                        smart_str_0(&obj->buffer.str);
                        zend_string_release(obj->buffer.str.s);
                }
-               zval_ptr_dtor(&obj->buffer.val);
        }
 }
 
index 25b0cb5e36e2a62ad66bf836cc97472b342faaec..9c6b03ecb869466a6b4171cbfe3e00c601dca13e 100644 (file)
@@ -6,8 +6,7 @@ ion
 TEST
 <?php
 
-$w = new ion\Writer\Buffer\Writer($buf,
-       new ion\Writer\Options(outputBinary: true));
+$w = new ion\Writer\Buffer\Writer(new ion\Writer\Options(outputBinary: true));
 
 $w->writeSymbol("local1");
 $w->writeSymbol("local1");
@@ -16,7 +15,7 @@ $w->writeSymbol("local2");
 
 $w->finish();
 
-foreach (str_split($buf, 8) as $line) {
+foreach (str_split($w->getBuffer(), 8) as $line) {
        printf("%-26s", chunk_split(bin2hex($line), 2, " "));
        foreach (str_split($line) as $byte) {
                echo $byte >= ' ' && $byte <= '~' ? $byte : ".";
@@ -26,7 +25,7 @@ foreach (str_split($buf, 8) as $line) {
 echo "\n";
 
 $u = new ion\Unserializer\PHP(multiSequence: true);
-var_dump($u->unserialize($buf));
+var_dump($u->unserialize($w->getBuffer()));
 
 ?>
 DONE
index b6a2a489b71e652d82de3b4e29d5e7fe13a65312..1a052dbbf0e01ff393748b1d72e6abc1f59fceec 100644 (file)
@@ -8,8 +8,7 @@ TEST
 
 $c = new ion\Catalog;
 $c->add(new ion\Symbol\Table\Shared("shared", 1, ["shared1", "shared2"]));
-$w = new ion\Writer\Buffer\Writer($buf,
-       new ion\Writer\Options(catalog: $c, outputBinary: true));
+$w = new ion\Writer\Buffer\Writer(new ion\Writer\Options(catalog: $c, outputBinary: true));
 
 $w->writeSymbol("shared1");
 $w->writeSymbol("shared1");
@@ -18,7 +17,7 @@ $w->writeSymbol("shared2");
 
 $w->finish();
 
-foreach (str_split($buf, 8) as $line) {
+foreach (str_split($w->getBuffer(), 8) as $line) {
        printf("%-26s", chunk_split(bin2hex($line), 2, " "));
        foreach (str_split($line) as $byte) {
                echo $byte >= ' ' && $byte <= '~' ? $byte : ".";
@@ -28,7 +27,7 @@ foreach (str_split($buf, 8) as $line) {
 echo "\n";
 
 $u = new ion\Unserializer\PHP(multiSequence: true);
-var_dump($s = $u->unserialize($buf));
+var_dump($s = $u->unserialize($w->getBuffer()));
 
 foreach ($s as $sym) {
        /** @var ion\Symbol $sym */
@@ -42,7 +41,7 @@ $u = new ion\Unserializer\PHP(multiSequence: true,
        readerOptions: new ion\Reader\Options(
                catalog: $c,
                onContextChange: fn(ion\Reader $r) => print("on_context_change\n")));
-var_dump($u->unserialize($buf));
+var_dump($u->unserialize($w->getBuffer()));
 
 ?>
 DONE
index aaa5b01c71f7268cd22375295d9a0bbf25748d2b..d9c870f85532ffe81d8e848e5cf83208e49f0e44 100644 (file)
@@ -6,16 +6,21 @@ ion
 TEST
 <?php
 
-$w = new ion\Writer\Buffer\Writer($buf);
-for ($i = 0; $i < 100; ++$i) $w->writeTypedNull(ion\Type::Int);
-var_dump($buf === $w->getBuffer());
+$w = new ion\Writer\Buffer\Writer;
+for ($i = 0; $i < 100; ++$i)
+       $w->writeTypedNull(ion\Type::Int);
+$w->flush();
+echo $w->getBuffer(),"\n";
+$w->resetBuffer();
+var_dump($w->getBuffer());
+$w->writeSymbol("bar");
 $w->finish();
-echo $buf;
+var_dump($w->getBuffer());
 ?>
-
 DONE
 --EXPECTF--
 TEST
-bool(true)
 null.int%r( null.int)*%r
+string(0) ""
+string(3) "bar"
 DONE