Skip to content

Commit

Permalink
Implement improved dup() and copy() (#355)
Browse files Browse the repository at this point in the history
* Implement improved dup and copy

* Upd changelog and test
  • Loading branch information
joente authored Nov 9, 2023
1 parent ff3af59 commit 9118e8e
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 7 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -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.
Expand Down
1 change: 1 addition & 0 deletions inc/ti/thing.t.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions inc/ti/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 */
Expand All @@ -25,7 +25,7 @@
* "-rc0"
* ""
*/
#define TI_VERSION_PRE_RELEASE ""
#define TI_VERSION_PRE_RELEASE "-alpha0"

#define TI_MAINTAINER \
"Jeroen van der Heijden <jeroen@cesbit.com>"
Expand Down
50 changes: 50 additions & 0 deletions itest/test_advanced.py
Original file line number Diff line number Diff line change
Expand Up @@ -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())
59 changes: 54 additions & 5 deletions src/ti/thing.c
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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);
Expand All @@ -1521,18 +1544,21 @@ 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;
}

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),
Expand All @@ -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))
{
Expand All @@ -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;
}
Expand Down Expand Up @@ -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,
Expand All @@ -1620,21 +1649,26 @@ 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;
}

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,
Expand All @@ -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;
}
Expand All @@ -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),
Expand All @@ -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);
Expand All @@ -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;
}
Expand All @@ -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);
Expand All @@ -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;
}
Expand All @@ -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)
Expand All @@ -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)
Expand Down

0 comments on commit 9118e8e

Please sign in to comment.