improve catalog support; depends on amzn/ion-c#271
authorMichael Wallner <mike@php.net>
Wed, 22 Dec 2021 10:06:05 +0000 (11:06 +0100)
committerMichael Wallner <mike@php.net>
Wed, 22 Dec 2021 10:49:36 +0000 (11:49 +0100)
ion.c
ion_private.h
tests/Catalog.phpt
tests/Symbol/Shared/roundtrip.phpt [deleted file]
tests/Symbol/Table/Local.phpt [new file with mode: 0644]
tests/Symbol/Table/Shared.phpt [new file with mode: 0644]
tests/Symbol/Table/Shared/roundtrip.phpt [new file with mode: 0644]

diff --git a/ion.c b/ion.c
index 53b65dfbe667c3499f050379719d3ff528b91d7f..762ea91da0cef433295df028646753a8628bbd70 100644 (file)
--- a/ion.c
+++ b/ion.c
@@ -325,26 +325,7 @@ static ZEND_METHOD(ion_Catalog, add)
        php_ion_symbol_table *o_symtab = php_ion_obj(symbol_table, zo_symtab);
        php_ion_catalog_add_symbol_table(obj, o_symtab);
 }
-struct remove_symtab_ctx {
-       const char *name;
-       zend_bool deleted;
-};
-static int remove_symtab(zval *ztab, void *ctx)
-{
-       struct remove_symtab_ctx *rsc = ctx;
-       php_ion_symbol_table *tab = php_ion_obj(symbol_table, Z_OBJ_P(ztab));
-       if (tab && tab->tab) {
-               ION_STRING is;
-               if (IERR_OK == ion_symbol_table_get_name(tab->tab, &is)) {
-                       if (strcmp((const char *) is.value, rsc->name)) {
-                               return ZEND_HASH_APPLY_KEEP;
-                       }
-               }
-       }
-       rsc->deleted = true;
-       return ZEND_HASH_APPLY_REMOVE;
 
-}
 static ZEND_METHOD(ion_Catalog, remove)
 {
        php_ion_catalog *obj = php_ion_obj(catalog, Z_OBJ_P(ZEND_THIS));
@@ -364,12 +345,22 @@ static ZEND_METHOD(ion_Catalog, remove)
                if (zo_symtab) {
                        // fast path
                        zend_ulong idx = (uintptr_t) &zo_symtab->gc;
-                       RETURN_BOOL(SUCCESS == zend_hash_index_del(Z_ARRVAL_P(ztabs), idx));
+                       RETVAL_BOOL(SUCCESS == zend_hash_index_del(Z_ARRVAL_P(ztabs), idx));
+                       ION_CHECK(ion_catalog_release_symbol_table(obj->cat, php_ion_obj(symbol_table, zo_symtab)->tab));
                } else {
-                       // iterate over all symbol tables and delete any with matching name
-                       struct remove_symtab_ctx ctx = {zs_symtab->val, false};
-                       zend_hash_apply_with_argument(Z_ARRVAL_P(ztabs), remove_symtab, &ctx);
-                       RETURN_BOOL(ctx.deleted);
+                       bool deleted = false;
+                       ION_SYMBOL_TABLE *tab;
+                       ION_STRING is;
+                       ion_string_from_zend(&is, zs_symtab);
+                       do {
+                               tab = NULL;
+                               ION_CHECK(ion_catalog_find_best_match(obj->cat, &is, 0, &tab));
+                               if (tab) {
+                                       ION_CHECK(ion_catalog_release_symbol_table(obj->cat, tab));
+                                       deleted = true;
+                               }
+                       } while(tab);
+                       RETVAL_BOOL(deleted);
                }
        }
 }
index 3f13897008e2b3732cd6fe5eccc32149c2b61375..1bc1c1518dab1c59af7a3f0032a8e28374a193c1 100644 (file)
@@ -1222,13 +1222,56 @@ static inline iERR php_ion_writer_buffer_handler(struct _ion_user_stream *user)
        return IERR_OK;
 }
 
