static inline int match_record(ErlNifEnv* env, int arity, const ERL_NIF_TERM *tuple, State *st){ EncRecord *records = enc_records_base(st->records); EncField *fields = enc_fields_base(st->records); int i, k; for(i = 0; i < st->records->records_cnt; i++){ if(records[i].tag == tuple[0] && records[i].arity == (arity -1)){ unsigned fds_offset = records[i].fds_offset; unsigned bin_size = 0; b_putc('{', st); for(k = 0; k < records[i].arity; k++){ EncField field = fields[fds_offset + k]; bin_size += field.size; //FIXME { b_puts(field.size, st->records->bin.data + field.offset, st); if(!match_term(env, tuple[k+1], st)) return 0; } b_putc('}', st); return 1; } } return 0; }
static inline int match_list(ErlNifEnv* env, ERL_NIF_TERM term, State *st){ ERL_NIF_TERM list, head, tail; unsigned len; if(!enif_get_list_length(env, term, &len)) return 0; b_putc('[', st); list = term; enif_get_list_cell(env, list, &head, &tail); if(!match_term(env, head, st)){ b_unputc(st); // delete '['; return 0; } list = tail; while(enif_get_list_cell(env, list, &head, &tail)){ b_putc(',', st); if(!match_term(env, head, st)){ return 0; } list = tail; } b_putc(']', st); return 1; }
static inline int match_pair(ErlNifEnv* env, ERL_NIF_TERM term, State *st){ const ERL_NIF_TERM *tuple; int arity; if(enif_get_tuple(env, term, &arity, &tuple)){ if(arity == 2){ if(match_string(env, tuple[0], st)){ b_putc(':', st); if(match_term(env, tuple[1], st)){ return 1; } } } } return 0; }
/* * Check whether f is a range constraint * - if so return a term t and fill in vector v with the formula's constants * - otherwise, return NULL_TERM * * Side effect: use queue and cache. * v may be modified even if the function returns NULL_TERM. */ static term_t formula_is_range_constraint(sym_breaker_t *breaker, term_t f, ivector_t *v) { int_queue_t *queue; int_hset_t *cache; term_table_t *terms; intern_tbl_t *intern; term_t r, t; term_t x, a, y, b; uint32_t neqs; queue = &breaker->queue; cache = &breaker->cache; terms = breaker->terms; intern = &breaker->ctx->intern; assert(int_queue_is_empty(queue) && int_hset_is_empty(cache)); push_term(queue, cache, f); neqs = 0; t = NULL_TERM; y = NULL_TERM; // prevent GCC warning b = NULL_TERM; // prevent GCC warning /* * Invariants: * - neqs = number of equality atoms seen so far * - if neq == 1, then the first equality is stored as (y == b) where b is a constant * - if neq >= 2, then all equalities seen so far were of the form (x == constant) */ do { // r := root of the first term in the queue r = intern_tbl_get_root(intern, int_queue_pop(queue)); switch (match_term(breaker->ctx, r, &a, &x)) { case MATCH_FALSE: // skip false terms break; case MATCH_OR: push_children(queue, cache, or_term_desc(terms, r)); break; case MATCH_EQ: assert(term_is_constant(terms, a)); if (neqs == 0) { y = x; b = a; } else if (neqs == 1) { /* * First equality: (y == b). Second equality: (x == a) */ if (y == x) { // y is the common term, a and b are constant ivector_push(v, b); ivector_push(v, a); } else if (y == a && term_is_uconst(terms, x)) { // y is the common term, b and x are constant ivector_push(v, b); ivector_push(v, a); } else if (x == b && term_is_uconst(terms, y)) { // b is the common term, y and a are constant ivector_push(v, y); ivector_push(v, a); y = b; } else if (a == b && term_is_uconst(terms, y) && term_is_uconst(terms, x)) { // b is the common term, y and x are constant ivector_push(v, y); ivector_push(v, x); y = b; } else { // abort goto done; } } else { /* * All equalities so far have the form (y == constant) * - the current equality is (x == a) */ if (y == x) { ivector_push(v, a); // match } else if (y == a && term_is_constant(terms, x)) { ivector_push(v, x); // swap a and x } else { // no match goto done; } } neqs ++; break; case MATCH_IFF: /* * the returned term x is equivalent to t */ push_term(queue, cache, x); break; default: // abort goto done; } } while (! int_queue_is_empty(queue)); assert(y != NULL_TERM && t == NULL_TERM); if (neqs >= 2) { assert(v->size == neqs); t = y; } done: int_queue_reset(queue); int_hset_reset(cache); return t; }