Skip to content

Commit 7eb8eeb

Browse files
committed
Use self-maps for representing timed sourceless maps; added test_map_no_src.c to test suite; fix for handler-call during setup for dst-processed map expressions that do not require input.
1 parent 42b6534 commit 7eb8eeb

11 files changed

Lines changed: 404 additions & 25 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ test/testmapinput
7979
test/testmaplocation
8080
test/testmapprotocol
8181
test/testmapscope
82+
test/test_map_no_src
8283
test/test_map_timed
8384
test/testmonitor
8485
test/testnetwork

src/expression.c

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,16 +224,56 @@ int mpr_expr_get_var_type(mpr_expr expr, int idx)
224224

225225
int mpr_expr_get_src_causes_update(mpr_expr expr, int idx)
226226
{
227-
int i, muted = VAR_MUTED;
227+
int i, muted = VAR_MUTED, reducing_src = 0;
228228
etoken_t *tok = expr->stack->tokens;
229229
for (i = 0; i < expr->stack->num_tokens; i++) {
230-
if ((tok[i].toktype == TOK_VAR || tok[i].toktype == TOK_TT) && tok[i].var.idx == idx + VAR_X) {
231-
muted &= tok[i].gen.flags;
230+
switch (tok[i].toktype) {
231+
case TOK_VAR:
232+
case TOK_TT:
233+
if ( reducing_src
234+
|| (VAR_X_NEWEST == tok[i].var.idx)
235+
|| (idx + VAR_X) == tok[i].var.idx)
236+
muted &= tok[i].gen.flags;
237+
break;
238+
case TOK_LOOP_START:
239+
if (RT_SIGNAL == (tok->con.flags & REDUCE_TYPE_MASK))
240+
reducing_src = 1;
241+
case TOK_LOOP_END:
242+
if (RT_SIGNAL == (tok->con.flags & REDUCE_TYPE_MASK))
243+
reducing_src = 0;
244+
default:
245+
break;
232246
}
233247
}
234248
return muted == 0;
235249
}
236250

251+
int mpr_expr_get_src_is_used(mpr_expr expr, int idx)
252+
{
253+
int i, reducing_src = 0;
254+
etoken_t *tok = expr->stack->tokens;
255+
for (i = 0; i < expr->stack->num_tokens; i++) {
256+
switch (tok[i].toktype) {
257+
case TOK_VAR:
258+
case TOK_TT:
259+
if ( reducing_src
260+
|| VAR_X_NEWEST == tok[i].var.idx
261+
|| (idx + VAR_X) == tok[i].var.idx)
262+
return 1;
263+
break;
264+
case TOK_LOOP_START:
265+
if (RT_SIGNAL == (tok->con.flags & REDUCE_TYPE_MASK))
266+
reducing_src = 1;
267+
case TOK_LOOP_END:
268+
if (RT_SIGNAL == (tok->con.flags & REDUCE_TYPE_MASK))
269+
reducing_src = 0;
270+
default:
271+
break;
272+
}
273+
}
274+
return 0;
275+
}
276+
237277
int mpr_expr_get_num_src(mpr_expr expr)
238278
{
239279
return expr ? expr->num_src : 0;

src/expression.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ int mpr_expr_get_var_is_instanced(mpr_expr expr, int idx);
3737
const char *mpr_expr_get_var_name(mpr_expr expr, int idx);
3838

3939
int mpr_expr_get_src_causes_update(mpr_expr expr, int idx);
40+
int mpr_expr_get_src_is_used(mpr_expr expr, int idx);
4041

4142
int mpr_expr_get_manages_inst(mpr_expr expr);
4243

src/map.c

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,18 @@ mpr_map mpr_map_new(int num_src, mpr_sig *src, int num_dst, mpr_sig *dst)
297297
mpr_list maps;
298298
unsigned char i, j, is_local = 0;
299299

300+
/* we will allow simple self-maps to support "sourceless" maps */
301+
if (0 == num_src && 1 == num_dst) {
302+
num_src = 1;
303+
src = dst;
304+
}
305+
300306
RETURN_ARG_UNLESS(src && *src && dst && *dst, 0);
301307
RETURN_ARG_UNLESS(num_src > 0 && num_src <= MAX_NUM_MAP_SRC, 0);
302308

309+
/* Only 1 destination supported for now */
310+
RETURN_ARG_UNLESS(1 == num_dst, 0);
311+
303312
for (i = 0; i < num_src; i++) {
304313
mpr_dev src_dev = mpr_sig_get_dev(src[i]);
305314
/* check to make sure a src signal is not included more than once */
@@ -311,8 +320,8 @@ mpr_map mpr_map_new(int num_src, mpr_sig *src, int num_dst, mpr_sig *dst)
311320
}
312321
for (j = 0; j < num_dst; j++) {
313322
mpr_dev dst_dev = mpr_sig_get_dev(dst[j]);
314-
if (src[i] == dst[j]) {
315-
trace("Cannot connect signal '%s:%s' to itself.\n",
323+
if (src[i] == dst[j] && num_src > 1) {
324+
trace("Cannot connect signal '%s:%s' to itself in a convergent map.\n",
316325
mpr_dev_get_name(src_dev), mpr_sig_get_name(src[i]));
317326
return 0;
318327
}
@@ -323,16 +332,14 @@ mpr_map mpr_map_new(int num_src, mpr_sig *src, int num_dst, mpr_sig *dst)
323332
trace("Cannot create map between uninitialized devices unless they share a graph.");
324333
return 0;
325334
}
326-
if (0 == mpr_sig_compare_names(src[i], dst[j])) {
327-
trace("Cannot connect signal '%s:%s' to itself.\n",
335+
if (0 == mpr_sig_compare_names(src[i], dst[j]) && num_src > 1) {
336+
trace("Cannot connect signal '%s:%s' to itself in a convergent map.\n",
328337
mpr_dev_get_name(src_dev), mpr_sig_get_name(src[i]));
329338
return 0;
330339
}
331340
}
332341
is_local += mpr_obj_get_is_local((mpr_obj)src[i]);
333342
}
334-
/* Only 1 destination supported for now */
335-
RETURN_ARG_UNLESS(1 == num_dst, 0);
336343
is_local += mpr_obj_get_is_local((mpr_obj)*dst);
337344
g = mpr_obj_get_graph((mpr_obj)*dst);
338345

@@ -1022,7 +1029,8 @@ mpr_time mpr_map_process(mpr_local_map m, mpr_time t_now)
10221029
/* check if source signals have a value for this instance */
10231030
/* TODO: check whether source signal is actually referenced in the map expression */
10241031
for (j = 0; j < m->num_src; j++) {
1025-
if (!mpr_value_get_has_value(src_vals[0], i))
1032+
if ( mpr_local_slot_get_is_used(m->src[0])
1033+
&& !mpr_value_get_has_value(src_vals[0], i))
10261034
break;
10271035
}
10281036
if (j < m->num_src)
@@ -1716,14 +1724,27 @@ static int set_expr(mpr_local_map m, const char *expr_str)
17161724
/* Special case: if we are the receiver and the new expression evaluates to
17171725
* a constant we can update immediately. */
17181726
/* TODO: should call handler for all instances updated through this map. */
1719-
if (mpr_expr_get_num_src(m->expr) <= 0 && !m->use_inst && mpr_obj_get_is_local((mpr_obj)dst_sig)) {
1720-
/* call handler if it exists */
1721-
mpr_sig_call_handler((mpr_local_sig)dst_sig, MPR_STATUS_UPDATE_REM, 0, 0);
1727+
if (!m->use_inst && mpr_obj_get_is_local((mpr_obj)dst_sig)) {
1728+
int num_src = mpr_expr_get_num_src(m->expr), i;
1729+
for (i = 0; i < num_src; i++) {
1730+
if (mpr_expr_get_src_is_used(m->expr, i)) {
1731+
break;
1732+
}
1733+
}
1734+
if (i >= num_src) {
1735+
/* apply update to all active destination instances */
1736+
mpr_value dst_val = mpr_slot_get_value(m->dst);
1737+
void *value = mpr_value_get_value(dst_val, i, 0);
1738+
mpr_local_sig_set_inst_value((mpr_local_sig)dst_sig, value, -1, &m->id_map, EXPR_UPDATE,
1739+
mpr_expr_get_manages_inst(m->expr), t_now);
1740+
}
17221741
}
17231742

1724-
/* check whether each source slot causes computation */
1725-
for (i = 0; i < m->num_src; i++)
1743+
/* check whether each source slot is referenced and should trigger evaluation */
1744+
for (i = 0; i < m->num_src; i++) {
1745+
mpr_local_slot_set_is_used(m->src[i], mpr_expr_get_src_is_used(m->expr, i));
17261746
mpr_slot_set_causes_update((mpr_slot)m->src[i], mpr_expr_get_src_causes_update(m->expr, i));
1747+
}
17271748

17281749
/* check whether expression manages recalculation scheduling */
17291750
if ((m->is_self_timed = mpr_expr_get_manages_time(m->expr))) {
@@ -2236,7 +2257,6 @@ mpr_map mpr_map_new_from_str(const char *expr, ...)
22362257
va_end(aq);
22372258

22382259
TRACE_RETURN_UNLESS(dst, NULL, "Map format string '%s' has no output signal!\n", expr);
2239-
TRACE_RETURN_UNLESS(num_src, NULL, "Map format string '%s' has no input signals!\n", expr);
22402260

22412261
/* create the map */
22422262
map = mpr_map_new(num_src, srcs, 1, &dst);

src/network.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1678,9 +1678,8 @@ static int parse_sig_names(const char *types, lo_arg **av, int ac, int *src_idx,
16781678
for (i = 0; i < num_src; i++) {
16791679
TRACE_RETURN_UNLESS(strchr((&av[*src_idx+i]->s)+1, '/'), 0,
16801680
"malformed source signal name '%s'.\n", &av[*src_idx+i]->s);
1681-
TRACE_RETURN_UNLESS(strcmp(&av[*src_idx+i]->s, &av[*dst_idx]->s), 0,
1682-
"prevented attempt to connect signal '%s' to itself.\n",
1683-
&av[*dst_idx]->s);
1681+
TRACE_RETURN_UNLESS(strcmp(&av[*src_idx+i]->s, &av[*dst_idx]->s) || (1 == num_src), 0,
1682+
"prevented loop in convergent map.\n");
16841683
}
16851684
TRACE_RETURN_UNLESS(strchr((&av[*dst_idx]->s)+1, '/'), 0, "malformed "
16861685
"destination signal name '%s'.\n", &av[*dst_idx]->s)

src/slot.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ typedef struct _mpr_local_slot {
4141
mpr_link link;
4242
lo_message msg;
4343
uint16_t num_msg;
44-
uint16_t sending;
44+
uint8_t sending;
45+
uint8_t is_used;
4546
} mpr_local_slot_t;
4647

4748
mpr_slot mpr_slot_new(mpr_map map, mpr_sig sig, mpr_dir dir,
@@ -363,6 +364,18 @@ void mpr_slot_set_causes_update(mpr_slot slot, int causes_update)
363364
slot->causes_update = causes_update;
364365
}
365366

367+
int mpr_local_slot_get_is_used(mpr_local_slot slot)
368+
{
369+
return slot->is_used;
370+
}
371+
372+
void mpr_local_slot_set_is_used(mpr_local_slot slot, int is_used)
373+
{
374+
slot->is_used = is_used;
375+
if (!is_used)
376+
slot->causes_update = 0;
377+
}
378+
366379
int mpr_slot_get_status(mpr_local_slot slot)
367380
{
368381
int status = 0;

src/slot.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ int mpr_slot_get_causes_update(mpr_slot slot);
6161

6262
void mpr_slot_set_causes_update(mpr_slot slot, int causes_update);
6363

64+
int mpr_local_slot_get_is_used(mpr_local_slot slot);
65+
66+
void mpr_local_slot_set_is_used(mpr_local_slot slot, int is_used);
67+
6468
mpr_value mpr_slot_get_value(mpr_local_slot slot);
6569

6670
int mpr_slot_set_value(mpr_local_slot slot, unsigned int inst_idx, const void *value, mpr_time time);

test/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ add_executable (testmany testmany.c ${PROJECT_SRC})
3636
add_executable (testmapfail testmapfail.c ${PROJECT_SRC})
3737
add_executable (testmapinput testmapinput.c)
3838
add_executable (testmaplocation testmaplocation.c)
39+
add_executable (test_map_no_src test_map_no_src.c)
3940
add_executable (testmapprotocol testmapprotocol.c)
4041
add_executable (testmapscope testmapscope.c)
4142
add_executable (test_map_timed test_map_timed.c)
@@ -77,6 +78,7 @@ target_link_libraries(testmany PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB}
7778
target_link_libraries(testmapfail PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB} wsock32.lib ws2_32.lib iphlpapi.lib)
7879
target_link_libraries(testmapinput PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB} wsock32.lib ws2_32.lib iphlpapi.lib)
7980
target_link_libraries(testmaplocation PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB} wsock32.lib ws2_32.lib iphlpapi.lib)
81+
target_link_libraries(test_map_no_src PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB} wsock32.lib ws2_32.lib iphlpapi.lib)
8082
target_link_libraries(testmapprotocol PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB} wsock32.lib ws2_32.lib iphlpapi.lib)
8183
target_link_libraries(testmapscope PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB} wsock32.lib ws2_32.lib iphlpapi.lib)
8284
target_link_libraries(test_map_timed PUBLIC ${Liblo_LIB} ${Zlib_LIB} ${Libmapper_LIB} wsock32.lib ws2_32.lib iphlpapi.lib)

test/Makefile.am

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ if WINDOWS_DLL
2727
testmapfail \
2828
testmapinput \
2929
testmaplocation \
30+
test_map_no_src \
3031
testmapprotocol \
3132
testmapscope \
3233
test_map_timed \
@@ -86,6 +87,7 @@ if WINDOWS_DLL
8687
test_subscriptions \
8788
test_time_sync \
8889
test_map_timed \
90+
test_map_no_src \
8991
test
9092

9193
else
@@ -111,6 +113,7 @@ else
111113
testmapfail \
112114
testmapinput \
113115
testmaplocation \
116+
test_map_no_src \
114117
testmapprotocol \
115118
testmapscope \
116119
test_map_timed \
@@ -173,6 +176,7 @@ else
173176
test_subscriptions \
174177
test_time_sync \
175178
test_map_timed \
179+
test_map_no_src \
176180
test
177181

178182
endif
@@ -261,6 +265,10 @@ testmaplocation_CFLAGS = $(TEST_CFLAGS)
261265
testmaplocation_SOURCES = testmaplocation.c
262266
testmaplocation_LDADD = $(TEST_LDADD)
263267

268+
test_map_no_src_CFLAGS = $(TEST_CFLAGS)
269+
test_map_no_src_SOURCES = test_map_no_src.c
270+
test_map_no_src_LDADD = $(TEST_LDADD)
271+
264272
testmapprotocol_CFLAGS = $(TEST_CFLAGS)
265273
testmapprotocol_SOURCES = testmapprotocol.c
266274
testmapprotocol_LDADD = $(TEST_LDADD)

0 commit comments

Comments
 (0)