+static inline ION_COLLECTION *php_ion_catalog_collection(php_ion_catalog *cat)
+{
+       /* do not look too close */
+       struct {
+               void *owner;
+               ION_SYMBOL_TABLE *sys;
+               ION_COLLECTION collection;
+       } *cat_ptr = (void *) cat->cat;
+       return &cat_ptr->collection;
+}
+
+static inline void php_ion_writer_options_init_shared_imports(php_ion_writer_options *opt)
+{
+       php_ion_catalog *cat = php_ion_obj(catalog, opt->cat);
+       OBJ_CHECK(cat);
+
+       ION_CHECK(ion_writer_options_initialize_shared_imports(&opt->opt));
+
+       ION_COLLECTION *col = php_ion_catalog_collection(cat);
+       if (!ION_COLLECTION_IS_EMPTY(col)) {
+               // holy, nah, forget it batman...
+#ifndef IPCN_pNODE_TO_pDATA
+# define IPCN_pNODE_TO_pDATA(x)    (&((x)->_data[0]))
+#endif
+               ION_COLLECTION_CURSOR cur;
+               ION_COLLECTION_OPEN(col, cur);
+               while (cur) {
+                       ION_SYMBOL_TABLE **ptr;
+                       ION_COLLECTION_NEXT(cur, ptr);
+                       if (*ptr) {
+                               ION_CHECK(ion_writer_options_add_shared_imports_symbol_tables(&opt->opt, ptr, 1));
+                       } else {
+                               break;
+                       }
+               }
+       }
+}
+
 static inline void php_ion_writer_ctor(php_ion_writer *obj)
 {
+       php_ion_writer_options *opt = NULL;
+
        if (obj->opt) {
                update_property_obj(&obj->std, ZEND_STRL("options"), obj->opt);
+               opt = php_ion_obj(writer_options, obj->opt);
+               if (opt->cat) {
+                       php_ion_writer_options_init_shared_imports(opt);
+               }
        }
 
-       php_ion_writer_options *opt = php_ion_obj(writer_options, obj->opt);
        ION_STREAM_HANDLER h;
        if (obj->type == STREAM_WRITER) {
                h = php_ion_writer_stream_handler;
@@ -1238,6 +1281,7 @@ static inline void php_ion_writer_ctor(php_ion_writer *obj)
                php_ion_writer_buffer_init(obj);
        }
 
+
        ION_CHECK(ion_writer_open_stream(&obj->writer, h, obj, opt ? &opt->opt : NULL));
        OBJ_CHECK(obj);
 }
@@ -1247,6 +1291,12 @@ static inline void php_ion_writer_dtor(php_ion_writer *obj)
        if (obj->writer) {
                ion_writer_close(obj->writer);
        }
