void* gu_map_insert(GuMap* map, const void* key) { size_t idx; bool found = gu_map_lookup(map, key, &idx); if (!found) { if (gu_map_maybe_resize(map)) { found = gu_map_lookup(map, key, &idx); gu_assert(!found); } if (map->kind == GU_MAP_ADDR) { ((const void**)map->data.keys)[idx] = key; } else if (map->kind == GU_MAP_STRING) { ((GuString*)map->data.keys)[idx] = key; } else { memcpy(&map->data.keys[idx * map->key_size], key, map->key_size); } if (map->default_value) { memcpy(&map->data.values[idx * map->value_size], map->default_value, map->value_size); } if (gu_map_entry_is_free(map, &map->data, idx)) { gu_assert(map->data.zero_idx == SIZE_MAX); map->data.zero_idx = idx; } map->data.n_occupied++; } return &map->data.values[idx * map->value_size]; }
GuChoiceMark gu_choice_mark(GuChoice* ch) { gu_assert(ch->path_idx <= gu_buf_length(ch->path)); gu_debug("%p@%d: mark", ch, ch->path_idx); return (GuChoiceMark){ch->path_idx}; }
static bool gu_out_begin_buf(GuOut* out, size_t req, GuExn* err) { GuOutStream* stream = out->stream; if (gu_out_is_buffering(out)) { if (out->buf_curr < 0) { return true; } else { gu_out_end_buf(out, err); if (!gu_ok(err)) { return false; } } } if (stream->begin_buf) { size_t sz = 0; uint8_t* buf = stream->begin_buf(stream, req, &sz, err); gu_assert(sz <= PTRDIFF_MAX); if (buf) { out->buf_end = &buf[sz]; out->buf_curr = -(ptrdiff_t) sz; out->buf_size = sz; return true; } } return false; }
GuOut gu_init_out(GuOutStream* stream) { gu_require(stream != NULL); GuOut out = { .buf_end = NULL, .buf_curr = 0, .stream = stream, .fini.fn = NULL }; return out; } static bool gu_out_is_buffering(GuOut* out) { return !!out->buf_end; } static void gu_out_end_buf(GuOut* out, GuExn* err) { if (!gu_out_is_buffering(out)) { return; } GuOutStream* stream = out->stream; size_t curr_len = ((ptrdiff_t)out->buf_size) + out->buf_curr; stream->end_buf(stream, curr_len, err); out->buf_end = NULL; out->buf_size = out->buf_curr = 0; } static bool gu_out_begin_buf(GuOut* out, size_t req, GuExn* err) { GuOutStream* stream = out->stream; if (gu_out_is_buffering(out)) { if (out->buf_curr < 0) { return true; } else { gu_out_end_buf(out, err); if (!gu_ok(err)) { return false; } } } if (stream->begin_buf) { size_t sz = 0; uint8_t* buf = stream->begin_buf(stream, req, &sz, err); gu_assert(sz <= PTRDIFF_MAX); if (buf) { out->buf_end = &buf[sz]; out->buf_curr = -(ptrdiff_t) sz; out->buf_size = sz; return true; } } return false; }
void gu_choice_reset(GuChoice* ch, GuChoiceMark mark) { gu_assert(ch->path_idx <= gu_buf_length(ch->path)); gu_debug("%p@%d: reset %d", ch, ch->path_idx, mark.path_idx); gu_require(mark.path_idx <= ch->path_idx ); ch->path_idx = mark.path_idx; }
int gu_choice_next(GuChoice* ch, int n_choices) { gu_assert(n_choices >= 0); gu_assert(ch->path_idx <= gu_buf_length(ch->path)); if (n_choices == 0) { return -1; } int i = 0; if (gu_buf_length(ch->path) > ch->path_idx) { i = (int) gu_buf_get(ch->path, size_t, ch->path_idx); gu_assert(i <= n_choices); } else { gu_buf_push(ch->path, size_t, n_choices); i = n_choices; } int ret = (i == 0) ? -1 : n_choices - i; gu_debug("%p@%d: %d", ch, ch->path_idx, ret); ch->path_idx++; return ret; }
PgfApplication* pgf_expr_unapply(PgfExpr expr, GuPool* pool) { int arity = pgf_expr_arity(expr); if (arity < 0) { return NULL; } PgfApplication* appl = gu_new_flex(pool, PgfApplication, args, arity); appl->n_args = arity; for (int n = arity - 1; n >= 0; n--) { PgfExpr e = pgf_expr_unwrap(expr); gu_assert(gu_variant_tag(e) == PGF_EXPR_APP); PgfExprApp* app = gu_variant_data(e); appl->args[n] = app->arg; expr = app->fun; } PgfExpr e = pgf_expr_unwrap(expr); gu_assert(gu_variant_tag(e) == PGF_EXPR_FUN); PgfExprFun* fun = gu_variant_data(e); appl->fun = fun->fun; return appl; }
bool gu_choice_advance(GuChoice* ch) { gu_assert(ch->path_idx <= gu_buf_length(ch->path)); while (gu_buf_length(ch->path) > ch->path_idx) { size_t last = gu_buf_pop(ch->path, size_t); if (last > 1) { gu_buf_push(ch->path, size_t, last-1); return true; } } return false; }
static bool gu_map_entry_is_free(GuMap* map, GuMapData* data, size_t idx) { if (idx == data->zero_idx) { return false; } else if (map->kind == GU_MAP_ADDR) { const void* key = ((const void**)data->keys)[idx]; return key == NULL; } else if (map->kind == GU_MAP_WORD) { GuWord key = ((GuWord*)data->keys)[idx]; return key == 0; } gu_assert(map->kind == GU_MAP_GENERIC); const void* key = &data->keys[idx * map->key_size]; return gu_map_buf_is_zero(key, map->key_size); }
static void gu_map_resize(GuMap* map) { GuMapData* data = &map->data; GuMapData old_data = *data; size_t req_entries = gu_twin_prime_sup(GU_MAX(11, map->data.n_occupied * 4 / 3 + 1)); size_t key_size = map->key_size; size_t key_alloc = 0; data->keys = gu_mem_buf_alloc(req_entries * key_size, &key_alloc); size_t value_size = map->value_size; size_t value_alloc = 0; if (value_size) { data->values = gu_mem_buf_alloc(req_entries * value_size, &value_alloc); memset(data->values, 0, value_alloc); } data->n_entries = gu_twin_prime_inf(value_size ? GU_MIN(key_alloc / key_size, value_alloc / value_size) : key_alloc / key_size); switch (map->kind) { case GU_MAP_GENERIC: case GU_MAP_WORD: memset(data->keys, 0, key_alloc); break; case GU_MAP_ADDR: for (size_t i = 0; i < data->n_entries; i++) { ((const void**)data->keys)[i] = NULL; } break; case GU_MAP_STRING: for (size_t i = 0; i < data->n_entries; i++) { ((GuString*)data->keys)[i] = NULL; } break; default: gu_impossible(); } gu_assert(data->n_entries > data->n_occupied); data->n_occupied = 0; data->zero_idx = SIZE_MAX; for (size_t i = 0; i < old_data.n_entries; i++) { if (gu_map_entry_is_free(map, &old_data, i)) { continue; } void* old_key = &old_data.keys[i * key_size]; if (map->kind == GU_MAP_ADDR) { old_key = *(void**)old_key; } else if (map->kind == GU_MAP_STRING) { old_key = (void*) *(GuString*)old_key; } void* old_value = &old_data.values[i * value_size]; memcpy(gu_map_insert(map, old_key), old_value, map->value_size); } gu_mem_buf_free(old_data.keys); if (value_size) { gu_mem_buf_free(old_data.values); } }
PgfClosure* pgf_evaluate_expr_thunk(PgfReasoner* rs, PgfExprThunk* thunk) { PgfEnv* env = thunk->env; PgfExpr expr = thunk->expr; size_t n_args = 0; PgfClosure** args = NULL; PgfClosure* res = NULL; repeat:; GuVariantInfo ei = gu_variant_open(expr); switch (ei.tag) { case PGF_EXPR_ABS: { PgfExprAbs* eabs = ei.data; if (n_args > 0) { PgfEnv* new_env = gu_new(PgfEnv, rs->pool); new_env->next = env; new_env->closure = args[--n_args]; env = new_env; expr = eabs->body; goto repeat; } else { thunk->header.code = rs->eval_gates->evaluate_value_lambda; thunk->expr = eabs->body; res = &thunk->header; } break; } case PGF_EXPR_APP: { PgfExprApp* eapp = ei.data; PgfExprThunk* thunk = gu_new(PgfExprThunk, rs->pool); thunk->header.code = rs->eval_gates->evaluate_expr_thunk; thunk->env = env; thunk->expr = eapp->arg; if (n_args % PGF_ARGS_DELTA == 0) { args = realloc(args, n_args + PGF_ARGS_DELTA); } args[n_args++] = &thunk->header; expr = eapp->fun; goto repeat; } case PGF_EXPR_LIT: { PgfExprLit* elit = ei.data; PgfValueLit* val = (PgfValueLit*) thunk; val->header.code = rs->eval_gates->evaluate_value_lit; val->lit = elit->lit; res = &val->header; break; } case PGF_EXPR_META: { PgfExprMeta* emeta = ei.data; PgfValueMeta* val = gu_new(PgfValueMeta, rs->pool); val->header.code = rs->eval_gates->evaluate_meta; val->env = env; val->id = emeta->id; res = pgf_mk_pap(rs, &val->header, n_args, args); break; } case PGF_EXPR_FUN: { PgfExprFun* efun = ei.data; PgfAbsFun* absfun = gu_seq_binsearch(rs->abstract->funs, pgf_absfun_order, PgfAbsFun, efun->fun); gu_assert(absfun != NULL); if (absfun->closure.code != NULL) { res = pgf_mk_pap(rs, (PgfClosure*) &absfun->closure, n_args, args); } else { size_t arity = absfun->arity; if (n_args == arity) { PgfValue* val = gu_new_flex(rs->pool, PgfValue, args, arity); val->header.code = rs->eval_gates->evaluate_value; val->con = (PgfClosure*) &absfun->closure; for (size_t i = 0; i < arity; i++) { val->args[i] = args[--n_args]; } res = &val->header; } else { gu_assert(n_args < arity); PgfExprThunk* lambda = gu_new(PgfExprThunk, rs->pool); lambda->header.code = rs->eval_gates->evaluate_value_lambda; lambda->env = NULL; res = pgf_mk_pap(rs, &lambda->header, n_args, args); for (size_t i = 0; i < arity; i++) { PgfExpr new_expr, arg; PgfExprVar *evar = gu_new_variant(PGF_EXPR_VAR, PgfExprVar, &arg, rs->pool); evar->var = arity-i-1; PgfExprApp *eapp = gu_new_variant(PGF_EXPR_APP, PgfExprApp, &new_expr, rs->pool); eapp->fun = expr; eapp->arg = arg; expr = new_expr; } for (size_t i = 0; i < arity-1; i++) { PgfExpr new_expr; PgfExprAbs *eabs = gu_new_variant(PGF_EXPR_ABS, PgfExprAbs, &new_expr, rs->pool); eabs->bind_type = PGF_BIND_TYPE_EXPLICIT; eabs->id = "_"; eabs->body = expr; expr = new_expr; } lambda->expr = expr; } } break; } case PGF_EXPR_VAR: { PgfExprVar* evar = ei.data; PgfEnv* tmp_env = env; size_t i = evar->var; while (i > 0) { tmp_env = tmp_env->next; if (tmp_env == NULL) { GuExnData* err_data = gu_raise(rs->err, PgfExn); if (err_data) { err_data->data = "invalid de Bruijn index"; } return NULL; } i--; } res = pgf_mk_pap(rs, tmp_env->closure, n_args, args); break; } case PGF_EXPR_TYPED: { PgfExprTyped* etyped = ei.data; expr = etyped->expr; goto repeat; } case PGF_EXPR_IMPL_ARG: { PgfExprImplArg* eimpl = ei.data; expr = eimpl->expr; goto repeat; } default: gu_impossible(); } free(args); return res; }