+static ZEND_METHOD(ion_Symbol_Enum, toSymbol)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ zval *zc = zend_enum_fetch_case_name(Z_OBJ_P(ZEND_THIS));
+ PTR_CHECK(zc);
+
+ zval *zsym = php_ion_global_symbol_fetch_by_enum(Z_STR_P(zc));
+ PTR_CHECK(zsym);
+ RETVAL_ZVAL(zsym, 1, 0);
+}
+static ZEND_METHOD(ion_Symbol_Enum, toSID)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ zval *zc = zend_enum_fetch_case_name(Z_OBJ_P(ZEND_THIS));
+ PTR_CHECK(zc);
+
+ zval *zsym = php_ion_global_symbol_fetch_by_enum(Z_STR_P(zc));
+ PTR_CHECK(zsym);
+
+ zval tmp;
+ RETVAL_ZVAL(zend_read_property(Z_OBJCE_P(zsym), Z_OBJ_P(zsym), ZEND_STRL("sid"), 0, &tmp), 1, 0);
+}
+static ZEND_METHOD(ion_Symbol_Enum, toString)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ zval *zc = zend_enum_fetch_case_name(Z_OBJ_P(ZEND_THIS));
+ PTR_CHECK(zc);
+
+ zval *zsym = php_ion_global_symbol_fetch_by_enum(Z_STR_P(zc));
+ PTR_CHECK(zsym);
+
+ zval tmp;
+ RETVAL_ZVAL(zend_read_property(Z_OBJCE_P(zsym), Z_OBJ_P(zsym), ZEND_STRL("value"), 0, &tmp), 1, 0);
+}
+static ZEND_FUNCTION(ion_Symbol_Table_System)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ object_init_ex(return_value, ce_Symbol_Table_Shared);
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(return_value));
+ ION_CHECK(ion_symbol_table_get_system_table(&obj->tab, 1));
+ php_ion_symbol_table_ctor(obj);
+ ion_symbol_table_lock(obj->tab);
+}
+static ZEND_FUNCTION(ion_Symbol_Table_PHP)
+{
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ object_init_ex(return_value, ce_Symbol_Table_Shared);
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(return_value));
+ obj->tab = g_sym_tab_php;
+ php_ion_symbol_table_ctor(obj);
+ ion_symbol_table_lock(obj->tab);
+}
+static ZEND_METHOD(ion_Symbol_Table_Local, __construct)
+{
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(ZEND_THIS));
+ PTR_CHECK(obj);
+
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ ION_CHECK(ion_symbol_table_open_with_type(&obj->tab, NULL, ist_LOCAL));
+ obj->dtor = ion_symbol_table_close;
+ OBJ_CHECK(obj);
+}
+static ZEND_METHOD(ion_Symbol_Table_Local, import)
+{
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ zend_object *zo_import;
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_OBJ_OF_CLASS(zo_import, ce_Symbol_Table);
+ ZEND_PARSE_PARAMETERS_END();
+
+ php_ion_symbol_table_import(obj, php_ion_obj(symbol_table, zo_import));
+}
+static ZEND_METHOD(ion_Symbol_Table_Shared, __construct)
+{
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(ZEND_THIS));
+ PTR_CHECK(obj);
+
+ zend_string *zname;
+ zend_long version = 1;
+ ZEND_PARSE_PARAMETERS_START(1, 2)
+ Z_PARAM_STR(zname)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(version)
+ ZEND_PARSE_PARAMETERS_END();
+
+ ION_CHECK(ion_symbol_table_open_with_type(&obj->tab, NULL, ist_SHARED));
+ obj->dtor = ion_symbol_table_close;
+
+ ION_STRING is;
+ ION_CHECK(ion_symbol_table_set_name(obj->tab, ion_string_from_zend(&is, zname)));
+ ION_CHECK(ion_symbol_table_set_version(obj->tab, version));
+
+ php_ion_symbol_table_ctor(obj);
+}
+static ZEND_METHOD(ion_Symbol_Table, getMaxId)
+{
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ SID max_sid;
+ ION_CHECK(ion_symbol_table_get_max_sid(obj->tab, &max_sid));
+ RETURN_LONG(max_sid);
+}
+static ZEND_METHOD(ion_Symbol_Table, add)
+{
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ zend_object *zo_sym = NULL;
+ zend_string *zs_sym = NULL;
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_OBJ_OF_CLASS_OR_STR(zo_sym, ce_Symbol, zs_sym)
+ ZEND_PARSE_PARAMETERS_END();
+
+ if (zo_sym) {
+ zval z_sym;
+ ZVAL_OBJ(&z_sym, zo_sym);
+ zs_sym = zval_get_string(&z_sym);
+ ION_CATCH();
+ }
+ SID sid;
+ ION_STRING is;
+ ION_CHECK(ion_symbol_table_add_symbol(obj->tab, ion_string_from_zend(&is, zs_sym), &sid),
+ if (zo_sym) {
+ zend_string_release(zs_sym);
+ });
+ if (zo_sym) {
+ zend_string_release(zs_sym);
+ }
+ RETURN_LONG(sid);
+}
+static ZEND_METHOD(ion_Symbol_Table, find)
+{
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ zend_long zsid;
+ zend_string *zstring = NULL;
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_STR_OR_LONG(zstring, zsid)
+ ZEND_PARSE_PARAMETERS_END();
+
+ if (zstring) {
+ SID sid;
+ ION_STRING is;
+ ION_CHECK(ion_symbol_table_find_by_name(obj->tab, ion_string_from_zend(&is, zstring), &sid));
+ zsid = sid;
+ }
+ ION_SYMBOL *sym;
+ ION_CHECK(ion_symbol_table_get_symbol(obj->tab, zsid, &sym));
+ if (sym) {
+ php_ion_symbol_table_symbol_zval(obj, sym, return_value);
+ }
+}
+static ZEND_METHOD(ion_Symbol_Table, findLocal)
+{
+ php_ion_symbol_table *obj = php_ion_obj(symbol_table, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ zend_long zsid;
+ zend_string *zstring;
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_STR_OR_LONG(zstring, zsid)
+ ZEND_PARSE_PARAMETERS_END();
+
+ if (zstring) {
+ SID sid;
+ ION_STRING is;
+ ION_CHECK(ion_symbol_table_find_by_name(obj->tab, ion_string_from_zend(&is, zstring), &sid));
+ zsid = sid;
+ }
+ ION_SYMBOL *sym;
+ ION_CHECK(ion_symbol_table_get_local_symbol(obj->tab, zsid, &sym));
+ if (sym) {
+ php_ion_symbol_table_symbol_zval(obj, sym, return_value);
+ }
+}
+static ZEND_METHOD(ion_Catalog, __construct)
+{
+ php_ion_catalog *obj = php_ion_obj(catalog, Z_OBJ_P(ZEND_THIS));
+ PTR_CHECK(obj);
+
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ php_ion_catalog_ctor(obj);
+}
+static ZEND_METHOD(ion_Catalog, count)
+{
+ php_ion_catalog *obj = php_ion_obj(catalog, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ ZEND_PARSE_PARAMETERS_NONE();
+
+ int32_t c;
+ ION_CHECK(ion_catalog_get_symbol_table_count(obj->cat, &c));
+ RETURN_LONG(c);
+}
+static ZEND_METHOD(ion_Catalog, add)
+{
+ php_ion_catalog *obj = php_ion_obj(catalog, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ zend_object *zo_symtab;
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_OBJ_OF_CLASS(zo_symtab, ce_Symbol_Table)
+ ZEND_PARSE_PARAMETERS_END();
+
+ 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));
+ OBJ_CHECK(obj);
+
+ zend_object *zo_symtab = NULL;
+ zend_string *zs_symtab = NULL;
+ ZEND_PARSE_PARAMETERS_START(1, 1)
+ Z_PARAM_OBJ_OF_CLASS_OR_STR(zo_symtab, ce_Symbol_Table, zs_symtab)
+ ZEND_PARSE_PARAMETERS_END();
+
+ RETVAL_FALSE;
+
+ zval tmp;
+ zval *ztabs = zend_read_property(obj->std.ce, &obj->std, ZEND_STRL("symbolTables"), 0, &tmp);
+ if (ztabs) {
+ 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));
+ } 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);
+ }
+ }
+}
+static ZEND_METHOD(ion_Catalog, find)
+{
+ php_ion_catalog *obj = php_ion_obj(catalog, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ zend_long zversion = 0;
+ zend_string *zname;
+ ZEND_PARSE_PARAMETERS_START(1, 2)
+ Z_PARAM_STR(zname)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(zversion)
+ ZEND_PARSE_PARAMETERS_END();
+
+ ION_STRING is;
+ ION_SYMBOL_TABLE *tab_ptr = NULL;
+ ION_CHECK(ion_catalog_find_symbol_table(obj->cat, ion_string_from_zend(&is, zname), zversion, &tab_ptr));
+ if (tab_ptr) {
+ php_ion_catalog_symbol_table_zval(obj, tab_ptr, return_value);
+ }
+}
+static ZEND_METHOD(ion_Catalog, findBest)
+{
+ php_ion_catalog *obj = php_ion_obj(catalog, Z_OBJ_P(ZEND_THIS));
+ OBJ_CHECK(obj);
+
+ zend_long zversion = 0;
+ zend_string *zname;
+ ZEND_PARSE_PARAMETERS_START(1, 2)
+ Z_PARAM_STR(zname)
+ Z_PARAM_OPTIONAL
+ Z_PARAM_LONG(zversion)
+ ZEND_PARSE_PARAMETERS_END();
+
+ ION_STRING is;
+ ION_SYMBOL_TABLE *tab_ptr = NULL;
+ ION_CHECK(ion_catalog_find_best_match(obj->cat, ion_string_from_zend(&is, zname), zversion, &tab_ptr));
+ if (tab_ptr) {
+ php_ion_catalog_symbol_table_zval(obj, tab_ptr, return_value);
+ }
+}
+static ZEND_METHOD(ion_Timestamp, __construct)