+       if (obj->opt) {
+               php_ion_writer_options *opt = php_ion_obj(writer_options, obj->opt);
+               if (opt->cat) {
+                       ion_writer_options_close_shared_imports(&opt->opt);
+               }
+       }
        if (obj->type == STREAM_WRITER) {
                if (obj->stream.buf.value) {
                        efree(obj->stream.buf.value);
index 133f161976e66f8565aa069f4046d1a5531aa2c4..d5ba180df3b27d612b14d02e0248da53aecbb8f6 100644 (file)
@@ -20,6 +20,8 @@ var_dump($c);
 var_dump($c->find("shared", 1));
 var_dump($c->findBest("shared"));
 
+$c->remove("shared");
+var_dump(count($c));
 ?>
 DONE
 --EXPECTF--
@@ -111,4 +113,5 @@ object(ion\Symbol\Table\Shared)#%d (3) {
   array(0) {
   }
 }
+int(1)
 DONE
diff --git a/tests/Symbol/Shared/roundtrip.phpt b/tests/Symbol/Shared/roundtrip.phpt
deleted file mode 100644 (file)
index c9e2b93..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
---TEST--
-Symbol\Table\Shared/roundtrip
---EXTENSIONS--
-ion
---FILE--
-TEST
-<?php
-$s = '$ion_shared_symbol_table::{name:"shared",version:1,symbols:["foo","bar","baz"]}';
-$t = new ion\Symbol\Table\Shared(name: "shared", symbols: ["foo","bar","baz"]);
-var_dump(
-       ion\serialize(
-               ion\unserialize(
-                       ion\serialize(
-                               ion\unserialize(
-                                       ion\serialize($t)
-                               )
-                       )
-               )
-       )
-);
-
-var_dump(
-       ion\unserialize(
-               ion\serialize(
-                       ion\unserialize(
-                               ion\serialize(
-                                       ion\unserialize($s)
-                               )
-                       )
-               )
-       )
-);
-?>
-DONE
---EXPECTF--
-TEST
-string(79) "$ion_shared_symbol_table::{name:"shared",version:1,symbols:["foo","bar","baz"]}"
-object(ion\Symbol\Table\Shared)#%d (3) {
-  ["name"]=>
-  string(6) "shared"
-  ["version"]=>
-  int(1)
-  ["symbols":"ion\Symbol\Table\Shared":private]=>
-  array(0) {
-  }
-}
-DONE
diff --git a/tests/Symbol/Table/Local.phpt b/tests/Symbol/Table/Local.phpt
new file mode 100644 (file)
index 0000000..5dc7778
--- /dev/null
@@ -0,0 +1,79 @@
+--TEST--
+ion\Symbol\Table\Local
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+
+$w = new ion\Writer\Buffer\Writer($buf,
+       new ion\Writer\Options(outputBinary: true));
+
+$w->writeSymbol("local1");
+$w->writeSymbol("local1");
+$w->writeSymbol("local2");
+$w->writeSymbol("local2");
+
+$w->finish();
+
+foreach (str_split($buf, 8) as $line) {
+       printf("%-26s", chunk_split(bin2hex($line), 2, " "));
+       foreach (str_split($line) as $byte) {
+               echo ctype_print($byte) ? $byte : ".";
+       }
+       echo "\n";
+}
+echo "\n";
+
+$u = new ion\Unserializer\PHP(multiSequence: true);
+var_dump($u($buf));
+
+?>
+DONE
+--EXPECTF--
+TEST
+e0 01 00 ea ee 95 81 83   ........
+de 91 87 be 8e 86 6c 6f   ......lo
+63 61 6c 31 86 6c 6f 63   cal1.loc
+61 6c 32 71 0a 71 0a 71   al2q.q.q
+0b 71 0b                  .q.
+
+array(4) {
+  [0]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(6) "local1"
+    ["sid"]=>
+    int(10)
+    ["importLocation"]=>
+    NULL
+  }
+  [1]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(6) "local1"
+    ["sid"]=>
+    int(10)
+    ["importLocation"]=>
+    NULL
+  }
+  [2]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(6) "local2"
+    ["sid"]=>
+    int(11)
+    ["importLocation"]=>
+    NULL
+  }
+  [3]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(6) "local2"
+    ["sid"]=>
+    int(11)
+    ["importLocation"]=>
+    NULL
+  }
+}
+DONE
diff --git a/tests/Symbol/Table/Shared.phpt b/tests/Symbol/Table/Shared.phpt
new file mode 100644 (file)
index 0000000..2d51c48
--- /dev/null
@@ -0,0 +1,164 @@
+--TEST--
+ion\Symbol\Table\Shared
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+
+$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->writeSymbol("shared1");
+$w->writeSymbol("shared1");
+$w->writeSymbol("shared2");
+$w->writeSymbol("shared2");
+
+$w->finish();
+
+foreach (str_split($buf, 8) as $line) {
+       printf("%-26s", chunk_split(bin2hex($line), 2, " "));
+       foreach (str_split($line) as $byte) {
+               echo ctype_print($byte) ? $byte : ".";
+       }
+       echo "\n";
+}
+echo "\n";
+
+$u = new ion\Unserializer\PHP(multiSequence: true);
+var_dump($u($buf));
+
+$u = new ion\Unserializer\PHP(multiSequence: true,
+       readerOptions: new ion\Reader\Options(catalog: $c));
+var_dump($u($buf));
+
+?>
+DONE
+--EXPECTF--
+TEST
+e0 01 00 ea ee 97 81 83   ........
+de 93 86 be 90 de 8e 84   ........
+86 73 68 61 72 65 64 85   .shared.
+21 01 88 21 02 71 0a 71   !..!.q.q
+0a 71 0b 71 0b            .q.q.
+
+array(4) {
+  [0]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(0) ""
+    ["sid"]=>
+    int(10)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(1)
+    }
+  }
+  [1]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(0) ""
+    ["sid"]=>
+    int(10)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(1)
+    }
+  }
+  [2]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(0) ""
+    ["sid"]=>
+    int(11)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(2)
+    }
+  }
+  [3]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(0) ""
+    ["sid"]=>
+    int(11)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(2)
+    }
+  }
+}
+on_context_change
+array(4) {
+  [0]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(7) "shared1"
+    ["sid"]=>
+    int(10)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(1)
+    }
+  }
+  [1]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(7) "shared1"
+    ["sid"]=>
+    int(10)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(1)
+    }
+  }
+  [2]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(7) "shared2"
+    ["sid"]=>
+    int(11)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(2)
+    }
+  }
+  [3]=>
+  object(ion\Symbol)#%d (3) {
+    ["value"]=>
+    string(7) "shared2"
+    ["sid"]=>
+    int(11)
+    ["importLocation"]=>
+    object(ion\Symbol\ImportLocation)#%d (2) {
+      ["name"]=>
+      string(6) "shared"
+      ["location"]=>
+      int(2)
+    }
+  }
+}
+DONE
diff --git a/tests/Symbol/Table/Shared/roundtrip.phpt b/tests/Symbol/Table/Shared/roundtrip.phpt
new file mode 100644 (file)
index 0000000..c9e2b93
--- /dev/null
@@ -0,0 +1,47 @@
+--TEST--
+Symbol\Table\Shared/roundtrip
+--EXTENSIONS--
+ion
+--FILE--
+TEST
+<?php
+$s = '$ion_shared_symbol_table::{name:"shared",version:1,symbols:["foo","bar","baz"]}';
+$t = new ion\Symbol\Table\Shared(name: "shared", symbols: ["foo","bar","baz"]);
+var_dump(
+       ion\serialize(
+               ion\unserialize(
+                       ion\serialize(
+                               ion\unserialize(
+                                       ion\serialize($t)
+                               )
+                       )
+               )
+       )
+);
+
+var_dump(
+       ion\unserialize(
+               ion\serialize(
+                       ion\unserialize(
+                               ion\serialize(
+                                       ion\unserialize($s)
+                               )
+                       )
+               )
+       )
+);
+?>
+DONE
+--EXPECTF--
+TEST
+string(79) "$ion_shared_symbol_table::{name:"shared",version:1,symbols:["foo","bar","baz"]}"
+object(ion\Symbol\Table\Shared)#%d (3) {
+  ["name"]=>
+  string(6) "shared"
+  ["version"]=>
+  int(1)
+  ["symbols":"ion\Symbol\Table\Shared":private]=>
+  array(0) {
+  }
+}
+DONE