Пример #1
0
static bool
_dict_insert(struct BX_Dict *dict, struct BoolExpr *key, struct BoolExpr *val)
{
    size_t index = _hash(dict, key);
    struct BX_DictItem *item;
    struct BX_DictItem **tail;

    tail = &dict->items[index];
    for (item = dict->items[index]; item; item = item->tail) {
        if (_eq(item->key, key)) {
            BX_DecRef(item->key);
            BX_DecRef(item->val);
            item->key = BX_IncRef(key);
            item->val = BX_IncRef(val);
            return true;
        }
        tail = &item->tail;
    }

    item = malloc(sizeof(struct BX_DictItem));
    if (item == NULL)
        return false; // LCOV_EXCL_LINE

    item->key = BX_IncRef(key);
    item->val = BX_IncRef(val);
    item->tail = (struct BX_DictItem *) NULL;

    *tail = item;

    dict->length += 1;

    return true;
}
Пример #2
0
static
Value *
eval(const Ast *expr) {
	switch(expr->class) {
	case N_CALL:
		return call(expr);
	case N_ASSIGNMENT:
		return assignment(expr);
	case N_IDENTIFIER:
		return identifier(expr);
	case N_NEG:
		return _neg(expr);
	case N_NOT:
		return _not(expr);
	case N_EQ:
		return _eq(expr);
	case N_NEQ:
		return _neq(expr);
	case N_AND:
		return _and(expr);
	case N_IOR:
		return _ior(expr);
	case N_XOR:
		return _neq(expr); // alias
	case N_LT:
		return _lt(expr);
	case N_LE:
		return _le(expr);
	case N_GE:
		return _ge(expr);
	case N_GT:
		return _gt(expr);
	case N_ADD:
		return _add(expr);
	case N_SUB:
		return _sub(expr);
	case N_MUL:
		return _mul(expr);
	case N_DIV:
		return _div(expr);
	case N_POW:
		return _pow(expr);
	case N_MOD:
		return _mod(expr);
	case N_BOOLEAN:
		return _bool(expr);
	case N_INTEGER:
		return _int(expr);
	case N_FLOAT:
		return _float(expr);
	case N_STRING:
		return _string(expr);
	case N_SET:
		return _set(expr);
	case N_R:
		return _relation(expr);
	}
printf("EVALFAIL %d ", expr->class); pn(expr);
	assert(false && "should not be reached");
}
Пример #3
0
/* NOTE: assumes arguments are already simple */
static struct BoolExpr *
_impl_simplify(struct BoolExpr *op)
{
    struct BoolExpr *p = op->data.xs->items[0];
    struct BoolExpr *q = op->data.xs->items[1];

    /* Implies(0, q) <=> Implies(p, 1) <=> 1 */
    if (BX_IS_ZERO(p) || BX_IS_ONE(q))
        return BX_IncRef(&BX_One);

    /* Implies(1, q) <=> q */
    if (BX_IS_ONE(p))
        return BX_IncRef(q);

    /* Implies(p, 0) <=> ~p */
    if (BX_IS_ZERO(q))
        return BX_Not(p);

    /* Implies(p, p) <=> 1 */
    if (_eq(p, q))
        return BX_IncRef(&BX_One);

    /* Implies(~p, p) <=> p */
    if (COMPLEMENTARY(p, q))
        return BX_IncRef(q);

    return BX_Implies(p, q);
}
Пример #4
0
inline bool _string<init_size, inc_bit>::operator==(const _Self & s) const
{
	if(this->__len != s.length())
		return false;
	for(size_t i = 0; i < this->__len; ++i)
		if(!_eq(this->__p_string[i], s[i]))
			return false;
	return true;
}//operator==(_string)
Пример #5
0
static
Value *
_neq(const Ast *expr) {
	//Ast *op1 = expr->child;
	//Ast *op2 = expr->child->next;
	Value *rval = _eq(expr);

	value_set_bool(rval, !rval->as_bool);

	return rval;
}
Пример #6
0
static struct BoolExpr *
_list_search(struct BX_DictItem *list, struct BoolExpr *key)
{
    if (!list)
        return (struct BoolExpr *) NULL;

    if (_eq(list->key, key))
        return list->val;

    return _list_search(list->tail, key);
}
Пример #7
0
pointlist* logicop::logic::hole2simple(const pointlist& outside, const pointlist& inside) {
   polycross::segmentlist _seg1(outside,1);
   polycross::segmentlist _seg2(inside  ,2);
   polycross::XQ _eq(_seg1, _seg2); // create the event queue
   polycross::BindCollection BC;
   
   _eq.sweep2bind(BC);
   polycross::BindSegment* sbc = BC.get_highest();
   //insert 2 bind points and link them
   polycross::BPoint* cpsegA = _seg1.insertBindPoint(sbc->poly0seg(), sbc->poly0pnt());
   polycross::BPoint* cpsegB = _seg2.insertBindPoint(sbc->poly1seg(), sbc->poly1pnt());
   cpsegA->linkto(cpsegB);
   cpsegB->linkto(cpsegA);
   // normalize the segment lists
   _seg1.normalize(outside);
   _seg2.normalize(inside);
   //
   // dump the new polygons in VList terms
   polycross::VPoint* outshape = _seg1.dump_points();
   polycross::VPoint*  inshape = _seg2.dump_points();
   // traverse and form the resulting shape
   polycross::VPoint* centinel = outshape;
   pointlist *shgen = DEBUG_NEW pointlist();
   bool direction = true; /*next*/
   polycross::VPoint* pickup = centinel;
   polycross::VPoint* prev = centinel->prev();
   bool modify = false;
   do {
      shgen->push_back(TP(pickup->cp()->x(), pickup->cp()->y()));
      modify = (-1 == prev->visited());
      prev = pickup;
      pickup = pickup->follower(direction, modify);
   } while (pickup != centinel);
   // clean-up dumped points
   cleanupDumped(outshape);
   cleanupDumped(inshape);
   // Validate the resulting polygon
   laydata::valid_poly check(*shgen);
//   delete shgen;
   if (!check.valid()) {
      std::ostringstream ost;
      ost << ": Resulting shape is invalid - " << check.failtype();
      tell_log(console::MT_ERROR, ost.str());
   }
   else {
      if (laydata::shp_OK != check.status())
         *shgen = check.get_validated();
   }
   return shgen;
}
Пример #8
0
bool
BX_Dict_Remove(struct BX_Dict *dict, struct BoolExpr *key)
{
    size_t index = _hash(dict, key);
    struct BX_DictItem *item;
    struct BX_DictItem **tail;

    tail = &dict->items[index];
    for (item = dict->items[index]; item; item = item->tail) {
        if (_eq(item->key, key)) {
            BX_DecRef(item->key);
            BX_DecRef(item->val);
            *tail = item->tail;
            free(item);
            dict->length -= 1;
            return true;
        }
        tail = &item->tail;
    }

    return false;
}
Пример #9
0
/* NOTE: assumes arguments are already simple */
static struct BoolExpr *
_ite_simplify(struct BoolExpr *op)
{
    struct BoolExpr *s = op->data.xs->items[0];
    struct BoolExpr *d1 = op->data.xs->items[1];
    struct BoolExpr *d0 = op->data.xs->items[2];

    struct BoolExpr *sn;
    struct BoolExpr *y;

    /* ITE(0, d1, d0) <=> d0 */
    if (BX_IS_ZERO(s))
        return BX_IncRef(d0);

    /* ITE(1, d1, d0) <=> d1 */
    if (BX_IS_ONE(s))
        return BX_IncRef(d1);

    if (BX_IS_ZERO(d1)) {
        /* ITE(s, 0, 0) <=> 0 */
        if (BX_IS_ZERO(d0))
            return BX_IncRef(&BX_Zero);

        /* ITE(s, 0, 1) <=> ~s */
        if (BX_IS_ONE(d0))
            return BX_Not(s);

        /* ITE(s, 0, d0) <=> And(~s, d0) */
        CHECK_NULL(sn, BX_Not(s));
        y = _simple_op2(BX_OP_AND, sn, d0);
        BX_DecRef(sn);
        return y;
    }

    if (BX_IS_ONE(d1)) {
        /* ITE(s, 1, 0) <=> s */
        if (BX_IS_ZERO(d0))
            return BX_IncRef(s);

        /* ITE(s, 1, 1) <=> 1 */
        if (BX_IS_ONE(d0))
            return BX_IncRef(&BX_One);

        /* ITE(s, 1, d0) <=> Or(s, d0) */
        return _simple_op2(BX_OP_OR, s, d0);
    }

    /* ITE(s, d1, 0) <=> And(s, d1) */
    if (BX_IS_ZERO(d0))
        return _simple_op2(BX_OP_AND, s, d1);

    /* ITE(s, d1, 1) <=> Or(~s, d1) */
    if (BX_IS_ONE(d0)) {
        CHECK_NULL(sn, BX_Not(s));
        y = _simple_op2(BX_OP_OR, sn, d1);
        BX_DecRef(sn);
        return y;
    }

    /* ITE(s, d1, d1) <=> d1 */
    if (_eq(d1, d0))
        return BX_IncRef(d1);

    /* ITE(s, s, d0) <=> Or(s, d0) */
    if (_eq(s, d1))
        return _simple_op2(BX_OP_OR, s, d0);

    /* ITE(s, d1, s) <=> And(s, d1) */
    if (_eq(s, d0))
        return _simple_op2(BX_OP_AND, s, d1);

    return BX_ITE(s, d1, d0);
}
Пример #10
0
/* NOTE: assumes arguments are already simple */
static struct BoolExpr *
_eq_simplify(struct BoolExpr *op)
{
    bool found_zero = false;
    bool found_one = false;

    size_t length = op->data.xs->length;
    struct BoolExpr **flat;
    size_t flat_len = 0;
    struct BoolExpr **uniq;
    size_t uniq_len = 0;
    struct BoolExpr *xi;
    struct BoolExpr *y;

    flat = malloc(length * sizeof(struct BoolExpr *));
    if (flat == NULL)
        return NULL; // LCOV_EXCL_LINE

    /* 1. Eliminate {0, 1} */
    for (size_t i = 0; i < length; ++i) {
        xi = op->data.xs->items[i];
        if (BX_IS_ZERO(xi))
            found_zero = true;
        else if (BX_IS_ONE(xi))
            found_one = true;
        else
            flat[flat_len++] = xi;
    }

    /* Equal(0, 1) <=> 0 */
    if (found_zero && found_one) {
        free(flat);
        return BX_IncRef(&BX_Zero);
    }

    /* 2. Sort arguments, so you get ~a, ~a, a, a, ~b, ... */
    qsort(flat, flat_len, sizeof(struct BoolExpr *), _cmp);

    uniq = malloc(flat_len * sizeof(struct BoolExpr *));
    if (uniq == NULL) {
        free(flat);  // LCOV_EXCL_LINE
        return NULL; // LCOV_EXCL_LINE
    }

    /* 3. Apply: Equal(~x, x) <=> 0, Equal(x0, x0, x1) <=> Equal(x0, x1) */
    for (size_t i = 0; i < flat_len; ++i) {
        if (uniq_len == 0) {
            uniq[uniq_len++] = flat[i];
        }
        else {
            /* Equal(~x, x) <=> 0 */
            if (COMPLEMENTARY(uniq[uniq_len-1], flat[i])) {
                free(flat);
                free(uniq);
                return BX_IncRef(&BX_Zero);
            }
            /* Equal(x0, x0, x1) <=> Equal(x0, x1) */
            else if (!_eq(flat[i], uniq[uniq_len-1]))
                uniq[uniq_len++] = flat[i];
        }
    }

    free(flat);

    if (found_zero) {
        /* Equal(0) <=> 1 */
        if (uniq_len == 0)
            y = BX_IncRef(&BX_One);
        /* Equal(0, x) <=> ~x */
        else if (uniq_len == 1)
            y = BX_Not(uniq[0]);
        /* Equal(0, x0, x1) <=> Nor(x0, x1) */
        else
            y = _simple_nop(BX_OP_OR, uniq_len, uniq);
    }
    else if (found_one) {
        /* Equal(1) <=> 1 */
        if (uniq_len == 0)
            y = BX_IncRef(&BX_One);
        /* Equal(1, x) <=> x */
        else if (uniq_len == 1)
            y = BX_IncRef(uniq[0]);
        /* Equal(1, x0, ...) <=> And(x0, ...) */
        else
            y = _simple_op(BX_OP_AND, uniq_len, uniq);
    }
    else {
        y = BX_Equal(uniq_len, uniq);
    }

    free(uniq);

    return y;
}
Пример #11
0
/* NOTE: assume operator arguments are already simple */
static struct BoolExpr *
_orand_simplify(struct BoolExpr *op)
{
    size_t n = _count_orand_args(op);
    struct BoolExpr **flat;
    size_t flat_len = 0;
    struct BoolExpr **uniq;
    size_t uniq_len = 0;
    struct BoolExpr *xi, *xj;
    struct BoolExpr *y;

    flat = malloc(n * sizeof(struct BoolExpr *));
    if (flat == NULL)
        return NULL; // LCOV_EXCL_LINE

    /* 1. Flatten arguments, and eliminate {0, 1} */
    for (size_t i = 0; i < op->data.xs->length; ++i) {
        xi = op->data.xs->items[i];
        /* Or(1, x) <=> 1 */
        if (xi == _bx_dominator[op->kind]) {
            free(flat);
            return BX_IncRef(_bx_dominator[op->kind]);
        }
        /* Or(Or(x0, x1), x2) <=> Or(x0, x1, x2) */
        else if (xi->kind == op->kind) {
            for (size_t j = 0; j < xi->data.xs->length; ++j) {
                xj = xi->data.xs->items[j];
                /* Or(1, x) <=> 1 */
                if (xj == _bx_dominator[op->kind]) {
                    free(flat);
                    return BX_IncRef(_bx_dominator[op->kind]);
                }
                /* Or(0, x) <=> x */
                else if (xj != _bx_identity[op->kind]) {
                    flat[flat_len++] = xj;
                }
            }
        }
        /* Or(0, x) <=> x */
        else if (xi != _bx_identity[op->kind]) {
            flat[flat_len++] = xi;
        }
    }

    /* 2. Sort arguments, so you get ~a, ~a, a, a, ~b, ... */
    qsort(flat, flat_len, sizeof(struct BoolExpr *), _cmp);

    uniq = malloc(flat_len * sizeof(struct BoolExpr *));
    if (uniq == NULL) {
        free(flat);  // LCOV_EXCL_LINE
        return NULL; // LCOV_EXCL_LINE
    }

    /* 3. Apply: Or(~x, x) <=> 1, Or(x, x) <=> x */
    for (size_t i = 0; i < flat_len; ++i) {
        if (uniq_len == 0) {
            uniq[uniq_len++] = flat[i];
        }
        else {
            /* Or(~x, x) <=> 1 */
            if (COMPLEMENTARY(uniq[uniq_len-1], flat[i])) {
                free(flat);
                free(uniq);
                return BX_IncRef(_bx_dominator[op->kind]);
            }
            /* Or(x, x) <=> x */
            else if (!_eq(flat[i], uniq[uniq_len-1])) {
                uniq[uniq_len++] = flat[i];
            }
        }
    }

    free(flat);

    y = _bx_orandxor_new(op->kind, uniq_len, uniq);

    free(uniq);

    return y;
}
Пример #12
0
inline bool _eq1(const T &a) {
    return _eq(a, T(1));
}
Пример #13
0
inline bool _eq0(const T &a) {
    return _eq(a, T(0));
}
Пример #14
0
inline bool _ne(const T &a, const T &b) {
    return !_eq(a, b);
}
Пример #15
0
ISTBOOL GetSphereFrom4Points(struct sphere_model *model)
{
	ISTFLOAT a[4][4] = {{0}};
	ISTFLOAT ho[3] = {0};
	ISTFLOAT norm = 0;
	ISTFLOAT rad = 0;
	ISTFLOAT tmpf = 0;
	ISTFLOAT two = _float(2);
	ISTFLOAT m11, m12, m13, m14, m15;
	ISTINT i, j;

	// Get sphere from 4 points
	for (i = 0; i < 4; i++) { /* find minor 11 */
		a[i][0] = model->p4s[i][0];
		a[i][1] = model->p4s[i][1];
		a[i][2] = model->p4s[i][2];
		a[i][3] = _one;
	}
	m11 = GetDet(a, 4);
	for (i = 0; i < 4; i++) { /* find minor 12 */
		a[i][0] = _add(_add(_mul(model->p4s[i][0], model->p4s[i][0]),
			_mul(model->p4s[i][1], model->p4s[i][1])),
			_mul(model->p4s[i][2], model->p4s[i][2]));
		a[i][1] = model->p4s[i][1];
		a[i][2] = model->p4s[i][2];
		a[i][3] = _one;
	}
	m12 = GetDet(a, 4);
	for (i = 0; i < 4; i++) { /* find minor 13 */
		a[i][0] = _add(_add(_mul(model->p4s[i][0], model->p4s[i][0]),
			_mul(model->p4s[i][1], model->p4s[i][1])),
			_mul(model->p4s[i][2], model->p4s[i][2]));
		a[i][1] = model->p4s[i][0];
		a[i][2] = model->p4s[i][2];
		a[i][3] = _one;
	}
	m13 = GetDet(a, 4);
	for (i = 0; i < 4; i++) { /* find minor 14 */
		a[i][0] = _add(_add(_mul(model->p4s[i][0], model->p4s[i][0]),
			_mul(model->p4s[i][1], model->p4s[i][1])),
			_mul(model->p4s[i][2], model->p4s[i][2]));
		a[i][1] = model->p4s[i][0];
		a[i][2] = model->p4s[i][1];
		a[i][3] = _one;
	}
	m14 = GetDet(a, 4);
	for (i = 0; i < 4; i++) { /* find minor 15 */
		a[i][0] = _add(_add(_mul(model->p4s[i][0], model->p4s[i][0]),
			_mul(model->p4s[i][1], model->p4s[i][1])),
			_mul(model->p4s[i][2], model->p4s[i][2]));
		a[i][1] = model->p4s[i][0];
		a[i][2] = model->p4s[i][1];
		a[i][3] = model->p4s[i][2];
	}
	m15 = GetDet(a, 4);
	if (_eq(m11, 0)) {
		rad = 0;
	} else { /* center of sphere */
		ho[0] = _div(_div(m12, m11), two);
		ho[1] = _neg(_div(_div(m13, m11), two));
		ho[2] = _div(_div(m14, m11), two);
		norm = _sub(_add(_add(_mul(ho[0], ho[0]),
			_mul(ho[1], ho[1])),
			_mul(ho[2], ho[2])),
			_div(m15, m11));
		if (_ge(norm, 0)) {
			rad = _sqrt(norm);
		}
	}
	if (_le(rad, 0)) {
		goto EXIT;
	}
	// Check distance
	for (i = 0; i < 4; i++) {
		for (j = (i + 1); j < 4; j++) {
			tmpf = GetDistance(model->p4s[i], model->p4s[j]);
			if (_lt(tmpf, rad) || _lt(tmpf, model->rad_min)) {
				goto EXIT;
			}
		}
	}
	// Update offset 
	for (i = 1; i < IST_SPHERE_OFFSET_NUM; i++) {
		for (j = 0; j < 3; ++j) {
			model->offsets[IST_SPHERE_OFFSET_NUM - i][j] = model->offsets[IST_SPHERE_OFFSET_NUM - i - 1][j];
		}
	}
	for (j = 0; j < 3; ++j) {
		model->offsets[0][j] = ho[j];
	}
	for (i = (IST_SPHERE_DATAMAX >> 1); i < IST_SPHERE_DATAMAX; i++) {
		for (j = 0; j < 3; ++j) {
			model->data[i][j] = _max;
		}
	}
	// Check offset buffer full
	if (IsInitedVector(model->offsets[IST_SPHERE_OFFSET_NUM - 1])) {
		goto EXIT;
	}
	// Calculate mean bias and radius
	if (!GetParams(model, rad)) {
		goto EXIT;
	}
	return ISTTRUE;

EXIT:
	return ISTFALSE;
}
Пример #16
0
/*
 * TKGetNextToken returns the next token from the token stream as a
 * character string.  Space for the returned token should be dynamically
 * allocated.  The caller is responsible for freeing the space once it is
 * no longer needed.
 *
 * If the function succeeds, it returns a C string (delimited by '\0')
 * containing the token.  Else it returns 0.
 *
 * You need to fill in this function as part of your implementation.
 */
