This commit is contained in:
2024-02-22 17:34:08 -06:00
parent 3811d82212
commit dea448e46b
4 changed files with 294 additions and 454 deletions

View File

@@ -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 kiwibridge.cpp luakiwi-int.h luacompat.h luakiwi.o: ckiwi.h 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

@@ -1,331 +0,0 @@
#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

@@ -1,6 +1,10 @@
#ifndef LUAKIWI_INT_H_ #ifndef LUAKIWI_INT_H_
#define LUAKIWI_INT_H_ #define LUAKIWI_INT_H_
#include <kiwi/kiwi.h>
#include <cstring>
#include "luacompat.h" #include "luacompat.h"
#define ARR_COUNT(x) ((int)(sizeof(x) / sizeof((x)[0]))) #define ARR_COUNT(x) ((int)(sizeof(x) / sizeof((x)[0])))
@@ -13,38 +17,6 @@
#define l_unlikely(x) (x) #define l_unlikely(x) (x)
#endif #endif
#ifndef LKIWI_NO_STALLOC
#if defined(_MSC_VER)
#include <malloc.h>
static inline void* stalloc(size_t sz) {
void* p = _malloca(sz);
if (!p) {
luaL_error(L, "out of memory");
}
return p;
}
#define stfree(ptr) _freea(ptr)
#else
#include <alloca.h>
#define stalloc alloca
#define stfree(ptr)
#endif
#else
#include <stdlib.h>
static inline void* stalloc(size_t sz) {
void* p = malloc(sz);
if (l_unlikely(!p)) {
luaL_error(L, "out of memory");
}
return p;
}
#define stfree(ptr) free(ptr)
#endif
// Lua 5.1 compatibility for missing lua_arith. // Lua 5.1 compatibility for missing lua_arith.
static void compat_arith_unm(lua_State* L) { static void compat_arith_unm(lua_State* L) {
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 #if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
@@ -81,4 +53,207 @@ static void setfuncs(lua_State* L, const luaL_Reg* l, int nup) {
#define newlib(L, l) (lua_newtable((L)), setfuncs((L), (l), 0)) #define newlib(L, l) (lua_newtable((L)), setfuncs((L), (l), 0))
namespace {
using namespace kiwi;
enum KiwiErrKind {
KiwiErrNone,
KiwiErrUnsatisfiableConstraint = 1,
KiwiErrUnknownConstraint,
KiwiErrDuplicateConstraint,
KiwiErrUnknownEditVariable,
KiwiErrDuplicateEditVariable,
KiwiErrBadRequiredStrength,
KiwiErrInternalSolverError,
KiwiErrAlloc,
KiwiErrNullObject,
KiwiErrUnknown,
};
struct KiwiTerm {
Variable* var;
double coefficient;
};
struct KiwiExpression {
double constant;
int term_count;
Constraint* owner;
KiwiTerm terms[1];
};
// This structure was initially designed for LuaJIT FFI. It works OK for C++
// though it certainly isn't idiomatic.
struct KiwiErr {
enum KiwiErrKind kind;
const char* message;
bool must_free;
};
struct KiwiSolver {
unsigned error_mask;
Solver solver;
};
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."};
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& s, F&& f) {
return wrap_err([&]() { f(s); });
}
template<typename P, typename R, typename F>
inline const KiwiErr* wrap_err(P& s, R& ref, F&& f) {
return wrap_err([&]() { f(s, ref); });
}
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,
RelationalOperator 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) {
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
);
}
inline const KiwiErr* kiwi_solver_add_constraint(Solver& s, const Constraint& constraint) {
return wrap_err(s, constraint, [](auto& solver, const auto& c) { solver.addConstraint(c); });
}
inline const KiwiErr* kiwi_solver_remove_constraint(Solver& s, const Constraint& constraint) {
return wrap_err(s, constraint, [](auto& solver, const auto& c) {
solver.removeConstraint(c);
});
}
inline const KiwiErr* kiwi_solver_add_edit_var(Solver& s, const Variable& var, double strength) {
return wrap_err(s, var, [strength](auto& solver, const auto& v) {
solver.addEditVariable(v, strength);
});
}
inline const KiwiErr* kiwi_solver_remove_edit_var(Solver& s, const Variable& var) {
return wrap_err(s, var, [](auto& solver, const auto& v) { solver.removeEditVariable(v); });
}
inline const KiwiErr* kiwi_solver_suggest_value(Solver& s, const Variable& var, double value) {
return wrap_err(s, var, [value](auto& solver, const auto& v) {
solver.suggestValue(v, value);
});
}
} // namespace
// Local Variables:
// mode: c++
// End:
#endif // LUAKIWI_INT_H_ #endif // LUAKIWI_INT_H_

