skin this cat

This commit is contained in:
2024-02-22 16:02:31 -06:00
parent 2baee14c5d
commit 3811d82212
7 changed files with 595 additions and 181 deletions

View File

@@ -29,7 +29,7 @@ endif
OBJS := ckiwi.o luakiwi.o OBJS := ckiwi.o luakiwi.o
VPATH = $(SRCDIR)/ckiwi VPATH = $(SRCDIR)/ckiwi $(SRCDIR)/luakiwi
all: ckiwi.$(LIB_EXT) all: ckiwi.$(LIB_EXT)
@@ -45,7 +45,7 @@ ckiwi.$(LIB_EXT): $(OBJS)
$(CXX) $(CXXFLAGS) $(CFLAGS) $(CFLAGS_EXTRA) -I$(SRCDIR)/kiwi $(LIBFLAG) -o $@ $^ $(CXX) $(CXXFLAGS) $(CFLAGS) $(CFLAGS_EXTRA) -I$(SRCDIR)/kiwi $(LIBFLAG) -o $@ $^
ckiwi.o: ckiwi.h ckiwi.o: ckiwi.h
luakiwi.o: ckiwi.h luakiwi-int.h luacompat.h luakiwi.o: ckiwi.h kiwibridge.cpp luakiwi-int.h luacompat.h
%.o: %.c %.o: %.c
$(CC) -I$(LUA_INCDIR) $(CFLAGS) $(CFLAGS_EXTRA) -c -o $@ $< $(CC) -I$(LUA_INCDIR) $(CFLAGS) $(CFLAGS_EXTRA) -c -o $@ $<

View File

@@ -78,7 +78,6 @@ KiwiConstraintRef kiwi_constraint_new(
double strength double strength
); );
void kiwi_constraint_del(KiwiConstraintRef constraint); void kiwi_constraint_del(KiwiConstraintRef constraint);
KiwiConstraintRef kiwi_constraint_clone(KiwiConstraintRef constraint);
double kiwi_constraint_strength(KiwiConstraintRef constraint); double kiwi_constraint_strength(KiwiConstraintRef constraint);
enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint); enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint);

88
luakiwi/.clang-format Normal file
View File

@@ -0,0 +1,88 @@
AccessModifierOffset: -2
AlignAfterOpenBracket: BlockIndent # New in v14. For earlier clang-format versions, use AlwaysBreak instead.
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: DontAlign
AlignOperands: false
AlignTrailingComments: false
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Empty
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BreakAfterAttributes: Always
BreakBeforeBinaryOperators: NonAssignment
BreakBeforeBraces: Attach
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: AfterColon
BreakInheritanceList: AfterColon
BreakStringLiterals: false
ColumnLimit: 98
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
FixNamespaceComments: true
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*\.h>'
Priority: 1
SortPriority: 0
CaseSensitive: false
- Regex: '^<.*'
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: '.*'
Priority: 3
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: BeforeHash
IndentWidth: 3
IndentWrappedFunctionNames: false
KeepEmptyLinesAtTheStartOfBlocks: false
MaxEmptyLinesToKeep: 1
NamespaceIndentation: Inner
PointerAlignment: Left
ReferenceAlignment: Left # New in v13. int &name ==> int& name
ReflowComments: false
SeparateDefinitionBlocks: Always # New in v14.
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Cpp11
TabWidth: 4
UseTab: Never

331
luakiwi/kiwibridge.cpp Normal file
View File

