// map : (item ⇒ item) ⇒ tree ⇒ tree
#define MAP_IMPL(NAME) \
static uint64_t NAME(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)); \
static inline uint64_t NAME##__real(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __REAL) \
} \
static inline uint64_t NAME##__variable(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __VARIABLE) \
} \
static inline uint64_t NAME##__boolean(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __BOOLEAN) \
} \
static inline uint64_t NAME##__undefined(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __UNDEFINED) \
} \
static inline uint64_t NAME##__smallint(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __SMALLINT) \
} \
static inline uint64_t NAME##__largeint(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __LARGEINT) \
} \
static inline uint64_t NAME##__fraction(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t in_numerator = get_car(a, expr); \
uint64_t in_denominator = get_cdr(a, expr); \
uint64_t numerator = NAME(a, in_numerator ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
uint64_t denominator = NAME(a, in_denominator ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
bool changed = in_numerator != numerator || in_denominator != denominator; \
ALIAS_CPP_CAT(NAME, __FRACTION) \
} \
static inline uint64_t NAME##__power(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t in_base = get_car(a, expr); \
uint64_t in_exponent = get_cdr(a, expr); \
uint64_t base = NAME(a, in_base ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
uint64_t exponent = NAME(a, in_exponent ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
bool changed = in_base != base || in_exponent != exponent; \
ALIAS_CPP_CAT(NAME, __POWER) \
} \
static inline uint64_t NAME##__sum(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint32_t count = get_list_count(expr); \
const uint64_t *in_values = a->values.data + get_list_index(expr); \
uint64_t *values = a->values.data + get_list_index(expr); \
uint64_t mapped_value = 0; \
uint32_t i__ = 0; \
for(;i__ < count; i__++) { \
mapped_value = NAME(a, in_values[i__] ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
if(mapped_value != in_values[i__]) { \
break; \
} \
} \
bool changed = i__ != count; \
if(changed) { \
values = alias_stack_allocation(sizeof(*values) * count, alignof(*values)); \
alias_memory_copy(values, sizeof(*values) * i__, in_values, sizeof(*values) * i__); \
values[i__++] = mapped_value; \
for(;i__ < count; i__++) { \
values[i__] = NAME(a, in_values[i__] ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
} \
} \
ALIAS_CPP_CAT(NAME, __SUM) \
} \
static inline uint64_t NAME##__product(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint32_t count = get_list_count(expr); \
const uint64_t *in_values = a->values.data + get_list_index(expr); \
uint64_t *values = a->values.data + get_list_index(expr); \
uint64_t mapped_value = 0; \
uint32_t i__ = 0; \
for(;i__ < count; i__++) { \
mapped_value = NAME(a, in_values[i__] ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
if(mapped_value != in_values[i__]) { \
break; \
} \
} \
bool changed = i__ != count; \
if(changed) { \
values = alias_stack_allocation(sizeof(*values) * count, alignof(*values)); \
alias_memory_copy(values, sizeof(*values) * i__, in_values, sizeof(*values) * i__); \
values[i__++] = mapped_value; \
for(;i__ < count; i__++) { \
values[i__] = NAME(a, in_values[i__] ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
} \
} \
ALIAS_CPP_CAT(NAME, __PRODUCT) \
} \
static inline uint64_t NAME##__equals(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t in_lhs = get_car(a, expr); \
uint64_t in_rhs = get_cdr(a, expr); \
uint64_t lhs = NAME(a, in_lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
uint64_t rhs = NAME(a, in_rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
bool changed = in_lhs != lhs || in_rhs != rhs; \
ALIAS_CPP_CAT(NAME, __EQUALS) \
} \
static inline uint64_t NAME##__not_equals(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t in_lhs = get_car(a, expr); \
uint64_t in_rhs = get_cdr(a, expr); \
uint64_t lhs = NAME(a, in_lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
uint64_t rhs = NAME(a, in_rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
bool changed = in_lhs != lhs || in_rhs != rhs; \
ALIAS_CPP_CAT(NAME, __NOT_EQUALS) \
} \
static inline uint64_t NAME##__less_than(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t in_lhs = get_car(a, expr); \
uint64_t in_rhs = get_cdr(a, expr); \
uint64_t lhs = NAME(a, in_lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
uint64_t rhs = NAME(a, in_rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
bool changed = in_lhs != lhs || in_rhs != rhs; \
ALIAS_CPP_CAT(NAME, __LESS_THAN) \
} \
static inline uint64_t NAME##__greater_than(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t in_lhs = get_car(a, expr); \
uint64_t in_rhs = get_cdr(a, expr); \
uint64_t lhs = NAME(a, in_lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
uint64_t rhs = NAME(a, in_rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
bool changed = in_lhs != lhs || in_rhs != rhs; \
ALIAS_CPP_CAT(NAME, __GREATER_THAN) \
} \
static inline uint64_t NAME##__invalid(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __INVALID) \
} \
static uint64_t NAME(struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __FIRST_STATEMENT); \
switch(get_tag(expr)) { \
case Tag_Real: \
return NAME##__real(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Variable: \
return NAME##__variable(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Boolean: \
return NAME##__boolean(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Undefined: \
return NAME##__undefined(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_SmallInt: \
return NAME##__smallint(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_LargeInt: \
return NAME##__largeint(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Fraction: \
return NAME##__fraction(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Power: \
return NAME##__power(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Sum: \
return NAME##__sum(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Product: \
return NAME##__product(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Equals: \
return NAME##__equals(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_NotEquals: \
return NAME##__not_equals(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_LessThan: \
return NAME##__less_than(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_GreaterThan: \
return NAME##__greater_than(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
default: \
return NAME##__invalid(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
} \
}
#define MAP(NAME) ALIAS_CPP_EVAL_3(MAP_IMPL(NAME))
// any : (item ⇒ bool) ⇒ tree ⇒ bool
#define ANY_IMPL(NAME) \
static bool NAME(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)); \
static inline bool NAME##__real(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __REAL) \
return false; \
} \
static inline bool NAME##__variable(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __VARIABLE) \
return false; \
} \
static inline bool NAME##__boolean(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __BOOLEAN) \
return false; \
} \
static inline bool NAME##__undefined(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __UNDEFINED) \
return false; \
} \
static inline bool NAME##__smallint(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __SMALLINT) \
return false; \
} \
static inline bool NAME##__largeint(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __LARGEINT) \
return false; \
} \
static inline bool NAME##__fraction(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t numerator = get_car(a, expr); \
uint64_t denominator = get_cdr(a, expr); \
ALIAS_CPP_CAT(NAME, __FRACTION) \
if(NAME(a, numerator ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
if(NAME(a, denominator ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
return false; \
} \
static inline bool NAME##__power(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t base = get_car(a, expr); \
uint64_t exponent = get_cdr(a, expr); \
ALIAS_CPP_CAT(NAME, __POWER) \
if(NAME(a, base ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
if(NAME(a, exponent ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
return false; \
} \
static inline bool NAME##__sum(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint32_t count = get_list_count(expr); \
const uint64_t *values = a->values.data + get_list_index(expr); \
ALIAS_CPP_CAT(NAME, __SUM) \
for(uint32_t i = 0; i < count; i++) { \
if(NAME(a, values[i] ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
} \
return false; \
} \
static inline bool NAME##__product(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint32_t count = get_list_count(expr); \
const uint64_t *values = a->values.data + get_list_index(expr); \
ALIAS_CPP_CAT(NAME, __PRODUCT) \
for(uint32_t i = 0; i < count; i++) { \
if(NAME(a, values[i] ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
} \
return false; \
} \
static inline bool NAME##__equals(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t lhs = get_car(a, expr); \
uint64_t rhs = get_cdr(a, expr); \
ALIAS_CPP_CAT(NAME, __EQUALS) \
if(NAME(a, lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
if(NAME(a, rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
return false; \
} \
static inline bool NAME##__not_equals(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t lhs = get_car(a, expr); \
uint64_t rhs = get_cdr(a, expr); \
ALIAS_CPP_CAT(NAME, __NOT_EQUALS) \
if(NAME(a, lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
if(NAME(a, rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
return false; \
} \
static inline bool NAME##__less_than(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t lhs = get_car(a, expr); \
uint64_t rhs = get_cdr(a, expr); \
ALIAS_CPP_CAT(NAME, __LESS_THAN) \
if(NAME(a, lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
if(NAME(a, rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
return false; \
} \
static inline bool NAME##__greater_than(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
uint64_t lhs = get_car(a, expr); \
uint64_t rhs = get_cdr(a, expr); \
ALIAS_CPP_CAT(NAME, __GREATER_THAN) \
if(NAME(a, lhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
if(NAME(a, rhs ALIAS_CPP_CAT(NAME, __EXTRA_PASS))) { \
return true; \
} \
return false; \
} \
static inline bool NAME##__invalid(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __INVALID) \
return false; \
} \
static bool NAME(const struct solver_Algebra *a, uint64_t expr ALIAS_CPP_CAT(NAME, __EXTRA_PARAMS)) { \
ALIAS_CPP_CAT(NAME, __FIRST_STATEMENT); \
switch(get_tag(expr)) { \
case Tag_Real: \
return NAME##__real(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Variable: \
return NAME##__variable(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Boolean: \
return NAME##__boolean(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Undefined: \
return NAME##__undefined(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_SmallInt: \
return NAME##__smallint(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_LargeInt: \
return NAME##__largeint(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Fraction: \
return NAME##__fraction(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Power: \
return NAME##__power(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Sum: \
return NAME##__sum(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Product: \
return NAME##__product(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_Equals: \
return NAME##__equals(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_NotEquals: \
return NAME##__not_equals(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_LessThan: \
return NAME##__less_than(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
case Tag_GreaterThan: \
return NAME##__greater_than(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
default: \
return NAME##__invalid(a, expr ALIAS_CPP_CAT(NAME, __EXTRA_PASS)); \
} \
}
#define ANY(NAME) ALIAS_CPP_EVAL_3(ANY_IMPL(NAME))
// all : (item ⇒ bool) ⇒ tree ⇒ bool
// all_pair : (item ⇒ item ⇒ bool) ⇒ tree ⇒ tree ⇒ bool
// each : (item ⇒ void) ⇒ tree ⇒ void