Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# v1.10.3-alpha1
# v1.10.3-alpha2

* Add `int.of_type(..)` to convert an ID to a stored intance, pr #466.
* Improve error message when typing `f()!=x`, ambiguous operator, pr #468.
* Added `dict.vmap(..)` function, pr #469.

# v1.10.2

Expand Down
1 change: 1 addition & 0 deletions inc/doc.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@
#define DOC_DICT_RESTRICTION DOC_SEE("data-types/dict/restriction")
#define DOC_DICT_SET DOC_SEE("data-types/dict/set")
#define DOC_DICT_VALUES DOC_SEE("data-types/dict/values")
#define DOC_DICT_VMAP DOC_SEE("data-types/dict/vmap")
#define DOC_ENUM_NAME DOC_SEE("data-types/enum/name")
#define DOC_ENUM_VALUE DOC_SEE("data-types/enum/value")
#define DOC_ERROR_CODE DOC_SEE("data-types/error/code")
Expand Down
96 changes: 92 additions & 4 deletions inc/ti/fn/fnvmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,37 @@ static int vmap__walk_i(ti_item_t * item, vmap__walk_i_t * w)
return 0;
}

static int do__f_vmap(ti_query_t * query, cleri_node_t * nd, ex_t * e)
typedef struct
{
ex_t * e;
ti_closure_t * closure;
ti_query_t * query;
ti_dict_t * dict;
} vmap__pair_t;

static int vmap__pair(ti_dict_key_t * key, ti_val_t * val, vmap__pair_t * w)
{
ti_closure_vars_val(w->closure, val);
if (ti_closure_do_statement(w->closure, w->query, w->e) ||
ti_val(w->query->rval)->to_nested(
&w->query->rval,
(ti_parent_t *) w->dict,
w->e) ||
ti_dict_setr(w->dict, key, w->query->rval))
return -1;

ti_val_unsafe_drop(w->query->rval);
w->query->rval = NULL;
return 0;
}

static int do__f_vmap_thing(ti_query_t * query, cleri_node_t * nd, ex_t * e)
{
const int nargs = fn_get_nargs(nd);
ti_thing_t * othing, * nthing;
ti_closure_t * closure;
int lock_was_set;

if (!ti_val_is_thing(query->rval))
return fn_call_try("vmap", query, nd, e);

if (fn_nargs("vmap", DOC_THING_VMAP, 1, nargs, e))
return e->nr;

Expand Down Expand Up @@ -125,3 +146,70 @@ static int do__f_vmap(ti_query_t * query, cleri_node_t * nd, ex_t * e)
ti_val_unsafe_drop((ti_val_t *) othing);
return e->nr;
}

static int do__f_vmap_dict(ti_query_t * query, cleri_node_t * nd, ex_t * e)
{
const int nargs = fn_get_nargs(nd);
ti_dict_t * odict;
ti_closure_t * closure;
int lock_was_set;

if (fn_nargs("vmap", DOC_DICT_VMAP, 1, nargs, e))
return e->nr;

lock_was_set = ti_val_ensure_lock(query->rval);
odict = (ti_dict_t *) query->rval;
query->rval = NULL;

if (ti_do_statement(query, nd->children, e) ||
fn_arg_closure("vmap", DOC_DICT_VMAP, 1, query->rval, e))
goto fail0;

closure = (ti_closure_t *) query->rval;
query->rval = NULL;

if ( ti_closure_try_wse(closure, query, e) ||
ti_closure_inc(closure, query, e))
goto fail1;

vmap__pair_t w = {
.closure = closure,
.e = e,
.query = query,
.dict = ti_dict_create(),
};

if (!w.dict || ti_dict_pairs(
odict,
(ti_dict_pair_cb) vmap__pair,
&w))
goto fail2;

query->rval = (ti_val_t *) w.dict;
goto done;

fail2:
if (!e->nr)
ex_set_mem(e);
ti_val_drop((ti_val_t *) w.dict);

done:
ti_closure_dec(closure, query);

fail1:
ti_val_unsafe_drop((ti_val_t *) closure);

fail0:
ti_val_unlock((ti_val_t *) odict, lock_was_set);
ti_val_unsafe_drop((ti_val_t *) odict);
return e->nr;
}

static int do__f_vmap(ti_query_t * query, cleri_node_t * nd, ex_t * e)
{
return ti_val_is_thing(query->rval)
? do__f_vmap_thing(query, nd, e)
: ti_val_is_dict(query->rval)
? do__f_vmap_dict(query, nd, e)
: fn_call_try("vmap", query, nd, e);
}
2 changes: 1 addition & 1 deletion inc/ti/version.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* "-rc0"
* ""
*/
#define TI_VERSION_PRE_RELEASE "-alpha1"
#define TI_VERSION_PRE_RELEASE "-alpha2"

#define TI_MAINTAINER \
"Jeroen van der Heijden <jeroen@cesbit.com>"
Expand Down
40 changes: 40 additions & 0 deletions itest/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,46 @@ async def test_dict_map(self, client):
self.assertEqual(keys, [f'key: {i}' for i in range(n)])
self.assertEqual(values, [f'value: {i}' for i in range(n)])

async def test_dict_vmap(self, client):
q = client.query
with self.assertRaisesRegex(
NumArgumentsError,
'function `vmap` takes 1 argument but 0 were given'):
await q('dict().vmap();')

with self.assertRaisesRegex(
TypeError,
'function `vmap` expects argument 1 to be of '
'type `closure` but got type `int` instead'):
await q('dict().vmap(0);')

self.assertEqual(await q('dict().vmap(||nil)'), [])

self.assertEqual(sorted(await q("""//ti
dict([
[0, 1],
[1, 2],
[2, 3],
[3, 4]
]).vmap(|v| v*v);
""")), [
[0, 1],
[1, 4],
[2, 9],
[3, 16]
])

# test conversion
a1, a2 = await q("""//ti
a = ["a", "b"];
d = dict([[0, nil]]).vmap(|| a);
a.push("c"); // this is still a list
assert(is_tuple(d[0])); // must be a tuple
[a, d[0]];
""")
self.assertEqual(a1, ["a", "b", "c"])
self.assertEqual(a2, ["a", "b"])

async def test_dict_restriction(self, client):
q = client.query
with self.assertRaisesRegex(
Expand Down
Loading