@@ -0,0 +1,331 @@
#include <kiwi/kiwi.h>
#include <cstdlib>
#include <cstring>
namespace {
using namespace kiwi;
enum KiwiErrKind {
KiwiErrNone,
KiwiErrUnsatisfiableConstraint = 1,
KiwiErrUnknownConstraint,
KiwiErrDuplicateConstraint,
KiwiErrUnknownEditVariable,
KiwiErrDuplicateEditVariable,
KiwiErrBadRequiredStrength,
KiwiErrInternalSolverError,
KiwiErrAlloc,
KiwiErrNullObject,
KiwiErrUnknown,
};
enum KiwiRelOp { KIWI_OP_LE, KIWI_OP_GE, KIWI_OP_EQ };
typedef struct KiwiVarRefType* KiwiVarRef;
typedef struct KiwiConstraintRefType* KiwiConstraintRef;
struct KiwiTerm {
Variable* var;
double coefficient;
};
struct KiwiExpression {
double constant;
int term_count;
Constraint* owner;
KiwiTerm terms[1]; // LuaJIT: struct KiwiTerm terms_[?];
};
struct KiwiErr {
enum KiwiErrKind kind;
const char* message;
bool must_free;
};
struct KiwiSolver {
unsigned error_mask;
Solver solver;
};
template<typename T, typename R, typename... Args>
inline R make_cref(Args&&... args) {
static_assert(
sizeof(R) >= sizeof(T), // NOLINT(bugprone-sizeof-expression)
"to_cref: R too small for T"
);
static_assert(alignof(R) >= alignof(T), "to_cref: R alignment too small for T");
R cref;
new (&cref) T(std::forward<Args>(args)...);
return cref;
}
template<typename... Args>
inline decltype(auto) make_var_cref(Args&&... args) {
return make_cref<Variable, KiwiVarRef>(std::forward<Args>(args)...);
}
template<typename... Args>
inline decltype(auto) make_constraint_cref(Args&&... args) {
return make_cref<Constraint, KiwiConstraintRef>(std::forward<Args>(args)...);
}
template<class T, class R>
class SharedRef {
private:
R& cref_;
public:
explicit SharedRef<T, R>(R& cref) : cref_(cref) {}
static_assert(
sizeof(R) >= sizeof(T), // NOLINT(bugprone-sizeof-expression)
"SharedRef<T,CS> CS too small for T"
);
R clone() const {
return make_cref<T, R>(cref());
}
void release() {
if (cref_) {
ptr()->~T();
cref_ = nullptr;
}
}
T* ptr() {
T* p;
void* s = &cref_;
std::memcpy(&p, &s, sizeof p); // NOLINT(bugprone-sizeof-expression)
return p;
}
const T* const_ptr() const {
const T* p;
const void* s = &cref_;
std::memcpy(&p, &s, sizeof p); // NOLINT(bugprone-sizeof-expression)
return p;
}
const T& cref() const {
return *const_ptr();
}
T* operator&() const {
return ptr();
}
T* operator->() {
return ptr();
}
const T* operator->() const {
return const_ptr();
}
operator const T&() const {
return cref();
}
explicit operator bool() const {
return cref_;
}
};
using ConstraintRef = SharedRef<Constraint, KiwiConstraintRef>;
using VariableRef = SharedRef<Variable, KiwiVarRef>;
using ConstVariableRef = const SharedRef<const Variable, const KiwiVarRef>;
const KiwiErr* new_error(const KiwiErr* base, const std::exception& ex) {
if (!std::strcmp(ex.what(), base->message))
return base;
const auto msg_n = std::strlen(ex.what()) + 1;
auto* mem = static_cast<char*>(std::malloc(sizeof(KiwiErr) + msg_n));
if (!mem) {
return base;
}
const auto* err = new (mem) KiwiErr {base->kind, mem + sizeof(KiwiErr), true};
std::memcpy(const_cast<char*>(err->message), ex.what(), msg_n);
return err;
}
const constexpr KiwiErr kKiwiErrUnhandledCxxException {
KiwiErrUnknown,
"An unhandled C++ exception occurred."};
const constexpr KiwiErr kKiwiErrNullObjectArg0 {
KiwiErrNullObject,
"null object passed as argument #0 (self)"};
const constexpr KiwiErr kKiwiErrNullObjectArg1 {
KiwiErrNullObject,
"null object passed as argument #1"};
template<typename F>
inline const KiwiErr* wrap_err(F&& f) {
try {
f();
} catch (const UnsatisfiableConstraint& ex) {
static const constexpr KiwiErr err {
KiwiErrUnsatisfiableConstraint,
"The constraint cannot be satisfied."};
return &err;
} catch (const UnknownConstraint& ex) {
static const constexpr KiwiErr err {
KiwiErrUnknownConstraint,
"The constraint has not been added to the solver."};
return &err;
} catch (const DuplicateConstraint& ex) {
static const constexpr KiwiErr err {
KiwiErrDuplicateConstraint,
"The constraint has already been added to the solver."};
return &err;
} catch (const UnknownEditVariable& ex) {
static const constexpr KiwiErr err {
KiwiErrUnknownEditVariable,
"The edit variable has not been added to the solver."};
return &err;
} catch (const DuplicateEditVariable& ex) {
static const constexpr KiwiErr err {
KiwiErrDuplicateEditVariable,
"The edit variable has already been added to the solver."};
return &err;
} catch (const BadRequiredStrength& ex) {
static const constexpr KiwiErr err {
KiwiErrBadRequiredStrength,
"A required strength cannot be used in this context."};
return &err;
} catch (const InternalSolverError& ex) {
static const constexpr KiwiErr base {
KiwiErrInternalSolverError,
"An internal solver error occurred."};
return new_error(&base, ex);
} catch (std::bad_alloc&) {
static const constexpr KiwiErr err {KiwiErrAlloc, "A memory allocation failed."};
return &err;
} catch (const std::exception& ex) {
return new_error(&kKiwiErrUnhandledCxxException, ex);
} catch (...) {
return &kKiwiErrUnhandledCxxException;
}
return nullptr;
}
template<typename P, typename R, typename F>
inline const KiwiErr* wrap_err(P ptr, F&& f) {
if (!ptr) {
return &kKiwiErrNullObjectArg0;
}
return wrap_err([&]() { f(ptr); });
}
template<typename P, typename R, typename F>
inline const KiwiErr* wrap_err(P ptr, R& ref, F&& f) {
if (!ptr) {
return &kKiwiErrNullObjectArg0;
}
return wrap_err([&]() { f(ptr, ref); });
}
// inline void kiwi_var_del(KiwiVarRef var) { VariableRef(var).release(); }
inline Variable* kiwi_var_retain(Variable* var) {
alignas(Variable) unsigned char buf[sizeof(Variable)];
new (buf) Variable(*var);
return var;
}
inline Constraint* kiwi_constraint_retain(Constraint* c) {
alignas(Constraint) unsigned char buf[sizeof(Constraint)];
new (buf) Constraint(*c);
return c;
}
inline void kiwi_constraint_new(
const KiwiExpression* lhs,
const KiwiExpression* rhs,
enum KiwiRelOp op,
double strength,
Constraint* mem
) {
if (strength < 0.0) {
strength = kiwi::strength::required;
}
std::vector<Term> terms;
terms.reserve((lhs ? lhs->term_count : 0) + (rhs ? rhs->term_count : 0));
if (lhs) {
// FIXME FIXME: this should cause a copy!
for (auto* t = lhs->terms; t != lhs->terms + lhs->term_count; ++t) {
terms.emplace_back(*t->var, t->coefficient);
}
}
if (rhs) {
for (auto* t = rhs->terms; t != rhs->terms + rhs->term_count; ++t) {
terms.emplace_back(*t->var, -t->coefficient);
}
}
new (mem) Constraint(
Expression(std::move(terms), (lhs ? lhs->constant : 0.0) - (rhs ? rhs->constant : 0.0)),
static_cast<RelationalOperator>(op),
strength
);
}
int kiwi_constraint_expression(const Constraint* c, KiwiExpression* out, int out_size) {
const auto& expr = c->expression();
const auto& terms = expr.terms();
const int n_terms = terms.size();
if (!out || out_size < n_terms)
return n_terms;
// FIXME FIXME FIXME: dangling pointer
auto* p = out->terms;
for (const auto& t : terms) {
Variable* v = const_cast<Variable*>(&t.variable());
*p = KiwiTerm {v, t.coefficient()};
++p;
}
out->term_count = p - out->terms;
out->constant = expr.constant();
return n_terms;
}
inline const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, const Constraint& constraint) {
return wrap_err(s, constraint, [](auto* s, const auto& c) { s->solver.addConstraint(c); });
}
inline const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, const Constraint& constraint) {
return wrap_err(s, constraint, [](auto* s, const auto& c) { s->solver.removeConstraint(c); });
}
inline const KiwiErr*
kiwi_solver_add_edit_var(KiwiSolver* s, const Variable& var, double strength) {
return wrap_err(s, var, [strength](auto* s, const auto& v) {
s->solver.addEditVariable(v, strength);
});
}
inline const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, const Variable& var) {
return wrap_err(s, var, [](auto* s, const auto& v) { s->solver.removeEditVariable(v); });
}
inline const KiwiErr*
kiwi_solver_suggest_value(KiwiSolver* s, const Variable& var, double value) {
return wrap_err(s, var, [value](auto* s, const auto& v) { s->solver.suggestValue(v, value); });
}
} // namespace

View File