TokenT *TKGetNextToken(TokenizerT *tk) {
    clearBuffer(tk);
    char curr = tk->inputIter[0];

    // skip all whitespace before next token
    while(isspace(curr)) {
        nextChar(tk);
        clearBuffer(tk);
        curr = tk->inputIter[0];
    }

    if(curr == '\0') {
        return NULL;
    } else if(isalpha(curr) || curr == '_') {
        return _word(tk);
    } else if(curr == '0') {
        return _zero(tk);
    } else if(isdigit(curr)) {
        return _decimal(tk);
    } else if(curr == '!') { // neq
        return _neq(tk);
    } else if(curr == '"') { // double_quote
        return _double_quote(tk);
    } else if(curr == '#') {
        return _pound(tk);
    } else if(curr == '$') { // INVALID
        return _invalid(tk);
    } else if(curr == '%') { // mod, mod_eq
        return _mod(tk);
    } else if(curr == '&') { // bit_and, log_and, address (?)
        return _bit_and(tk);
    } else if(curr == '\'') { // single_quote
        return _single_quote(tk);
    } else if(curr == '(') { // open_paren
        return _open_paren(tk);
    } else if(curr == ')') { // close_paren
        return _close_paren(tk);
    } else if(curr == '*') { // mult, mult_eq, pointer (?)
        return _mult(tk);
    } else if(curr == '+') { // plus, plus_eq, inc
        return _plus(tk);
    } else if(curr == ',') { // comma
        return _comma(tk);
    } else if(curr == '-') { // minus, minus_eq, dec, struct_pointer
        return _minus(tk);
    } else if(curr == '.') { // dot
        return _dot(tk);
    } else if(curr == '/') { // div, div_eq
        return _div(tk);
    } else if(curr == ':') { // ternary_colon
        return _ternary_colon(tk);
    } else if(curr == ';') { // semicolon
        return _semicolon(tk);
    } else if(curr == '<') { // lt, lshift, lt_eq
        return _lt(tk);
    } else if(curr == '=') { // eq, assign
        return _eq(tk);
    } else if(curr == '>') { // gt, rshift, gt_eq
        return _gt(tk);
    } else if(curr == '?') { // ternary_qmark
        return _ternary_qmark(tk);
    } else if(curr == '@') { // INVALID
        return _invalid(tk);
    } else if(curr == '[') { // open_bracket
        return _open_bracket(tk);
    } else if(curr == '\\') { // backslash (?)
        return _invalid(tk);
    } else if(curr == ']') { // close_bracket
        return _close_bracket(tk);
    } else if(curr == '^') { // bit_xor
        return _bit_xor(tk);
    } else if(curr == '`') { // INVALID
        return _invalid(tk);
    } else if(curr == '{') { // open_brace
        return _open_brace(tk);
    } else if(curr == '|') { // bit_or, log_or
        return _bit_or(tk);
    } else if(curr == '}') { // close_brace
        return _close_brace(tk);
    } else if(curr == '~') { // bit_not
        return _bit_not(tk);
    } else {
        return _invalid(tk);
    }
}
Пример #17
0
/* NOTE: assume operator arguments are already simple */
static struct BoolExpr *
_xor_simplify(struct BoolExpr *op)
{
    bool parity = true;

    size_t n = _count_xor_args(op);
    struct BoolExpr **flat;
    size_t flat_len = 0;
    struct BoolExpr **uniq;
    size_t uniq_len = 0;
    struct BoolExpr *xi, *xj;
    struct BoolExpr *y;

    flat = malloc(n * sizeof(struct BoolExpr *));
    if (flat == NULL)
        return NULL; // LCOV_EXCL_LINE

    /* 1. Flatten arguments, and eliminate {0, 1} */
    for (size_t i = 0; i < op->data.xs->length; ++i) {
        xi = op->data.xs->items[i];
        if (BX_IS_CONST(xi)) {
            parity ^= (bool) xi->kind;
        }
        /* Xor(Xor(x0, x1), x2) <=> Xor(x0, x1, x2) */
        else if (BX_IS_XOR(xi)) {
            for (size_t j = 0; j < xi->data.xs->length; ++j) {
                xj = xi->data.xs->items[j];
                if (BX_IS_CONST(xj))
                    parity ^= (bool) xj->kind;
                else
                    flat[flat_len++] = xj;
            }
        }
        /* Xor(Xnor(x0, x1), x2) <=> Xnor(x0, x1, x2) */
        else if (BX_IS_XNOR(xi)) {
            parity ^= true;
            for (size_t j = 0; j < xi->data.xs->items[0]->data.xs->length; ++j) {
                xj = xi->data.xs->items[0]->data.xs->items[j];
                if (BX_IS_CONST(xj))
                    parity ^= (bool) xj->kind;
                else
                    flat[flat_len++] = xj;
            }
        }
        else {
            flat[flat_len++] = xi;
        }
    }

    /* 2. Sort arguments, so you get ~a, ~a, a, a, ~b, ... */
    qsort(flat, flat_len, sizeof(struct BoolExpr *), _cmp);

    uniq = malloc(flat_len * sizeof(struct BoolExpr *));
    if (uniq == NULL) {
        free(flat);  // LCOV_EXCL_LINE
        return NULL; // LCOV_EXCL_LINE
    }

    /* 3. Apply: Xor(~x, x) <=> 1, Xor(x, x) <=> 0 */
    for (size_t i = 0; i < flat_len; ++i) {
        if (uniq_len == 0) {
            uniq[uniq_len++] = flat[i];
        }
        else {
            /* Xor(~x, x) <=> 1 */
            if (COMPLEMENTARY(uniq[uniq_len-1], flat[i])) {
                parity ^= true;
                uniq_len -= 1;
            }
            /* Xor(x, x) <=> 0 */
            else if (_eq(flat[i], uniq[uniq_len-1])) {
                uniq_len -= 1;
            }
            else {
                uniq[uniq_len++] = flat[i];
            }
        }
    }

    free(flat);

    y = parity ? BX_Xor(uniq_len, uniq) : BX_Xnor(uniq_len, uniq);

    free(uniq);

    return y;
}