From a575f5df3614a01cf03c6d0f07558e0e1ae31878 Mon Sep 17 00:00:00 2001 From: Calvin Rose Date: Fri, 26 Aug 2022 11:20:02 -0500 Subject: [PATCH] Add option to marshal values without cycle detection. --- src/core/marsh.c | 35 +++++++++++++++++++++++------------ src/include/janet.h | 1 + 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/src/core/marsh.c b/src/core/marsh.c index b58b176b..3fa3a6d0 100644 --- a/src/core/marsh.c +++ b/src/core/marsh.c @@ -37,6 +37,7 @@ typedef struct { JanetFuncEnv **seen_envs; JanetFuncDef **seen_defs; int32_t nextid; + int maybe_cycles; } MarshalState; /* Lead bytes in marshaling protocol */ @@ -364,13 +365,15 @@ void janet_marshal_janet(JanetMarshalContext *ctx, Janet x) { void janet_marshal_abstract(JanetMarshalContext *ctx, void *abstract) { MarshalState *st = (MarshalState *)(ctx->m_state); - janet_table_put(&st->seen, - janet_wrap_abstract(abstract), - janet_wrap_integer(st->nextid++)); + if (st->maybe_cycles) { + janet_table_put(&st->seen, + janet_wrap_abstract(abstract), + janet_wrap_integer(st->nextid++)); + } } #define MARK_SEEN() \ - janet_table_put(&st->seen, x, janet_wrap_integer(st->nextid++)) + do { if (st->maybe_cycles) janet_table_put(&st->seen, x, janet_wrap_integer(st->nextid++)); } while (0) static void marshal_one_abstract(MarshalState *st, Janet x, int flags) { void *abstract = janet_unwrap_abstract(x); @@ -428,11 +431,14 @@ static void marshal_one(MarshalState *st, Janet x, int flags) { /* Check reference and registry value */ { - Janet check = janet_table_get(&st->seen, x); - if (janet_checkint(check)) { - pushbyte(st, LB_REFERENCE); - pushint(st, janet_unwrap_integer(check)); - return; + Janet check; + if (st->maybe_cycles) { + check = janet_table_get(&st->seen, x); + if (janet_checkint(check)) { + pushbyte(st, LB_REFERENCE); + pushint(st, janet_unwrap_integer(check)); + return; + } } if (st->rreg) { check = janet_table_get(st->rreg, x); @@ -613,6 +619,7 @@ void janet_marshal( st.seen_defs = NULL; st.seen_envs = NULL; st.rreg = rreg; + st.maybe_cycles = !(flags & JANET_MARSHAL_NO_CYCLES); janet_table_init(&st.seen, 0); marshal_one(&st, x, flags); janet_table_deinit(&st.seen); @@ -1471,16 +1478,17 @@ JANET_CORE_FN(cfun_env_lookup, } JANET_CORE_FN(cfun_marshal, - "(marshal x &opt reverse-lookup buffer)", + "(marshal x &opt reverse-lookup buffer no-cycles)", "Marshal a value into a buffer and return the buffer. The buffer " "can then later be unmarshalled to reconstruct the initial value. " "Optionally, one can pass in a reverse lookup table to not marshal " "aliased values that are found in the table. Then a forward " "lookup table can be used to recover the original value when " "unmarshalling.") { - janet_arity(argc, 1, 3); + janet_arity(argc, 1, 4); JanetBuffer *buffer; JanetTable *rreg = NULL; + uint32_t flags = 0; if (argc > 1) { rreg = janet_gettable(argv, 1); } @@ -1489,7 +1497,10 @@ JANET_CORE_FN(cfun_marshal, } else { buffer = janet_buffer(10); } - janet_marshal(buffer, argv[0], rreg, 0); + if (argc > 3 && janet_truthy(argv[3])) { + flags |= JANET_MARSHAL_NO_CYCLES; + } + janet_marshal(buffer, argv[0], rreg, flags); return janet_wrap_buffer(buffer); } diff --git a/src/include/janet.h b/src/include/janet.h index 041c7dcc..7d6f2fd1 100644 --- a/src/include/janet.h +++ b/src/include/janet.h @@ -1671,6 +1671,7 @@ JANET_API JanetModule janet_native(const char *name, JanetString *error); /* Marshaling */ #define JANET_MARSHAL_UNSAFE 0x20000 +#define JANET_MARSHAL_NO_CYCLES 0x40000 JANET_API void janet_marshal( JanetBuffer *buf,