@@ -2,7 +2,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "ckiwi.h" #include "kiwibridge.cpp"
#include "luacompat.h" #include "luacompat.h"
#include "luakiwi-int.h" #include "luakiwi-int.h"
@@ -144,17 +144,16 @@ static inline void* try_type(lua_State* L, int idx, enum TypeId type_id) {
return lua_rawequal(L, -1, -2) ? p : 0; return lua_rawequal(L, -1, -2) ? p : 0;
} }
static inline KiwiVarRef try_var(lua_State* L, int idx) { static inline Variable* try_var(lua_State* L, int idx) {
void* p = try_type(L, idx, VAR); return static_cast<Variable*>(try_type(L, idx, VAR));
return p ? *(KiwiVarRef*)p : 0;
} }
static inline KiwiTerm* try_term(lua_State* L, int idx) { static inline KiwiTerm* try_term(lua_State* L, int idx) {
return (KiwiTerm*)try_type(L, idx, TERM); return static_cast<KiwiTerm*>(try_type(L, idx, TERM));
} }
static inline KiwiExpression* try_expr(lua_State* L, int idx) { static inline KiwiExpression* try_expr(lua_State* L, int idx) {
return (KiwiExpression*)try_type(L, idx, EXPR); return static_cast<KiwiExpression*>(try_type(L, idx, EXPR));
} }
// method to test types for expression functions // method to test types for expression functions
@@ -190,51 +189,52 @@ static inline void* try_arg(lua_State* L, int idx, enum TypeId* type_id, double*
return 0; return 0;
} }
static inline KiwiVarRef get_var(lua_State* L, int idx) { static inline Variable* get_var(lua_State* L, int idx) {
return *((KiwiVarRef*)check_arg(L, idx, VAR)); return static_cast<Variable*>(check_arg(L, idx, VAR));
} }
static inline KiwiTerm* get_term(lua_State* L, int idx) { static inline KiwiTerm* get_term(lua_State* L, int idx) {
return (KiwiTerm*)check_arg(L, idx, TERM); return static_cast<KiwiTerm*>(check_arg(L, idx, TERM));
} }
static inline KiwiExpression* get_expr(lua_State* L, int idx) { static inline KiwiExpression* get_expr(lua_State* L, int idx) {
return (KiwiExpression*)check_arg(L, idx, EXPR); return static_cast<KiwiExpression*>(check_arg(L, idx, EXPR));
} }
static inline KiwiExpression* get_expr_opt(lua_State* L, int idx) { static inline KiwiExpression* get_expr_opt(lua_State* L, int idx) {
if (lua_isnoneornil(L, idx)) { if (lua_isnoneornil(L, idx)) {
return 0; return 0;
} }
return (KiwiExpression*)check_arg(L, idx, EXPR); return static_cast<KiwiExpression*>(check_arg(L, idx, EXPR));
} }
static inline KiwiConstraintRef get_constraint(lua_State* L, int idx) { static inline Constraint* get_constraint(lua_State* L, int idx) {
return *((KiwiConstraintRef*)check_arg(L, idx, CONSTRAINT)); return static_cast<Constraint*>(check_arg(L, idx, CONSTRAINT));
} }
static inline KiwiSolver* get_solver(lua_State* L, int idx) { static inline KiwiSolver* get_solver(lua_State* L, int idx) {
return *(KiwiSolver**)check_arg(L, idx, SOLVER); return static_cast<KiwiSolver*>(check_arg(L, idx, SOLVER));
} }
// note this expects the 2nd upvalue to have the variable weak table // note this expects the 2nd upvalue to have the variable weak table
static inline KiwiVarRef var_new(lua_State* L, KiwiVarRef var) { template<typename... Args>
KiwiVarRef* varp = (KiwiVarRef*)lua_newuserdata(L, sizeof(KiwiVarRef)); static inline Variable* var_new(lua_State* L, Args&&... args) {
*varp = var; auto* p = static_cast<Variable*>(lua_newuserdata(L, sizeof(Variable)));
new (p) Variable(std::forward<Args>(args)...);
push_type(L, VAR); push_type(L, VAR);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
// a true compatibility shim has performance implications here // a true compatibility shim has performance implications here
lua_pushlightuserdata(L, var); lua_pushlightuserdata(L, p);
lua_pushvalue(L, -2); lua_pushvalue(L, -2);
lua_rawset(L, lua_upvalueindex(2)); lua_rawset(L, lua_upvalueindex(2));
#else #else
lua_pushvalue(L, -1); lua_pushvalue(L, -1);
lua_rawsetp(L, lua_upvalueindex(2), var); lua_rawsetp(L, lua_upvalueindex(2), p);
#endif #endif
return var; return p;
} }
static inline KiwiTerm* term_new(lua_State* L) { static inline KiwiTerm* term_new(lua_State* L) {
@@ -254,19 +254,19 @@ static inline KiwiExpression* expr_new(lua_State* L, int nterms) {
return ret; return ret;
} }
static inline KiwiConstraintRef constraint_new( static inline Constraint* constraint_new(
lua_State* L, lua_State* L,
const KiwiExpression* lhs, const KiwiExpression* lhs,
const KiwiExpression* rhs, const KiwiExpression* rhs,
enum KiwiRelOp op, enum KiwiRelOp op,
double strength double strength
) { ) {
KiwiConstraintRef* ref = (KiwiConstraintRef*)lua_newuserdata(L, sizeof(KiwiConstraintRef)); auto* ref = static_cast<Constraint*>(lua_newuserdata(L, sizeof(Constraint)));
*ref = kiwi_constraint_new(lhs, rhs, op, strength); kiwi_constraint_new(lhs, rhs, op, strength, ref);
push_type(L, CONSTRAINT); push_type(L, CONSTRAINT);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return *ref; return ref;
} }
// stack disposition: dirty // stack disposition: dirty
@@ -291,7 +291,7 @@ static KiwiExpression* toexpr(lua_State* L, int idx, KiwiExpression* temp) {
temp->term_count = 1; temp->term_count = 1;
push_type(L, VAR); push_type(L, VAR);
if (lua_rawequal(L, -1, -3)) { if (lua_rawequal(L, -1, -3)) {
temp->terms[0].var = *(KiwiVarRef*)ud; temp->terms[0].var = static_cast<Variable*>(ud);
temp->terms[0].coefficient = 1.0; temp->terms[0].coefficient = 1.0;
return temp; return temp;
} }
@@ -334,7 +334,7 @@ static inline int push_expr_one(lua_State* L, double constant, const KiwiTerm* t
expr->constant = constant; expr->constant = constant;
expr->term_count = 1; expr->term_count = 1;
expr->terms[0].coefficient = term->coefficient; expr->terms[0].coefficient = term->coefficient;
expr->terms[0].var = kiwi_var_clone(term->var); expr->terms[0].var = kiwi_var_retain(term->var);
return 1; return 1;
} }
@@ -344,21 +344,21 @@ push_expr_pair(lua_State* L, double constant, const KiwiTerm* ta, const KiwiTerm
e->constant = constant; e->constant = constant;
e->term_count = 2; e->term_count = 2;
e->terms[0].coefficient = ta->coefficient; e->terms[0].coefficient = ta->coefficient;
e->terms[0].var = kiwi_var_clone(ta->var); e->terms[0].var = kiwi_var_retain(ta->var);
e->terms[1].coefficient = tb->coefficient; e->terms[1].coefficient = tb->coefficient;
e->terms[1].var = kiwi_var_clone(tb->var); e->terms[1].var = kiwi_var_retain(tb->var);
return 1; return 1;
} }
static inline int static inline int
push_expr_var_term(lua_State* L, double constant, KiwiVarRef var, const KiwiTerm* t) { push_expr_var_term(lua_State* L, double constant, Variable* var, const KiwiTerm* t) {
KiwiExpression* e = expr_new(L, 2); KiwiExpression* e = expr_new(L, 2);
e->constant = constant; e->constant = constant;
e->term_count = 2; e->term_count = 2;
e->terms[0].coefficient = 1.0; e->terms[0].coefficient = 1.0;
e->terms[0].var = kiwi_var_clone(var); e->terms[0].var = kiwi_var_retain(var);
e->terms[1].coefficient = t->coefficient; e->terms[1].coefficient = t->coefficient;
e->terms[1].var = kiwi_var_clone(t->var); e->terms[1].var = kiwi_var_retain(t->var);
return 1; return 1;
} }
@@ -369,42 +369,42 @@ static int push_add_expr_term(lua_State* L, const KiwiExpression* expr, const Ki
int i = 0; int i = 0;
for (; i < expr->term_count; ++i) { for (; i < expr->term_count; ++i) {
e->terms[i].coefficient = expr->terms[i].coefficient; e->terms[i].coefficient = expr->terms[i].coefficient;
e->terms[i].var = kiwi_var_clone(expr->terms[i].var); e->terms[i].var = kiwi_var_retain(expr->terms[i].var);
} }
e->terms[i].coefficient = t->coefficient; e->terms[i].coefficient = t->coefficient;
e->terms[i].var = kiwi_var_clone(t->var); e->terms[i].var = kiwi_var_retain(t->var);
return 1; return 1;
} }
static int lkiwi_var_m_add(lua_State* L) { static int lkiwi_var_m_add(lua_State* L) {
enum TypeId type_id_b; enum TypeId type_id_b;
double num; double num;
const void* arg_b = try_arg(L, 2, &type_id_b, &num); void* arg_b = try_arg(L, 2, &type_id_b, &num);
if (type_id_b == VAR) { if (type_id_b == VAR) {
int isnum_a; int isnum_a;
num = lua_tonumberx(L, 1, &isnum_a); num = lua_tonumberx(L, 1, &isnum_a);
if (isnum_a) { if (isnum_a) {
const KiwiTerm t = {*(KiwiVarRef*)arg_b, 1.0}; const KiwiTerm t {static_cast<Variable*>(arg_b), 1.0};
return push_expr_one(L, num, &t); return push_expr_one(L, num, &t);
} }
} }
KiwiVarRef var_a = try_var(L, 1); Variable* var_a = try_var(L, 1);
if (var_a) { if (var_a) {
switch (type_id_b) { switch (type_id_b) {
case VAR: { case VAR: {
const KiwiTerm ta = {var_a, 1.0}, tb = {*(KiwiVarRef*)arg_b, 1.0}; const KiwiTerm ta {var_a, 1.0}, tb {static_cast<Variable*>(arg_b), 1.0};
return push_expr_pair(L, 0.0, &ta, &tb); return push_expr_pair(L, 0.0, &ta, &tb);
} }
case TERM: case TERM:
return push_expr_var_term(L, 0.0, var_a, (const KiwiTerm*)arg_b); return push_expr_var_term(L, 0.0, var_a, (static_cast<KiwiTerm*>(arg_b)));
case EXPR: { case EXPR: {
const KiwiTerm t = {var_a, 1.0}; const KiwiTerm t {var_a, 1.0};
return push_add_expr_term(L, (const KiwiExpression*)arg_b, &t); return push_add_expr_term(L, static_cast<KiwiExpression*>(arg_b), &t);
} }
case NUMBER: { case NUMBER: {
const KiwiTerm t = {var_a, 1.0}; const KiwiTerm t {var_a, 1.0};
return push_expr_one(L, num, &t); return push_expr_one(L, num, &t);
} }
default: default:
@@ -437,10 +437,10 @@ static int lkiwi_var_m_mul(lua_State* L) {
} }
if (isnum) { if (isnum) {
KiwiVarRef var = try_var(L, varidx); auto* var = try_var(L, varidx);
if (var) { if (var) {
KiwiTerm* term = term_new(L); auto* term = term_new(L);
term->var = kiwi_var_clone(var); term->var = kiwi_var_retain(var);
term->coefficient = num; term->coefficient = num;
return 1; return 1;
} }
@@ -449,82 +449,78 @@ static int lkiwi_var_m_mul(lua_State* L) {
} }
static int lkiwi_var_m_div(lua_State* L) { static int lkiwi_var_m_div(lua_State* L) {
KiwiVarRef var = try_var(L, 1); auto* var = try_var(L, 1);
int isnum; int isnum;
double num = lua_tonumberx(L, 2, &isnum); double num = lua_tonumberx(L, 2, &isnum);
if (!var || !isnum) { if (!var || !isnum) {
return op_error(L, "/", 1, 2); return op_error(L, "/", 1, 2);
} }
KiwiTerm* term = term_new(L); KiwiTerm* term = term_new(L);
term->var = kiwi_var_clone(var); term->var = kiwi_var_retain(var);
term->coefficient = 1.0 / num; term->coefficient = 1.0 / num;
return 1; return 1;
} }
static int lkiwi_var_m_unm(lua_State* L) { static int lkiwi_var_m_unm(lua_State* L) {
KiwiVarRef var = get_var(L, 1); auto* term = term_new(L);
KiwiTerm* term = term_new(L); term->var = kiwi_var_retain(get_var(L, 1));
term->var = kiwi_var_clone(var);
term->coefficient = -1.0; term->coefficient = -1.0;
return 1; return 1;
} }
static int lkiwi_var_m_eq(lua_State* L) { static int lkiwi_var_m_eq(lua_State* L) {
lua_pushboolean(L, get_var(L, 1) == get_var(L, 2)); lua_pushboolean(L, get_var(L, 1)->equals(*get_var(L, 2)));
return 1; return 1;
} }
static int lkiwi_var_m_tostring(lua_State* L) { static int lkiwi_var_m_tostring(lua_State* L) {
KiwiVarRef var = get_var(L, 1); auto* var = get_var(L, 1);
lua_pushfstring(L, "%s(%f)", kiwi_var_name(var), kiwi_var_value(var)); lua_pushfstring(L, "%s(%f)", var->name().c_str(), var->value());
return 1; return 1;
} }
static int lkiwi_var_m_gc(lua_State* L) { static int lkiwi_var_m_gc(lua_State* L) {
KiwiVarRef var = get_var(L, 1); get_var(L, 1)->~Variable();
kiwi_var_del(var);
return 0; return 0;
} }
static int lkiwi_var_set_name(lua_State* L) { static int lkiwi_var_set_name(lua_State* L) {
KiwiVarRef var = get_var(L, 1); auto* var = get_var(L, 1);
const char* name = luaL_checkstring(L, 2); const char* name = luaL_checkstring(L, 2);
kiwi_var_set_name(var, name); var->setName(name);
return 0; return 0;
} }
static int lkiwi_var_name(lua_State* L) { static int lkiwi_var_name(lua_State* L) {
KiwiVarRef var = get_var(L, 1); lua_pushstring(L, get_var(L, 1)->name().c_str());
lua_pushstring(L, kiwi_var_name(var));
return 1; return 1;
} }
static int lkiwi_var_set(lua_State* L) { static int lkiwi_var_set(lua_State* L) {
KiwiVarRef var = get_var(L, 1); auto* var = get_var(L, 1);
const double value = luaL_checknumber(L, 2); const double value = luaL_checknumber(L, 2);
kiwi_var_set_value(var, value); var->setValue(value);
return 0; return 0;
} }
static int lkiwi_var_value(lua_State* L) { static int lkiwi_var_value(lua_State* L) {
KiwiVarRef var = get_var(L, 1); lua_pushnumber(L, get_var(L, 1)->value());
lua_pushnumber(L, kiwi_var_value(var));
return 1; return 1;
} }
static int lkiwi_var_toterm(lua_State* L) { static int lkiwi_var_toterm(lua_State* L) {
KiwiVarRef var = get_var(L, 1); auto* var = get_var(L, 1);
double coefficient = luaL_optnumber(L, 2, 1.0); double coefficient = luaL_optnumber(L, 2, 1.0);
auto* term = term_new(L);
KiwiTerm* term = term_new(L); term->var = kiwi_var_retain(var);
term->var = kiwi_var_clone(var);
term->coefficient = coefficient; term->coefficient = coefficient;
return 1; return 1;
} }
static int lkiwi_var_toexpr(lua_State* L) { static int lkiwi_var_toexpr(lua_State* L) {
const KiwiTerm t = {get_var(L, 1), 1.0}; const KiwiTerm t {get_var(L, 1), 1.0};
return push_expr_one(L, 0.0, &t); return push_expr_one(L, 0.0, &t);
} }
@@ -550,7 +546,7 @@ static const struct luaL_Reg kiwi_var_m[] = {
static int lkiwi_var_new(lua_State* L) { static int lkiwi_var_new(lua_State* L) {
const char* name = luaL_optstring(L, 1, ""); const char* name = luaL_optstring(L, 1, "");
var_new(L, kiwi_var_new(name)); var_new(L, name);
return 1; return 1;
} }
@@ -564,10 +560,10 @@ static int lkiwi_term_m_mul(lua_State* L) {
} }
if (isnum) { if (isnum) {
const KiwiTerm* term = try_term(L, termidx); const auto* term = try_term(L, termidx);
if (term) { if (term) {
KiwiTerm* ret = term_new(L); auto* ret = term_new(L);
ret->var = kiwi_var_clone(term->var); ret->var = kiwi_var_retain(term->var);
ret->coefficient = term->coefficient * num; ret->coefficient = term->coefficient * num;
return 1; return 1;
} }
@@ -583,7 +579,7 @@ static int lkiwi_term_m_div(lua_State* L) {
return op_error(L, "/", 1, 2); return op_error(L, "/", 1, 2);
} }
KiwiTerm* ret = term_new(L); KiwiTerm* ret = term_new(L);
ret->var = kiwi_var_clone(term->var); ret->var = kiwi_var_retain(term->var);
ret->coefficient = term->coefficient / num; ret->coefficient = term->coefficient / num;
return 1; return 1;
} }
@@ -591,7 +587,7 @@ static int lkiwi_term_m_div(lua_State* L) {
static int lkiwi_term_m_unm(lua_State* L) { static int lkiwi_term_m_unm(lua_State* L) {
const KiwiTerm* term = get_term(L, 1); const KiwiTerm* term = get_term(L, 1);
KiwiTerm* ret = term_new(L); KiwiTerm* ret = term_new(L);
ret->var = kiwi_var_clone(term->var); ret->var = kiwi_var_retain(term->var);
ret->coefficient = -term->coefficient; ret->coefficient = -term->coefficient;
return 1; return 1;
} }
@@ -599,7 +595,7 @@ static int lkiwi_term_m_unm(lua_State* L) {
static int lkiwi_term_m_add(lua_State* L) { static int lkiwi_term_m_add(lua_State* L) {
enum TypeId type_id_b; enum TypeId type_id_b;
double num; double num;
const void* arg_b = try_arg(L, 2, &type_id_b, &num); void* arg_b = try_arg(L, 2, &type_id_b, &num);
if (type_id_b == TERM) { if (type_id_b == TERM) {
int isnum_a; int isnum_a;
@@ -613,13 +609,13 @@ static int lkiwi_term_m_add(lua_State* L) {
if (term_a) { if (term_a) {
switch (type_id_b) { switch (type_id_b) {
case TERM: case TERM:
return push_expr_pair(L, 0.0, term_a, (const KiwiTerm*)arg_b); return push_expr_pair(L, 0.0, term_a, static_cast<KiwiTerm*>(arg_b));
case VAR: { case VAR: {
const KiwiTerm term_b = {*(KiwiVarRef*)arg_b, 1.0}; const KiwiTerm term_b {static_cast<Variable*>(arg_b), 1.0};
return push_expr_pair(L, 0.0, term_a, &term_b); return push_expr_pair(L, 0.0, term_a, &term_b);
} }
case EXPR: case EXPR:
return push_add_expr_term(L, (const KiwiExpression*)arg_b, term_a); return push_add_expr_term(L, static_cast<KiwiExpression*>(arg_b), term_a);
case NUMBER: case NUMBER:
return push_expr_one(L, num, term_a); return push_expr_one(L, num, term_a);
default: default:
@@ -641,25 +637,24 @@ static int lkiwi_term_toexpr(lua_State* L) {
} }
static int lkiwi_term_value(lua_State* L) { static int lkiwi_term_value(lua_State* L) {
KiwiTerm* term = get_term(L, 1); const auto* term = get_term(L, 1);
lua_pushnumber(L, kiwi_var_value(term->var) * term->coefficient); lua_pushnumber(L, term->var->value() * term->coefficient);
return 1; return 1;
} }
static int lkiwi_term_m_tostring(lua_State* L) { static int lkiwi_term_m_tostring(lua_State* L) {
KiwiTerm* term = get_term(L, 1); const auto* term = get_term(L, 1);
lua_pushfstring(L, "%f %s", term->coefficient, kiwi_var_name(term->var)); lua_pushfstring(L, "%f %s", term->coefficient, term->var->name().c_str());
return 1; return 1;
} }
static int lkiwi_term_m_gc(lua_State* L) { static int lkiwi_term_m_gc(lua_State* L) {
KiwiTerm* term = get_term(L, 1); get_term(L, 1)->var->~Variable();
kiwi_var_del(term->var);
return 0; return 0;
} }
static int lkiwi_term_m_index(lua_State* L) { static int lkiwi_term_m_index(lua_State* L) {
KiwiTerm* term = get_term(L, 1); const auto* term = get_term(L, 1);
size_t len; size_t len;
const char* k = lua_tolstring(L, 2, &len); const char* k = lua_tolstring(L, 2, &len);
if (len == 3 && memcmp("var", k, len) == 0) { if (len == 3 && memcmp("var", k, len) == 0) {
@@ -670,7 +665,7 @@ static int lkiwi_term_m_index(lua_State* L) {
lua_rawgetp(L, lua_upvalueindex(2), term->var); lua_rawgetp(L, lua_upvalueindex(2), term->var);
#endif #endif
if (lua_isnil(L, -1)) if (lua_isnil(L, -1))
var_new(L, kiwi_var_clone(term->var)); var_new(L, *term->var);
return 1; return 1;
} else if (len == 11 && memcmp("coefficient", k, len) == 0) { } else if (len == 11 && memcmp("coefficient", k, len) == 0) {
lua_pushnumber(L, term->coefficient); lua_pushnumber(L, term->coefficient);
@@ -702,18 +697,18 @@ static const struct luaL_Reg kiwi_term_m[] = {
{0, 0}}; {0, 0}};
static int lkiwi_term_new(lua_State* L) { static int lkiwi_term_new(lua_State* L) {
KiwiVarRef var = get_var(L, 1); auto* var = get_var(L, 1);
double coefficient = luaL_optnumber(L, 2, 1.0); double coefficient = luaL_optnumber(L, 2, 1.0);
KiwiTerm* term = term_new(L); auto* term = term_new(L);
term->var = kiwi_var_clone(var); term->var = kiwi_var_retain(var);
term->coefficient = coefficient; term->coefficient = coefficient;
return 1; return 1;
} }
static int push_expr_constant(lua_State* L, const KiwiExpression* expr, double constant) { static int push_expr_constant(lua_State* L, const KiwiExpression* expr, double constant) {
KiwiExpression* ne = expr_new(L, expr->term_count); auto* ne = expr_new(L, expr->term_count);
for (int i = 0; i < expr->term_count; i++) { for (int i = 0; i < expr->term_count; i++) {
ne->terms[i].var = kiwi_var_clone(expr->terms[i].var); ne->terms[i].var = kiwi_var_retain(expr->terms[i].var);
ne->terms[i].coefficient = expr->terms[i].coefficient; ne->terms[i].coefficient = expr->terms[i].coefficient;
} }
ne->constant = constant; ne->constant = constant;
@@ -722,11 +717,11 @@ static int push_expr_constant(lua_State* L, const KiwiExpression* expr, double c
} }
static int push_mul_expr_coeff(lua_State* L, const KiwiExpression* expr, double coeff) { static int push_mul_expr_coeff(lua_State* L, const KiwiExpression* expr, double coeff) {
KiwiExpression* ne = expr_new(L, expr->term_count); auto* ne = expr_new(L, expr->term_count);
ne->constant = expr->constant * coeff; ne->constant = expr->constant * coeff;
ne->term_count = expr->term_count; ne->term_count = expr->term_count;
for (int i = 0; i < expr->term_count; i++) { for (int i = 0; i < expr->term_count; i++) {
ne->terms[i].var = kiwi_var_clone(expr->terms[i].var); ne->terms[i].var = kiwi_var_retain(expr->terms[i].var);
ne->terms[i].coefficient = expr->terms[i].coefficient * coeff; ne->terms[i].coefficient = expr->terms[i].coefficient * coeff;
} }
return 1; return 1;
@@ -735,16 +730,16 @@ static int push_mul_expr_coeff(lua_State* L, const KiwiExpression* expr, double
static int push_add_expr_expr(lua_State* L, const KiwiExpression* a, const KiwiExpression* b) { static int push_add_expr_expr(lua_State* L, const KiwiExpression* a, const KiwiExpression* b) {
int na = a->term_count, nb = b->term_count; int na = a->term_count, nb = b->term_count;
KiwiExpression* ne = expr_new(L, na + nb); auto* ne = expr_new(L, na + nb);
ne->constant = a->constant + b->constant; ne->constant = a->constant + b->constant;
ne->term_count = na + nb; ne->term_count = na + nb;
for (int i = 0; i < na; i++) { for (int i = 0; i < na; i++) {
ne->terms[i].var = kiwi_var_clone(a->terms[i].var); ne->terms[i].var = kiwi_var_retain(a->terms[i].var);
ne->terms[i].coefficient = a->terms[i].coefficient; ne->terms[i].coefficient = a->terms[i].coefficient;
} }
for (int i = 0; i < nb; i++) { for (int i = 0; i < nb; i++) {
ne->terms[i + na].var = kiwi_var_clone(b->terms[i].var); ne->terms[i + na].var = kiwi_var_retain(b->terms[i].var);
ne->terms[i + na].coefficient = b->terms[i].coefficient; ne->terms[i + na].coefficient = b->terms[i].coefficient;
} }
return 1; return 1;
@@ -760,7 +755,7 @@ static int lkiwi_expr_m_mul(lua_State* L) {
} }
if (isnum) { if (isnum) {
const KiwiExpression* expr = try_expr(L, expridx); const auto* expr = try_expr(L, expridx);
if (expr) if (expr)
return push_mul_expr_coeff(L, expr, num); return push_mul_expr_coeff(L, expr, num);
} }
@@ -768,7 +763,7 @@ static int lkiwi_expr_m_mul(lua_State* L) {
} }
static int lkiwi_expr_m_div(lua_State* L) { static int lkiwi_expr_m_div(lua_State* L) {
const KiwiExpression* expr = try_expr(L, 1); const auto* expr = try_expr(L, 1);
int isnum; int isnum;
double num = lua_tonumberx(L, 2, &isnum); double num = lua_tonumberx(L, 2, &isnum);
if (!expr || !isnum) { if (!expr || !isnum) {
@@ -778,20 +773,20 @@ static int lkiwi_expr_m_div(lua_State* L) {
} }
static int lkiwi_expr_m_unm(lua_State* L) { static int lkiwi_expr_m_unm(lua_State* L) {
const KiwiExpression* expr = get_expr(L, 1); const auto* expr = get_expr(L, 1);
return push_mul_expr_coeff(L, expr, -1.0); return push_mul_expr_coeff(L, expr, -1.0);
} }
static int lkiwi_expr_m_add(lua_State* L) { static int lkiwi_expr_m_add(lua_State* L) {
enum TypeId type_id_b; enum TypeId type_id_b;
double num; double num;
const void* arg_b = try_arg(L, 2, &type_id_b, &num); void* arg_b = try_arg(L, 2, &type_id_b, &num);
if (type_id_b == EXPR) { if (type_id_b == EXPR) {
int isnum_a; int isnum_a;
num = lua_tonumberx(L, 1, &isnum_a); num = lua_tonumberx(L, 1, &isnum_a);
if (isnum_a) { if (isnum_a) {
const KiwiExpression* expr_b = (const KiwiExpression*)arg_b; auto* expr_b = static_cast<const KiwiExpression*>(arg_b);
return push_expr_constant(L, expr_b, num + expr_b->constant); return push_expr_constant(L, expr_b, num + expr_b->constant);
} }
} }
@@ -800,11 +795,11 @@ static int lkiwi_expr_m_add(lua_State* L) {
if (expr_a) { if (expr_a) {
switch (type_id_b) { switch (type_id_b) {
case EXPR: case EXPR:
return push_add_expr_expr(L, expr_a, (const KiwiExpression*)arg_b); return push_add_expr_expr(L, expr_a, static_cast<KiwiExpression*>(arg_b));
case TERM: case TERM:
return push_add_expr_term(L, expr_a, (const KiwiTerm*)arg_b); return push_add_expr_term(L, expr_a, static_cast<KiwiTerm*>(arg_b));
case VAR: { case VAR: {
const KiwiTerm term_b = {*(KiwiVarRef*)arg_b, 1.0}; const KiwiTerm term_b {static_cast<Variable*>(arg_b), 1.0};
return push_add_expr_term(L, expr_a, &term_b); return push_add_expr_term(L, expr_a, &term_b);
} }
case NUMBER: case NUMBER:
@@ -824,23 +819,23 @@ static int lkiwi_expr_m_sub(lua_State* L) {
} }
static int lkiwi_expr_value(lua_State* L) { static int lkiwi_expr_value(lua_State* L) {
KiwiExpression* expr = get_expr(L, 1); const auto* expr = get_expr(L, 1);
double sum = expr->constant; double sum = expr->constant;
for (int i = 0; i < expr->term_count; i++) { for (int i = 0; i < expr->term_count; i++) {
const KiwiTerm* t = &expr->terms[i]; const auto* t = &expr->terms[i];
sum += kiwi_var_value(t->var) * t->coefficient; sum += t->var->value() * t->coefficient;
} }
lua_pushnumber(L, sum); lua_pushnumber(L, sum);
return 1; return 1;
} }
static int lkiwi_expr_terms(lua_State* L) { static int lkiwi_expr_terms(lua_State* L) {
KiwiExpression* expr = get_expr(L, 1); const auto* expr = get_expr(L, 1);
lua_createtable(L, expr->term_count, 0); lua_createtable(L, expr->term_count, 0);
for (int i = 0; i < expr->term_count; i++) { for (int i = 0; i < expr->term_count; i++) {
KiwiTerm* t = &expr->terms[i]; const auto* t = &expr->terms[i];
KiwiTerm* new_term = term_new(L); auto* new_term = term_new(L);
new_term->var = kiwi_var_clone(t->var); new_term->var = kiwi_var_retain(t->var);
new_term->coefficient = t->coefficient; new_term->coefficient = t->coefficient;
lua_rawseti(L, -2, i + 1); lua_rawseti(L, -2, i + 1);
} }
@@ -858,7 +853,7 @@ static void push_expr_string(lua_State* L, KiwiExpression* expr) {
for (int i = 0; i < expr->term_count; i++) { for (int i = 0; i < expr->term_count; i++) {
KiwiTerm* t = &expr->terms[i]; KiwiTerm* t = &expr->terms[i];
lua_pushfstring(L, "%f %s", t->coefficient, kiwi_var_name(t->var)); lua_pushfstring(L, "%f %s", t->coefficient, t->var->name().c_str());
luaL_addvalue(&buf); luaL_addvalue(&buf);
luaL_addstring(&buf, " + "); luaL_addstring(&buf, " + ");
} }
@@ -874,9 +869,9 @@ static int lkiwi_expr_m_tostring(lua_State* L) {
} }
static int lkiwi_expr_m_gc(lua_State* L) { static int lkiwi_expr_m_gc(lua_State* L) {
KiwiExpression* expr = get_expr(L, 1); const auto* expr = get_expr(L, 1);
for (int i = 0; i < expr->term_count; i++) { for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) {
kiwi_var_del(expr->terms[i].var); t->var->~Variable();
} }
return 0; return 0;
} }
@@ -925,45 +920,42 @@ static int lkiwi_expr_new(lua_State* L) {
for (int i = 0; i < nterms; i++) { for (int i = 0; i < nterms; i++) {
const KiwiTerm* term = get_term(L, i + 2); const KiwiTerm* term = get_term(L, i + 2);
expr->terms[i].var = kiwi_var_clone(term->var); expr->terms[i].var = kiwi_var_retain(term->var);
expr->terms[i].coefficient = term->coefficient; expr->terms[i].coefficient = term->coefficient;
} }
return 1; return 1;
} }
static int lkiwi_constraint_strength(lua_State* L) { static int lkiwi_constraint_strength(lua_State* L) {
KiwiConstraintRef c = get_constraint(L, 1); lua_pushnumber(L, get_constraint(L, 1)->strength());
lua_pushnumber(L, kiwi_constraint_strength(c));
return 1; return 1;
} }
static int lkiwi_constraint_op(lua_State* L) { static int lkiwi_constraint_op(lua_State* L) {
KiwiConstraintRef c = get_constraint(L, 1); auto op = get_constraint(L, 1)->op();
enum KiwiRelOp op = kiwi_constraint_op(c);
const char* opstr = "??"; const char* opstr = "??";
switch (op) { switch (op) {
case KIWI_OP_EQ: case kiwi::OP_LE:
opstr = "EQ";
break;
case KIWI_OP_LE:
opstr = "LE"; opstr = "LE";
break; break;
case KIWI_OP_GE: case kiwi::OP_GE:
opstr = "GE"; opstr = "GE";
break; break;
case kiwi::OP_EQ:
opstr = "EQ";
break;
} }
lua_pushlstring(L, opstr, 2); lua_pushlstring(L, opstr, 2);
return 1; return 1;
} }
static int lkiwi_constraint_violated(lua_State* L) { static int lkiwi_constraint_violated(lua_State* L) {
KiwiConstraintRef c = get_constraint(L, 1); lua_pushboolean(L, get_constraint(L, 1)->violated());
lua_pushboolean(L, kiwi_constraint_violated(c));
return 1; return 1;
} }
static int lkiwi_constraint_expression(lua_State* L) { static int lkiwi_constraint_expression(lua_State* L) {
KiwiConstraintRef c = get_constraint(L, 1); auto* c = get_constraint(L, 1);
const static int SZ = 7; const static int SZ = 7;
KiwiExpression* expr = expr_new(L, SZ); KiwiExpression* expr = expr_new(L, SZ);
int n = kiwi_constraint_expression(c, expr, SZ); int n = kiwi_constraint_expression(c, expr, SZ);
@@ -977,41 +969,46 @@ static int lkiwi_constraint_expression(lua_State* L) {
} }
static int lkiwi_constraint_m_tostring(lua_State* L) { static int lkiwi_constraint_m_tostring(lua_State* L) {
KiwiConstraintRef c = get_constraint(L, 1); const auto& c = *get_constraint(L, 1);
const static int SZ = 16; const constexpr static int SZ = 16;
KiwiExpression* expr =
(KiwiExpression*)stalloc(sizeof(KiwiExpression) + sizeof(KiwiTerm) * (SZ - 1)); alignas(KiwiExpression
int n = kiwi_constraint_expression(c, expr, SZ); ) unsigned char expr_buf[sizeof(KiwiExpression) + sizeof(KiwiTerm) * (SZ - 1)];
auto* expr = reinterpret_cast<KiwiExpression*>(&expr_buf);
int n = kiwi_constraint_expression(&c, expr, SZ);
if (l_unlikely(n > SZ)) { if (l_unlikely(n > SZ)) {
expr = (KiwiExpression*)malloc(sizeof(KiwiExpression) + sizeof(KiwiTerm) * (n - 1)); expr =
static_cast<KiwiExpression*>(malloc(sizeof(KiwiExpression) + sizeof(KiwiTerm) * (n - 1))
);
if (!expr) { if (!expr) {
luaL_error(L, "out of memory"); luaL_error(L, "out of memory");
} }
kiwi_constraint_expression(c, expr, n); kiwi_constraint_expression(&c, expr, n);
} }
luaL_Buffer buf; luaL_Buffer buf;
luaL_buffinit(L, &buf); luaL_buffinit(L, &buf);
const char* oppart = " ?? 0 | "; const char* oppart = " ?? 0 | ";
switch (kiwi_constraint_op(c)) { switch (c.op()) {
case KIWI_OP_EQ: case kiwi::OP_LE:
oppart = " == 0 | ";
break;
case KIWI_OP_LE:
oppart = " <= 0 | "; oppart = " <= 0 | ";
break; break;
case KIWI_OP_GE: case kiwi::OP_GE:
oppart = " >= 0 | "; oppart = " >= 0 | ";
break; break;
case kiwi::OP_EQ:
oppart = " == 0 | ";
break;
} }
push_expr_string(L, expr); push_expr_string(L, expr);
luaL_addvalue(&buf); luaL_addvalue(&buf);
luaL_addlstring(&buf, oppart, 8); luaL_addlstring(&buf, oppart, 8);
const char* strength_name = 0; const char* strength_name = 0;
const double strength = kiwi_constraint_strength(c); const double strength = c.strength();
if (strength == STRENGTH_REQUIRED) { if (strength == STRENGTH_REQUIRED) {
strength_name = "required"; strength_name = "required";
@@ -1035,8 +1032,7 @@ static int lkiwi_constraint_m_tostring(lua_State* L) {
} }
static int lkiwi_constraint_m_gc(lua_State* L) { static int lkiwi_constraint_m_gc(lua_State* L) {
KiwiConstraintRef c = get_constraint(L, 1); get_constraint(L, 1)->~Constraint();
kiwi_constraint_del(c);
return 0; return 0;
} }
@@ -1082,14 +1078,15 @@ static int lkiwi_constraint_new(lua_State* L) {
static int push_pair_constraint( static int push_pair_constraint(
lua_State* L, lua_State* L,
KiwiVarRef left, Variable* left,
double coeff, double coeff,
KiwiVarRef right, Variable* right,
double constant, double constant,
enum KiwiRelOp op, enum KiwiRelOp op,
double strength double strength
) { ) {
KiwiExpression* expr = (KiwiExpression*)stalloc(sizeof(KiwiExpression) + sizeof(KiwiTerm)); alignas(KiwiExpression) unsigned char expr_buf[sizeof(KiwiExpression) + sizeof(KiwiTerm)];
auto* expr = reinterpret_cast<KiwiExpression*>(&expr_buf);
expr->constant = constant; expr->constant = constant;
expr->term_count = 2; expr->term_count = 2;
expr->terms[0].var = left; expr->terms[0].var = left;
@@ -1233,8 +1230,7 @@ static int lkiwi_solver_handle_err(lua_State* L, const KiwiErr* err, const KiwiS
lua_settop(L, 2); lua_settop(L, 2);
if (err) { if (err) {
error_new(L, err, 1, 2); error_new(L, err, 1, 2);
unsigned error_mask; unsigned error_mask = solver->error_mask;
memcpy(&error_mask, solver, sizeof(error_mask));
if (error_mask & (1 << err->kind)) { if (error_mask & (1 << err->kind)) {
return 2; return 2;
} else { } else {
@@ -1245,22 +1241,22 @@ static int lkiwi_solver_handle_err(lua_State* L, const KiwiErr* err, const KiwiS
} }
static int lkiwi_solver_add_constraint(lua_State* L) { static int lkiwi_solver_add_constraint(lua_State* L) {
KiwiSolver* solver = get_solver(L, 1); auto* solver = get_solver(L, 1);
KiwiConstraintRef c = get_constraint(L, 2); const auto& c = *get_constraint(L, 2);
const KiwiErr* err = kiwi_solver_add_constraint(solver, c); const KiwiErr* err = kiwi_solver_add_constraint(solver, c);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, solver);
} }
static int lkiwi_solver_remove_constraint(lua_State* L) { static int lkiwi_solver_remove_constraint(lua_State* L) {
KiwiSolver* solver = get_solver(L, 1); auto* solver = get_solver(L, 1);
KiwiConstraintRef c = get_constraint(L, 2); const auto& c = *get_constraint(L, 2);
const KiwiErr* err = kiwi_solver_remove_constraint(solver, c); const KiwiErr* err = kiwi_solver_remove_constraint(solver, c);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, solver);
} }
static int lkiwi_solver_add_edit_var(lua_State* L) { static int lkiwi_solver_add_edit_var(lua_State* L) {
KiwiSolver* solver = get_solver(L, 1); KiwiSolver* solver = get_solver(L, 1);
KiwiVarRef var = get_var(L, 2); const auto& var = *get_var(L, 2);
double strength = luaL_checknumber(L, 3); double strength = luaL_checknumber(L, 3);
const KiwiErr* err = kiwi_solver_add_edit_var(solver, var, strength); const KiwiErr* err = kiwi_solver_add_edit_var(solver, var, strength);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, solver);
@@ -1268,46 +1264,51 @@ static int lkiwi_solver_add_edit_var(lua_State* L) {
static int lkiwi_solver_remove_edit_var(lua_State* L) { static int lkiwi_solver_remove_edit_var(lua_State* L) {
KiwiSolver* solver = get_solver(L, 1); KiwiSolver* solver = get_solver(L, 1);
KiwiVarRef var = get_var(L, 2); const auto& var = *get_var(L, 2);
const KiwiErr* err = kiwi_solver_remove_edit_var(solver, var); const KiwiErr* err = kiwi_solver_remove_edit_var(solver, var);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, solver);
} }
static int lkiwi_solver_suggest_value(lua_State* L) { static int lkiwi_solver_suggest_value(lua_State* L) {
KiwiSolver* solver = get_solver(L, 1); KiwiSolver* solver = get_solver(L, 1);
KiwiVarRef var = get_var(L, 2); const auto& var = *get_var(L, 2);
double value = luaL_checknumber(L, 3); double value = luaL_checknumber(L, 3);
const KiwiErr* err = kiwi_solver_suggest_value(solver, var, value); const KiwiErr* err = kiwi_solver_suggest_value(solver, var, value);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, solver);
} }
static int lkiwi_solver_update_vars(lua_State* L) { static int lkiwi_solver_update_vars(lua_State* L) {
kiwi_solver_update_vars(get_solver(L, 1)); get_solver(L, 1)->solver.updateVariables();
return 0; return 0;
} }
static int lkiwi_solver_reset(lua_State* L) { static int lkiwi_solver_reset(lua_State* L) {
kiwi_solver_reset(get_solver(L, 1)); get_solver(L, 1)->solver.reset();
return 0; return 0;
} }
static int lkiwi_solver_has_constraint(lua_State* L) { static int lkiwi_solver_has_constraint(lua_State* L) {
lua_pushboolean(L, kiwi_solver_has_constraint(get_solver(L, 1), get_constraint(L, 2))); auto* s = get_solver(L, 1);
const auto* c = get_constraint(L, 2);
lua_pushboolean(L, s->solver.hasConstraint(*c));
return 1; return 1;
} }
static int lkiwi_solver_has_edit_var(lua_State* L) { static int lkiwi_solver_has_edit_var(lua_State* L) {
lua_pushboolean(L, kiwi_solver_has_edit_var(get_solver(L, 1), get_var(L, 2))); auto* s = get_solver(L, 1);
const auto* var = get_var(L, 2);
lua_pushboolean(L, s->solver.hasEditVariable(*var));
return 1; return 1;
} }
static int lkiwi_solver_dump(lua_State* L) { static int lkiwi_solver_dump(lua_State* L) {
kiwi_solver_dump(get_solver(L, 1)); get_solver(L, 1)->solver.dump();
return 0; return 0;
} }
static int lkiwi_solver_dumps(lua_State* L) { static int lkiwi_solver_dumps(lua_State* L) {
lua_pushstring(L, kiwi_solver_dumps(get_solver(L, 1))); const auto s = get_solver(L, 1)->solver.dumps();
lua_pushlstring(L, s.data(), s.length());
return 1; return 1;
} }
@@ -1328,8 +1329,7 @@ static int lkiwi_add_remove_tab(lua_State* L, add_remove_fn_t fn, void* d) {
const KiwiErr* err = fn(L, solver, d); const KiwiErr* err = fn(L, solver, d);
if (err) { if (err) {
error_new(L, err, 1, narg + 1 /* item_absi */); error_new(L, err, 1, narg + 1 /* item_absi */);
unsigned error_mask; unsigned error_mask = solver->error_mask;
memcpy(&error_mask, solver, sizeof(error_mask));
if (error_mask & (1 << err->kind)) { if (error_mask & (1 << err->kind)) {
lua_replace(L, 3); lua_replace(L, 3);
lua_settop(L, 3); lua_settop(L, 3);
@@ -1345,8 +1345,7 @@ static int lkiwi_add_remove_tab(lua_State* L, add_remove_fn_t fn, void* d) {
} }
static const KiwiErr* add_constraint_fn(lua_State* L, KiwiSolver* s, void* d) { static const KiwiErr* add_constraint_fn(lua_State* L, KiwiSolver* s, void* d) {
KiwiConstraintRef c = get_constraint(L, -1); return kiwi_solver_add_constraint(s, *get_constraint(L, -1));
return kiwi_solver_add_constraint(s, c);
} }
static int lkiwi_solver_add_constraints(lua_State* L) { static int lkiwi_solver_add_constraints(lua_State* L) {
@@ -1354,8 +1353,7 @@ static int lkiwi_solver_add_constraints(lua_State* L) {
} }
static const KiwiErr* remove_constraint_fn(lua_State* L, KiwiSolver* s, void* d) { static const KiwiErr* remove_constraint_fn(lua_State* L, KiwiSolver* s, void* d) {
KiwiConstraintRef c = get_constraint(L, -1); return kiwi_solver_remove_constraint(s, *get_constraint(L, -1));
return kiwi_solver_remove_constraint(s, c);
} }
static int lkiwi_solver_remove_constraints(lua_State* L) { static int lkiwi_solver_remove_constraints(lua_State* L) {
@@ -1363,8 +1361,7 @@ static int lkiwi_solver_remove_constraints(lua_State* L) {
} }
static const KiwiErr* add_edit_var_fn(lua_State* L, KiwiSolver* s, void* d) { static const KiwiErr* add_edit_var_fn(lua_State* L, KiwiSolver* s, void* d) {
KiwiVarRef v = get_var(L, -1); return kiwi_solver_add_edit_var(s, *get_var(L, -1), *(double*)d);
return kiwi_solver_add_edit_var(s, v, *(double*)d);
} }
static int lkiwi_solver_add_edit_vars(lua_State* L) { static int lkiwi_solver_add_edit_vars(lua_State* L) {
@@ -1373,8 +1370,7 @@ static int lkiwi_solver_add_edit_vars(lua_State* L) {
} }
static const KiwiErr* remove_edit_var_fn(lua_State* L, KiwiSolver* s, void* d) { static const KiwiErr* remove_edit_var_fn(lua_State* L, KiwiSolver* s, void* d) {
KiwiVarRef v = get_var(L, -1); return kiwi_solver_remove_edit_var(s, *get_var(L, -1));
return kiwi_solver_remove_edit_var(s, v);
} }
static int lkiwi_solver_remove_edit_vars(lua_State* L) { static int lkiwi_solver_remove_edit_vars(lua_State* L) {
@@ -1398,15 +1394,15 @@ static int lkiwi_solver_suggest_values(lua_State* L) {
if (lua_geti(L, 2, i) == LUA_TNIL) { if (lua_geti(L, 2, i) == LUA_TNIL) {
break; break;
} }
KiwiVarRef var = get_var(L, -1); auto* var = get_var(L, -1);
lua_geti(L, 3, i); lua_geti(L, 3, i);
double value = luaL_checknumber(L, -1); double value = luaL_checknumber(L, -1);
const KiwiErr* err = kiwi_solver_suggest_value(solver, var, value); const KiwiErr* err = kiwi_solver_suggest_value(solver, *var, value);
if (err) { if (err) {
error_new(L, err, 1, narg + 1 /* item_absi */); error_new(L, err, 1, narg + 1 /* item_absi */);
unsigned error_mask; unsigned error_mask = solver->error_mask;
memcpy(&error_mask, solver, sizeof(error_mask));
if (error_mask & (1 << err->kind)) { if (error_mask & (1 << err->kind)) {
lua_replace(L, 4); lua_replace(L, 4);
lua_settop(L, 4); lua_settop(L, 4);
@@ -1434,7 +1430,7 @@ static int lkiwi_solver_set_error_mask(lua_State* L) {
error_mask = luaL_checkinteger(L, 2); error_mask = luaL_checkinteger(L, 2);
} }
memcpy(solver, &error_mask, sizeof(error_mask)); solver->error_mask = error_mask;
return 0; return 0;
} }
@@ -1444,7 +1440,7 @@ static int lkiwi_solver_tostring(lua_State* L) {
} }
static int lkiwi_solver_del(lua_State* L) { static int lkiwi_solver_del(lua_State* L) {
kiwi_solver_del(get_solver(L, 1)); get_solver(L, 1)->~KiwiSolver();
return 0; return 0;
} }
@@ -1479,8 +1475,8 @@ static int lkiwi_solver_new_meth(lua_State* L) {
error_mask = luaL_optinteger(L, 1, 0); error_mask = luaL_optinteger(L, 1, 0);
} }
KiwiSolver** sp = (KiwiSolver**)lua_newuserdata(L, sizeof(KiwiSolver*)); KiwiSolver* sp = static_cast<KiwiSolver*>(lua_newuserdata(L, sizeof(KiwiSolver)));
*sp = kiwi_solver_new(error_mask); new (sp) KiwiSolver {error_mask};
push_type(L, SOLVER); push_type(L, SOLVER);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);