View File

@@ -2,7 +2,6 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "kiwibridge.cpp"
#include "luacompat.h" #include "luacompat.h"
#include "luakiwi-int.h" #include "luakiwi-int.h"
@@ -34,21 +33,21 @@ static const double STRENGTH_STRONG = 1000000.0;
static const double STRENGTH_MEDIUM = 1000.0; static const double STRENGTH_MEDIUM = 1000.0;
static const double STRENGTH_WEAK = 1.0; static const double STRENGTH_WEAK = 1.0;
static enum KiwiRelOp get_op_opt(lua_State* L, int idx) { static kiwi::RelationalOperator get_op_opt(lua_State* L, int idx) {
size_t opn; size_t opn;
const char* op = luaL_optlstring(L, idx, "EQ", &opn); const char* op = luaL_optlstring(L, idx, "EQ", &opn);
if (opn == 2) { if (opn == 2) {
if (op[0] == 'E' && op[1] == 'Q') { if (op[0] == 'E' && op[1] == 'Q') {
return KIWI_OP_EQ; return kiwi::OP_EQ;
} else if (op[0] == 'L' && op[1] == 'E') { } else if (op[0] == 'L' && op[1] == 'E') {
return KIWI_OP_LE; return kiwi::OP_LE;
} else if (op[0] == 'G' && op[1] == 'E') { } else if (op[0] == 'G' && op[1] == 'E') {
return KIWI_OP_GE; return kiwi::OP_GE;
} }
} }
luaL_argerror(L, idx, "invalid operator"); luaL_argerror(L, idx, "invalid operator");
return KIWI_OP_EQ; return kiwi::OP_EQ;
} }
static inline void push_type(lua_State* L, int type_id) { static inline void push_type(lua_State* L, int type_id) {
@@ -136,7 +135,7 @@ static inline void* check_arg(lua_State* L, int idx, int type_id) {
return udp; return udp;
} }
static inline void* try_type(lua_State* L, int idx, enum TypeId type_id) { static inline void* try_type(lua_State* L, int idx, TypeId type_id) {
void* p = lua_touserdata(L, idx); void* p = lua_touserdata(L, idx);
if (!p || !lua_getmetatable(L, idx)) if (!p || !lua_getmetatable(L, idx))
return 0; return 0;
@@ -158,7 +157,7 @@ static inline KiwiExpression* try_expr(lua_State* L, int idx) {
// method to test types for expression functions // method to test types for expression functions
// stack disposition: dirty // stack disposition: dirty
static inline void* try_arg(lua_State* L, int idx, enum TypeId* type_id, double* num) { static inline void* try_arg(lua_State* L, int idx, TypeId* type_id, double* num) {
void* p = lua_touserdata(L, idx); void* p = lua_touserdata(L, idx);
if (!p || !lua_getmetatable(L, idx)) { if (!p || !lua_getmetatable(L, idx)) {
int isnum; int isnum;
@@ -221,7 +220,6 @@ template<typename... Args>
static inline Variable* var_new(lua_State* L, Args&&... args) { static inline Variable* var_new(lua_State* L, Args&&... args) {
auto* p = static_cast<Variable*>(lua_newuserdata(L, sizeof(Variable))); auto* p = static_cast<Variable*>(lua_newuserdata(L, sizeof(Variable)));
new (p) Variable(std::forward<Args>(args)...); new (p) Variable(std::forward<Args>(args)...);
push_type(L, VAR); push_type(L, VAR);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
@@ -238,17 +236,18 @@ static inline Variable* var_new(lua_State* L, Args&&... args) {
} }
static inline KiwiTerm* term_new(lua_State* L) { static inline KiwiTerm* term_new(lua_State* L) {
KiwiTerm* ret = (KiwiTerm*)lua_newuserdata(L, sizeof(KiwiTerm)); auto* ret = static_cast<KiwiTerm*>(lua_newuserdata(L, sizeof(KiwiTerm)));
push_type(L, TERM); push_type(L, TERM);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return ret; return ret;
} }
static inline KiwiExpression* expr_new(lua_State* L, int nterms) { static inline KiwiExpression* expr_new(lua_State* L, int nterms) {
KiwiExpression* ret = (KiwiExpression*)lua_newuserdata( auto* ret = static_cast<KiwiExpression*>(lua_newuserdata(
L, L,
sizeof(KiwiExpression) + sizeof(KiwiTerm) * (nterms > 1 ? nterms - 1 : 0) sizeof(KiwiExpression) + sizeof(KiwiTerm) * (nterms > 1 ? nterms - 1 : 0)
); ));
ret->owner = nullptr;
push_type(L, EXPR); push_type(L, EXPR);
lua_setmetatable(L, -2); lua_setmetatable(L, -2);
return ret; return ret;
@@ -258,7 +257,7 @@ 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, kiwi::RelationalOperator op,
double strength double strength
) { ) {
auto* ref = static_cast<Constraint*>(lua_newuserdata(L, sizeof(Constraint))); auto* ref = static_cast<Constraint*>(lua_newuserdata(L, sizeof(Constraint)));
@@ -284,7 +283,7 @@ static KiwiExpression* toexpr(lua_State* L, int idx, KiwiExpression* temp) {
push_type(L, EXPR); push_type(L, EXPR);
if (lua_rawequal(L, -1, -2)) { if (lua_rawequal(L, -1, -2)) {
return (KiwiExpression*)ud; return static_cast<KiwiExpression*>(ud);
} }
temp->constant = 0; temp->constant = 0;
@@ -297,13 +296,13 @@ static KiwiExpression* toexpr(lua_State* L, int idx, KiwiExpression* temp) {
} }
push_type(L, TERM); push_type(L, TERM);
if (lua_rawequal(L, -1, -4)) { if (lua_rawequal(L, -1, -4)) {
temp->terms[0] = *(KiwiTerm*)ud; temp->terms[0] = *static_cast<KiwiTerm*>(ud);
return temp; return temp;
} }
return 0; return 0;
} }
static int relop(lua_State* L, enum KiwiRelOp op, const char opdisp[2]) { static int relop(lua_State* L, kiwi::RelationalOperator op, const char opdisp[2]) {
KiwiExpression tmpl, tmpr; KiwiExpression tmpl, tmpr;
double strength = luaL_optnumber(L, 3, STRENGTH_REQUIRED); double strength = luaL_optnumber(L, 3, STRENGTH_REQUIRED);
const KiwiExpression* lhs = toexpr(L, 1, &tmpl); const KiwiExpression* lhs = toexpr(L, 1, &tmpl);
@@ -318,15 +317,15 @@ static int relop(lua_State* L, enum KiwiRelOp op, const char opdisp[2]) {
} }
static int lkiwi_eq(lua_State* L) { static int lkiwi_eq(lua_State* L) {
return relop(L, KIWI_OP_EQ, "=="); return relop(L, kiwi::OP_EQ, "==");
} }
static int lkiwi_le(lua_State* L) { static int lkiwi_le(lua_State* L) {
return relop(L, KIWI_OP_LE, "<="); return relop(L, kiwi::OP_LE, "<=");
} }
static int lkiwi_ge(lua_State* L) { static int lkiwi_ge(lua_State* L) {
return relop(L, KIWI_OP_GE, ">="); return relop(L, kiwi::OP_GE, ">=");
} }
static inline int push_expr_one(lua_State* L, double constant, const KiwiTerm* term) { static inline int push_expr_one(lua_State* L, double constant, const KiwiTerm* term) {
@@ -377,7 +376,7 @@ static int push_add_expr_term(lua_State* L, const KiwiExpression* expr, const Ki
} }
static int lkiwi_var_m_add(lua_State* L) { static int lkiwi_var_m_add(lua_State* L) {
enum TypeId type_id_b; TypeId type_id_b;
double num; double num;
void* arg_b = try_arg(L, 2, &type_id_b, &num); void* arg_b = try_arg(L, 2, &type_id_b, &num);
@@ -593,7 +592,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; TypeId type_id_b;
double num; double num;
void* arg_b = try_arg(L, 2, &type_id_b, &num); void* arg_b = try_arg(L, 2, &type_id_b, &num);
@@ -778,7 +777,7 @@ static int lkiwi_expr_m_unm(lua_State* L) {
} }
static int lkiwi_expr_m_add(lua_State* L) { static int lkiwi_expr_m_add(lua_State* L) {
enum TypeId type_id_b; TypeId type_id_b;
double num; double num;
void* arg_b = try_arg(L, 2, &type_id_b, &num); void* arg_b = try_arg(L, 2, &type_id_b, &num);
@@ -847,12 +846,13 @@ static int lkiwi_expr_copy(lua_State* L) {
return push_expr_constant(L, expr, expr->constant); return push_expr_constant(L, expr, expr->constant);
} }
static void push_expr_string(lua_State* L, KiwiExpression* expr) { static int lkiwi_expr_m_tostring(lua_State* L) {
const auto* expr = get_expr(L, 1);
luaL_Buffer buf; luaL_Buffer buf;
luaL_buffinit(L, &buf); luaL_buffinit(L, &buf);
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];
lua_pushfstring(L, "%f %s", t->coefficient, t->var->name().c_str()); lua_pushfstring(L, "%f %s", t->coefficient, t->var->name().c_str());
luaL_addvalue(&buf); luaL_addvalue(&buf);
luaL_addstring(&buf, " + "); luaL_addstring(&buf, " + ");
@@ -861,17 +861,18 @@ static void push_expr_string(lua_State* L, KiwiExpression* expr) {
lua_pushfstring(L, "%f", expr->constant); lua_pushfstring(L, "%f", expr->constant);
luaL_addvalue(&buf); luaL_addvalue(&buf);
luaL_pushresult(&buf); luaL_pushresult(&buf);
}
static int lkiwi_expr_m_tostring(lua_State* L) {
push_expr_string(L, get_expr(L, 1));
return 1; return 1;
} }
static int lkiwi_expr_m_gc(lua_State* L) { static int lkiwi_expr_m_gc(lua_State* L) {
const auto* expr = get_expr(L, 1); const auto* expr = get_expr(L, 1);
for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) { if (expr->owner) {
t->var->~Variable(); expr->owner->~Constraint();
} else {
for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) {
t->var->~Variable();
}
} }
return 0; return 0;
} }
@@ -956,14 +957,18 @@ static int lkiwi_constraint_violated(lua_State* L) {
static int lkiwi_constraint_expression(lua_State* L) { static int lkiwi_constraint_expression(lua_State* L) {
auto* c = get_constraint(L, 1); auto* c = get_constraint(L, 1);
const static int SZ = 7; const auto& expr = c->expression();
KiwiExpression* expr = expr_new(L, SZ); const auto& terms = expr.terms();
int n = kiwi_constraint_expression(c, expr, SZ); const int term_count = terms.size();
if (l_unlikely(n > SZ)) { auto* ne = expr_new(L, term_count);
lua_pop(L, 1); ne->owner = kiwi_constraint_retain(c);
expr = expr_new(L, n); ne->constant = expr.constant();
kiwi_constraint_expression(c, expr, n); ne->term_count = term_count;
for (int i = 0; i < term_count; ++i) {
ne->terms[i].var = const_cast<Variable*>(&terms[i].variable());
ne->terms[i].coefficient = terms[i].coefficient();
} }
return 1; return 1;
} }
@@ -971,24 +976,6 @@ 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) {
const auto& c = *get_constraint(L, 1); const auto& c = *get_constraint(L, 1);
const constexpr static int SZ = 16;
alignas(KiwiExpression
) 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)) {
expr =
static_cast<KiwiExpression*>(malloc(sizeof(KiwiExpression) + sizeof(KiwiTerm) * (n - 1))
);
if (!expr) {
luaL_error(L, "out of memory");
}
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 | ";
@@ -1004,8 +991,17 @@ static int lkiwi_constraint_m_tostring(lua_State* L) {
break; break;
} }
push_expr_string(L, expr); const auto& expr = c.expression();
for (const auto& t : expr.terms()) {
lua_pushfstring(L, "%f %s", t.coefficient(), t.variable().name().c_str());
luaL_addvalue(&buf);
luaL_addstring(&buf, " + ");
}
lua_pushfstring(L, "%f", expr.constant());
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 = c.strength(); const double strength = c.strength();
@@ -1067,9 +1063,9 @@ static const struct luaL_Reg kiwi_constraint_m[] = {
{0, 0}}; {0, 0}};
static int lkiwi_constraint_new(lua_State* L) { static int lkiwi_constraint_new(lua_State* L) {
KiwiExpression* lhs = get_expr_opt(L, 1); const auto* lhs = get_expr_opt(L, 1);
KiwiExpression* rhs = get_expr_opt(L, 2); const auto* rhs = get_expr_opt(L, 2);
enum KiwiRelOp op = get_op_opt(L, 3); const auto op = get_op_opt(L, 3);
double strength = luaL_optnumber(L, 4, STRENGTH_REQUIRED); double strength = luaL_optnumber(L, 4, STRENGTH_REQUIRED);
constraint_new(L, lhs, rhs, op, strength); constraint_new(L, lhs, rhs, op, strength);
@@ -1082,7 +1078,7 @@ static int push_pair_constraint(
double coeff, double coeff,
Variable* right, Variable* right,
double constant, double constant,
enum KiwiRelOp op, kiwi::RelationalOperator op,
double strength double strength
) { ) {
alignas(KiwiExpression) unsigned char expr_buf[sizeof(KiwiExpression) + sizeof(KiwiTerm)]; alignas(KiwiExpression) unsigned char expr_buf[sizeof(KiwiExpression) + sizeof(KiwiTerm)];
@@ -1241,40 +1237,40 @@ 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) {
auto* solver = get_solver(L, 1); auto* self = get_solver(L, 1);
const auto& 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(self->solver, c);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, self);
} }
static int lkiwi_solver_remove_constraint(lua_State* L) { static int lkiwi_solver_remove_constraint(lua_State* L) {
auto* solver = get_solver(L, 1); auto* self = get_solver(L, 1);
const auto& 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(self->solver, c);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, self);
} }
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* self = get_solver(L, 1);
const auto& 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(self->solver, var, strength);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, self);
} }
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* self = get_solver(L, 1);
const auto& 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(self->solver, var);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, self);
} }
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* self = get_solver(L, 1);
const auto& 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(self->solver, var, value);
return lkiwi_solver_handle_err(L, err, solver); return lkiwi_solver_handle_err(L, err, self);
} }
static int lkiwi_solver_update_vars(lua_State* L) { static int lkiwi_solver_update_vars(lua_State* L) {
@@ -1289,15 +1285,15 @@ static int lkiwi_solver_reset(lua_State* L) {
static int lkiwi_solver_has_constraint(lua_State* L) { static int lkiwi_solver_has_constraint(lua_State* L) {
auto* s = get_solver(L, 1); auto* s = get_solver(L, 1);
const auto* c = get_constraint(L, 2); const auto& c = *get_constraint(L, 2);
lua_pushboolean(L, s->solver.hasConstraint(*c)); 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) {
auto* s = get_solver(L, 1); auto* s = get_solver(L, 1);
const auto* var = get_var(L, 2); const auto& var = *get_var(L, 2);
lua_pushboolean(L, s->solver.hasEditVariable(*var)); lua_pushboolean(L, s->solver.hasEditVariable(var));
return 1; return 1;
} }
@@ -1345,7 +1341,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) {
return kiwi_solver_add_constraint(s, *get_constraint(L, -1)); return kiwi_solver_add_constraint(s->solver, *get_constraint(L, -1));
} }
static int lkiwi_solver_add_constraints(lua_State* L) { static int lkiwi_solver_add_constraints(lua_State* L) {
@@ -1353,7 +1349,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) {
return kiwi_solver_remove_constraint(s, *get_constraint(L, -1)); return kiwi_solver_remove_constraint(s->solver, *get_constraint(L, -1));
} }
static int lkiwi_solver_remove_constraints(lua_State* L) { static int lkiwi_solver_remove_constraints(lua_State* L) {
@@ -1361,7 +1357,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) {
return kiwi_solver_add_edit_var(s, *get_var(L, -1), *(double*)d); return kiwi_solver_add_edit_var(s->solver, *get_var(L, -1), *(double*)d);
} }
static int lkiwi_solver_add_edit_vars(lua_State* L) { static int lkiwi_solver_add_edit_vars(lua_State* L) {
@@ -1370,7 +1366,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) {
return kiwi_solver_remove_edit_var(s, *get_var(L, -1)); return kiwi_solver_remove_edit_var(s->solver, *get_var(L, -1));
} }
static int lkiwi_solver_remove_edit_vars(lua_State* L) { static int lkiwi_solver_remove_edit_vars(lua_State* L) {
@@ -1378,7 +1374,7 @@ static int lkiwi_solver_remove_edit_vars(lua_State* L) {
} }
static int lkiwi_solver_suggest_values(lua_State* L) { static int lkiwi_solver_suggest_values(lua_State* L) {
KiwiSolver* solver = get_solver(L, 1); auto* self = get_solver(L, 1);
int narg = lua_gettop(L); int narg = lua_gettop(L);
// block this particularly obnoxious case which is always a bug // block this particularly obnoxious case which is always a bug
@@ -1399,10 +1395,10 @@ static int lkiwi_solver_suggest_values(lua_State* L) {
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(self->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 = solver->error_mask; unsigned error_mask = self->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,12 +1430,12 @@ static int lkiwi_solver_set_error_mask(lua_State* L) {
return 0; return 0;
} }
static int lkiwi_solver_tostring(lua_State* L) { static int lkiwi_solver_m_tostring(lua_State* L) {
lua_pushfstring(L, "kiwi.Solver(%p)", get_solver(L, 1)); lua_pushfstring(L, "kiwi.Solver(%p)", get_solver(L, 1));
return 1; return 1;
} }
static int lkiwi_solver_del(lua_State* L) { static int lkiwi_solver_m_gc(lua_State* L) {
get_solver(L, 1)->~KiwiSolver(); get_solver(L, 1)->~KiwiSolver();
return 0; return 0;
} }
@@ -1462,8 +1458,8 @@ static const struct luaL_Reg kiwi_solver_m[] = {
{"dump", lkiwi_solver_dump}, {"dump", lkiwi_solver_dump},
{"dumps", lkiwi_solver_dumps}, {"dumps", lkiwi_solver_dumps},
{"set_error_mask", lkiwi_solver_set_error_mask}, {"set_error_mask", lkiwi_solver_set_error_mask},
{"__tostring", lkiwi_solver_tostring}, {"__tostring", lkiwi_solver_m_tostring},
{"__gc", lkiwi_solver_del}, {"__gc", lkiwi_solver_m_gc},
{0, 0}}; {0, 0}};
static int lkiwi_solver_new_meth(lua_State* L) { static int lkiwi_solver_new_meth(lua_State* L) {
@@ -1475,7 +1471,7 @@ 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 = static_cast<KiwiSolver*>(lua_newuserdata(L, sizeof(KiwiSolver))); auto* sp = static_cast<KiwiSolver*>(lua_newuserdata(L, sizeof(KiwiSolver)));
new (sp) KiwiSolver {error_mask}; new (sp) KiwiSolver {error_mask};
push_type(L, SOLVER); push_type(L, SOLVER);