From 9118e8eaaff1f9ef0d03896eede43dea500529df Mon Sep 17 00:00:00 2001 From: Jeroen van der Heijden Date: Thu, 9 Nov 2023 16:15:08 +0100 Subject: [PATCH] Implement improved dup() and copy() (#355) * Implement improved dup and copy * Upd changelog and test --- CHANGELOG.md | 4 +++ inc/ti/thing.t.h | 1 + inc/ti/version.h | 4 +-- itest/test_advanced.py | 50 +++++++++++++++++++++++++++++++++++ src/ti/thing.c | 59 ++++++++++++++++++++++++++++++++++++++---- 5 files changed, 111 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fcd33228..f91199f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +# v1.4.16 + +* Improve `dup()` and `copy()` with self references, pr #355. + # v1.4.15 * Added support for methods on an _enumerator_ type, pr #352. diff --git a/inc/ti/thing.t.h b/inc/ti/thing.t.h index ee02044d..77cf89bb 100644 --- a/inc/ti/thing.t.h +++ b/inc/ti/thing.t.h @@ -56,6 +56,7 @@ enum the `id`.*/ TI_THING_FLAG_DICT =1<<2, /* thing is an object and items are stored in the smap_t. */ + TI_THING_FLAG_DEEP =1<<3, /* used for deep copy/duplication */ }; union ti_thing_via_items diff --git a/inc/ti/version.h b/inc/ti/version.h index ea021a28..00e54b41 100644 --- a/inc/ti/version.h +++ b/inc/ti/version.h @@ -6,7 +6,7 @@ #define TI_VERSION_MAJOR 1 #define TI_VERSION_MINOR 4 -#define TI_VERSION_PATCH 15 +#define TI_VERSION_PATCH 16 /* The syntax version is used to test compatibility with functions * using the `ti_nodes_check_syntax()` function */ @@ -25,7 +25,7 @@ * "-rc0" * "" */ -#define TI_VERSION_PRE_RELEASE "" +#define TI_VERSION_PRE_RELEASE "-alpha0" #define TI_MAINTAINER \ "Jeroen van der Heijden " diff --git a/itest/test_advanced.py b/itest/test_advanced.py index 334b6613..7704b2f3 100755 --- a/itest/test_advanced.py +++ b/itest/test_advanced.py @@ -2422,6 +2422,56 @@ async def test_enum_wrong_scope(self, client): A{TEST}; """, scope='/thingsdb') + async def test_deep_copy_and_dup(self, client): + # pr #355 + res = await client.query(r"""//ti + a = {}; + a.a = a; + b = a.dup(10); + b == b.a.a.a; + """) + self.assertIs(res, True) + res = await client.query(r"""//ti + a = {}; + a.a = a; + b = a.copy(10); + b == b.a.a.a; + """) + self.assertIs(res, True) + res = await client.query(r"""//ti + a = {}; + a['for item thing'] = 1; + a.a = a; + b = a.copy(10); + b == b.a.a.a; + """) + self.assertIs(res, True) + res = await client.query(r"""//ti + a = {}; + a['for item thing'] = 1; + a.a = a; + b = a.dup(10); + b == b.a.a.a; + """) + self.assertIs(res, True) + res = await client.query(r"""//ti + new_type('T'); + set_type('T', { + a: 'T?' + }); + a = T{}; + a.a = a; + b = a.dup(10); + b == b.a.a.a; + """) + self.assertIs(res, True) + res = await client.query(r"""//ti + a = T{}; + a.a = a; + b = a.copy(10); + b == b.a.a.a; + """) + self.assertIs(res, True) if __name__ == '__main__': run_test(TestAdvanced()) diff --git a/src/ti/thing.c b/src/ti/thing.c index 84578589..9d95e9ce 100644 --- a/src/ti/thing.c +++ b/src/ti/thing.c @@ -1497,9 +1497,31 @@ _Bool ti_thing_equals(ti_thing_t * thing, ti_val_t * otherv, uint8_t deep) return true; } +static inline void thing__deep_set(ti_thing_t * thing, ti_thing_t * other) +{ + thing->collection = (ti_collection_t *) other; + thing->flags |= TI_THING_FLAG_DEEP; +} + +static inline void thing__deep_unset(ti_thing_t * thing, ti_collection_t * collection) +{ + thing->collection = collection; + thing->flags &= ~TI_THING_FLAG_DEEP; +} + +static inline int thing__deep_use(ti_thing_t ** taddr) +{ + ti_thing_t * thing = *taddr; + *taddr = (ti_thing_t *) (*taddr)->collection; + ti_incref(*taddr); + ti_val_unsafe_gc_drop((ti_val_t *) thing); + return 0; +} + static int thing__copy_p(ti_thing_t ** taddr, uint8_t deep) { ti_thing_t * thing = *taddr; + ti_collection_t * collection = thing->collection; ti_thing_t * other = ti_thing_o_create( 0, ti_thing_n(thing), @@ -1508,6 +1530,7 @@ static int thing__copy_p(ti_thing_t ** taddr, uint8_t deep) if (!other) return -1; + thing__deep_set(thing, other); for (vec_each(thing->items.vec, ti_prop_t, prop)) { ti_prop_t * p = ti_prop_dup(prop); @@ -1521,11 +1544,13 @@ static int thing__copy_p(ti_thing_t ** taddr, uint8_t deep) VEC_push(other->items.vec, p); } + thing__deep_unset(thing, collection); ti_val_unsafe_gc_drop((ti_val_t *) thing); *taddr = other; return 0; fail: + thing__deep_unset(thing, collection); ti_val_unsafe_drop((ti_val_t *) other); return -1; } @@ -1533,6 +1558,7 @@ static int thing__copy_p(ti_thing_t ** taddr, uint8_t deep) static int thing__dup_p(ti_thing_t ** taddr, uint8_t deep) { ti_thing_t * thing = *taddr; + ti_collection_t * collection = thing->collection; ti_thing_t * other = ti_thing_o_create( 0, ti_thing_n(thing), @@ -1542,6 +1568,7 @@ static int thing__dup_p(ti_thing_t ** taddr, uint8_t deep) return -1; other->via.spec = thing->via.spec; + thing__deep_set(thing, other); for (vec_each(thing->items.vec, ti_prop_t, prop)) { @@ -1556,11 +1583,13 @@ static int thing__dup_p(ti_thing_t ** taddr, uint8_t deep) VEC_push(other->items.vec, p); } + thing__deep_unset(thing, collection); ti_val_unsafe_gc_drop((ti_val_t *) thing); *taddr = other; return 0; fail: + thing__deep_unset(thing, collection); ti_val_unsafe_drop((ti_val_t *) other); return -1; } @@ -1607,10 +1636,10 @@ static int thing__dup_cb(ti_item_t * item, thing__wcd_t * w) return 0; } - static int thing__copy_i(ti_thing_t ** taddr, uint8_t deep) { ti_thing_t * thing = *taddr; + ti_collection_t * collection = thing->collection; ti_thing_t * other = ti_thing_i_create(0, thing->collection); thing__wcd_t w = { .other = other, @@ -1620,14 +1649,18 @@ static int thing__copy_i(ti_thing_t ** taddr, uint8_t deep) if (!other) return -1; + thing__deep_set(thing, other); + if (smap_values(thing->items.smap, (smap_val_cb) thing__copy_cb, &w)) goto fail; + thing__deep_unset(thing, collection); ti_val_unsafe_gc_drop((ti_val_t *) thing); *taddr = other; return 0; fail: + thing__deep_unset(thing, collection); ti_val_unsafe_drop((ti_val_t *) other); return -1; } @@ -1635,6 +1668,7 @@ static int thing__copy_i(ti_thing_t ** taddr, uint8_t deep) static int thing__dup_i(ti_thing_t ** taddr, uint8_t deep) { ti_thing_t * thing = *taddr; + ti_collection_t * collection = thing->collection; ti_thing_t * other = ti_thing_i_create(0, thing->collection); thing__wcd_t w = { .other = other, @@ -1645,15 +1679,18 @@ static int thing__dup_i(ti_thing_t ** taddr, uint8_t deep) return -1; other->via.spec = thing->via.spec; + thing__deep_set(thing, other); if (smap_values(thing->items.smap, (smap_val_cb) thing__dup_cb, &w)) goto fail; + thing__deep_unset(thing, collection); ti_val_unsafe_gc_drop((ti_val_t *) thing); *taddr = other; return 0; fail: + thing__deep_unset(thing, collection); ti_val_unsafe_drop((ti_val_t *) other); return -1; } @@ -1663,6 +1700,7 @@ static int thing__copy_t(ti_thing_t ** taddr, uint8_t deep) ti_name_t * name; ti_val_t * val; ti_thing_t * thing = *taddr; + ti_collection_t * collection = thing->collection; ti_thing_t * other = ti_thing_o_create( 0, ti_thing_n(thing), @@ -1672,6 +1710,8 @@ static int thing__copy_t(ti_thing_t ** taddr, uint8_t deep) if (!other) return -1; + thing__deep_set(thing, other); + for(thing_t_each(thing, name, val)) { ti_prop_t * p = ti_prop_create(name, val); @@ -1689,12 +1729,13 @@ static int thing__copy_t(ti_thing_t ** taddr, uint8_t deep) VEC_push(other->items.vec, p); } - + thing__deep_unset(thing, collection); ti_val_unsafe_gc_drop((ti_val_t *) thing); *taddr = other; return 0; fail: + thing__deep_unset(thing, collection); ti_val_unsafe_drop((ti_val_t *) other); return -1; } @@ -1703,11 +1744,14 @@ static int thing__dup_t(ti_thing_t ** taddr, uint8_t deep) { ti_val_t * val; ti_thing_t * thing = *taddr; + ti_collection_t * collection = thing->collection; ti_type_t * type = thing->via.type; ti_thing_t * other = ti_thing_t_create(0, type, thing->collection); if (!other) return -1; + thing__deep_set(thing, other); + for (vec_each(type->fields, ti_field_t, field)) { val = VEC_get(thing->items.vec, field->idx); @@ -1719,12 +1763,13 @@ static int thing__dup_t(ti_thing_t ** taddr, uint8_t deep) } VEC_push(other->items.vec, val); } - + thing__deep_unset(thing, collection); ti_val_unsafe_gc_drop((ti_val_t *) thing); *taddr = other; return 0; fail: + thing__deep_unset(thing, collection); ti_val_unsafe_drop((ti_val_t *) other); return -1; } @@ -1733,7 +1778,9 @@ int ti_thing_copy(ti_thing_t ** thing, uint8_t deep) { assert (deep); return deep-- - ? ti_thing_is_object(*thing) + ? (*thing)->flags & TI_THING_FLAG_DEEP + ? thing__deep_use(thing) + : ti_thing_is_object(*thing) ? ti_thing_is_dict(*thing) ? thing__copy_i(thing, deep) : thing__copy_p(thing, deep) @@ -1745,7 +1792,9 @@ int ti_thing_dup(ti_thing_t ** thing, uint8_t deep) { assert (deep); return deep-- - ? ti_thing_is_object(*thing) + ? (*thing)->flags & TI_THING_FLAG_DEEP + ? thing__deep_use(thing) + : ti_thing_is_object(*thing) ? ti_thing_is_dict(*thing) ? thing__dup_i(thing, deep) : thing__dup_p(thing, deep)