From dea448e46b8a24b3dc68b7f5de4d5df2224088d3 Mon Sep 17 00:00:00 2001 From: "John K. Luebs" Date: Thu, 22 Feb 2024 17:34:08 -0600 Subject: [PATCH] better --- Makefile | 2 +- luakiwi/kiwibridge.cpp | 331 ----------------------------------------- luakiwi/luakiwi-int.h | 239 +++++++++++++++++++++++++---- luakiwi/luakiwi.cpp | 176 +++++++++++----------- 4 files changed, 294 insertions(+), 454 deletions(-) delete mode 100644 luakiwi/kiwibridge.cpp diff --git a/Makefile b/Makefile index 5e6329d..ba5446d 100644 --- a/Makefile +++ b/Makefile @@ -45,7 +45,7 @@ ckiwi.$(LIB_EXT): $(OBJS) $(CXX) $(CXXFLAGS) $(CFLAGS) $(CFLAGS_EXTRA) -I$(SRCDIR)/kiwi $(LIBFLAG) -o $@ $^ 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 $(CC) -I$(LUA_INCDIR) $(CFLAGS) $(CFLAGS_EXTRA) -c -o $@ $< diff --git a/luakiwi/kiwibridge.cpp b/luakiwi/kiwibridge.cpp deleted file mode 100644 index cbf0d61..0000000 --- a/luakiwi/kiwibridge.cpp +++ /dev/null @@ -1,331 +0,0 @@ -#include - -#include -#include - -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 -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)...); - return cref; -} - -template -inline decltype(auto) make_var_cref(Args&&... args) { - return make_cref(std::forward(args)...); -} - -template -inline decltype(auto) make_constraint_cref(Args&&... args) { - return make_cref(std::forward(args)...); -} - -template -class SharedRef { - private: - R& cref_; - - public: - explicit SharedRef(R& cref) : cref_(cref) {} - - static_assert( - sizeof(R) >= sizeof(T), // NOLINT(bugprone-sizeof-expression) - "SharedRef CS too small for T" - ); - - R clone() const { - return make_cref(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; -using VariableRef = SharedRef; -using ConstVariableRef = const SharedRef; - -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(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(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 -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 -inline const KiwiErr* wrap_err(P ptr, F&& f) { - if (!ptr) { - return &kKiwiErrNullObjectArg0; - } - return wrap_err([&]() { f(ptr); }); -} - -template -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 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(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(&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 diff --git a/luakiwi/luakiwi-int.h b/luakiwi/luakiwi-int.h index 024cdb8..8abb140 100644 --- a/luakiwi/luakiwi-int.h +++ b/luakiwi/luakiwi-int.h @@ -1,6 +1,10 @@ #ifndef LUAKIWI_INT_H_ #define LUAKIWI_INT_H_ +#include + +#include + #include "luacompat.h" #define ARR_COUNT(x) ((int)(sizeof(x) / sizeof((x)[0]))) @@ -13,38 +17,6 @@ #define l_unlikely(x) (x) #endif -#ifndef LKIWI_NO_STALLOC - #if defined(_MSC_VER) - #include - -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 - #define stalloc alloca - #define stfree(ptr) - #endif -#else - #include - -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. static void compat_arith_unm(lua_State* L) { #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)) +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(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(err->message), ex.what(), msg_n); + return err; +} + +const constexpr KiwiErr kKiwiErrUnhandledCxxException { + KiwiErrUnknown, + "An unhandled C++ exception occurred."}; + +template +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 +inline const KiwiErr* wrap_err(P& s, F&& f) { + return wrap_err([&]() { f(s); }); +} + +template +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 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(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_ diff --git a/luakiwi/luakiwi.cpp b/luakiwi/luakiwi.cpp index d1c5d13..f86db7d 100644 --- a/luakiwi/luakiwi.cpp +++ b/luakiwi/luakiwi.cpp @@ -2,7 +2,6 @@ #include #include -#include "kiwibridge.cpp" #include "luacompat.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_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; const char* op = luaL_optlstring(L, idx, "EQ", &opn); if (opn == 2) { if (op[0] == 'E' && op[1] == 'Q') { - return KIWI_OP_EQ; + return kiwi::OP_EQ; } else if (op[0] == 'L' && op[1] == 'E') { - return KIWI_OP_LE; + return kiwi::OP_LE; } else if (op[0] == 'G' && op[1] == 'E') { - return KIWI_OP_GE; + return kiwi::OP_GE; } } 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) { @@ -136,7 +135,7 @@ static inline void* check_arg(lua_State* L, int idx, int type_id) { 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); if (!p || !lua_getmetatable(L, idx)) return 0; @@ -158,7 +157,7 @@ static inline KiwiExpression* try_expr(lua_State* L, int idx) { // method to test types for expression functions // 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); if (!p || !lua_getmetatable(L, idx)) { int isnum; @@ -221,7 +220,6 @@ template static inline Variable* var_new(lua_State* L, Args&&... args) { auto* p = static_cast(lua_newuserdata(L, sizeof(Variable))); new (p) Variable(std::forward(args)...); - push_type(L, VAR); 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) { - KiwiTerm* ret = (KiwiTerm*)lua_newuserdata(L, sizeof(KiwiTerm)); + auto* ret = static_cast(lua_newuserdata(L, sizeof(KiwiTerm))); push_type(L, TERM); lua_setmetatable(L, -2); return ret; } static inline KiwiExpression* expr_new(lua_State* L, int nterms) { - KiwiExpression* ret = (KiwiExpression*)lua_newuserdata( + auto* ret = static_cast(lua_newuserdata( L, sizeof(KiwiExpression) + sizeof(KiwiTerm) * (nterms > 1 ? nterms - 1 : 0) - ); + )); + ret->owner = nullptr; push_type(L, EXPR); lua_setmetatable(L, -2); return ret; @@ -258,7 +257,7 @@ static inline Constraint* constraint_new( lua_State* L, const KiwiExpression* lhs, const KiwiExpression* rhs, - enum KiwiRelOp op, + kiwi::RelationalOperator op, double strength ) { auto* ref = static_cast(lua_newuserdata(L, sizeof(Constraint))); @@ -284,7 +283,7 @@ static KiwiExpression* toexpr(lua_State* L, int idx, KiwiExpression* temp) { push_type(L, EXPR); if (lua_rawequal(L, -1, -2)) { - return (KiwiExpression*)ud; + return static_cast(ud); } temp->constant = 0; @@ -297,13 +296,13 @@ static KiwiExpression* toexpr(lua_State* L, int idx, KiwiExpression* temp) { } push_type(L, TERM); if (lua_rawequal(L, -1, -4)) { - temp->terms[0] = *(KiwiTerm*)ud; + temp->terms[0] = *static_cast(ud); return temp; } 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; double strength = luaL_optnumber(L, 3, STRENGTH_REQUIRED); 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) { - return relop(L, KIWI_OP_EQ, "=="); + return relop(L, kiwi::OP_EQ, "=="); } 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) { - 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) { @@ -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) { - enum TypeId type_id_b; + TypeId type_id_b; double 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) { - enum TypeId type_id_b; + TypeId type_id_b; double 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) { - enum TypeId type_id_b; + TypeId type_id_b; double 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); } -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_buffinit(L, &buf); 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()); luaL_addvalue(&buf); luaL_addstring(&buf, " + "); @@ -861,17 +861,18 @@ static void push_expr_string(lua_State* L, KiwiExpression* expr) { lua_pushfstring(L, "%f", expr->constant); luaL_addvalue(&buf); luaL_pushresult(&buf); -} -static int lkiwi_expr_m_tostring(lua_State* L) { - push_expr_string(L, get_expr(L, 1)); return 1; } static int lkiwi_expr_m_gc(lua_State* L) { const auto* expr = get_expr(L, 1); - for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) { - t->var->~Variable(); + if (expr->owner) { + expr->owner->~Constraint(); + } else { + for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) { + t->var->~Variable(); + } } return 0; } @@ -956,14 +957,18 @@ static int lkiwi_constraint_violated(lua_State* L) { static int lkiwi_constraint_expression(lua_State* L) { auto* c = get_constraint(L, 1); - const static int SZ = 7; - KiwiExpression* expr = expr_new(L, SZ); - int n = kiwi_constraint_expression(c, expr, SZ); + const auto& expr = c->expression(); + const auto& terms = expr.terms(); + const int term_count = terms.size(); - if (l_unlikely(n > SZ)) { - lua_pop(L, 1); - expr = expr_new(L, n); - kiwi_constraint_expression(c, expr, n); + auto* ne = expr_new(L, term_count); + ne->owner = kiwi_constraint_retain(c); + ne->constant = expr.constant(); + ne->term_count = term_count; + + for (int i = 0; i < term_count; ++i) { + ne->terms[i].var = const_cast(&terms[i].variable()); + ne->terms[i].coefficient = terms[i].coefficient(); } return 1; } @@ -971,24 +976,6 @@ static int lkiwi_constraint_expression(lua_State* L) { static int lkiwi_constraint_m_tostring(lua_State* L) { 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(&expr_buf); - - int n = kiwi_constraint_expression(&c, expr, SZ); - - if (l_unlikely(n > SZ)) { - expr = - static_cast(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_buffinit(L, &buf); const char* oppart = " ?? 0 | "; @@ -1004,8 +991,17 @@ static int lkiwi_constraint_m_tostring(lua_State* L) { 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_addlstring(&buf, oppart, 8); const char* strength_name = 0; const double strength = c.strength(); @@ -1067,9 +1063,9 @@ static const struct luaL_Reg kiwi_constraint_m[] = { {0, 0}}; static int lkiwi_constraint_new(lua_State* L) { - KiwiExpression* lhs = get_expr_opt(L, 1); - KiwiExpression* rhs = get_expr_opt(L, 2); - enum KiwiRelOp op = get_op_opt(L, 3); + const auto* lhs = get_expr_opt(L, 1); + const auto* rhs = get_expr_opt(L, 2); + const auto op = get_op_opt(L, 3); double strength = luaL_optnumber(L, 4, STRENGTH_REQUIRED); constraint_new(L, lhs, rhs, op, strength); @@ -1082,7 +1078,7 @@ static int push_pair_constraint( double coeff, Variable* right, double constant, - enum KiwiRelOp op, + kiwi::RelationalOperator op, double strength ) { 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) { - auto* solver = get_solver(L, 1); + auto* self = get_solver(L, 1); const auto& c = *get_constraint(L, 2); - const KiwiErr* err = kiwi_solver_add_constraint(solver, c); - return lkiwi_solver_handle_err(L, err, solver); + const KiwiErr* err = kiwi_solver_add_constraint(self->solver, c); + return lkiwi_solver_handle_err(L, err, self); } 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 KiwiErr* err = kiwi_solver_remove_constraint(solver, c); - return lkiwi_solver_handle_err(L, err, solver); + const KiwiErr* err = kiwi_solver_remove_constraint(self->solver, c); + return lkiwi_solver_handle_err(L, err, self); } 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); double strength = luaL_checknumber(L, 3); - const KiwiErr* err = kiwi_solver_add_edit_var(solver, var, strength); - return lkiwi_solver_handle_err(L, err, solver); + const KiwiErr* err = kiwi_solver_add_edit_var(self->solver, var, strength); + return lkiwi_solver_handle_err(L, err, self); } 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 KiwiErr* err = kiwi_solver_remove_edit_var(solver, var); - return lkiwi_solver_handle_err(L, err, solver); + const KiwiErr* err = kiwi_solver_remove_edit_var(self->solver, var); + return lkiwi_solver_handle_err(L, err, self); } 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); double value = luaL_checknumber(L, 3); - const KiwiErr* err = kiwi_solver_suggest_value(solver, var, value); - return lkiwi_solver_handle_err(L, err, solver); + const KiwiErr* err = kiwi_solver_suggest_value(self->solver, var, value); + return lkiwi_solver_handle_err(L, err, self); } 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) { auto* s = get_solver(L, 1); - const auto* c = get_constraint(L, 2); - lua_pushboolean(L, s->solver.hasConstraint(*c)); + const auto& c = *get_constraint(L, 2); + lua_pushboolean(L, s->solver.hasConstraint(c)); return 1; } static int lkiwi_solver_has_edit_var(lua_State* L) { auto* s = get_solver(L, 1); - const auto* var = get_var(L, 2); - lua_pushboolean(L, s->solver.hasEditVariable(*var)); + const auto& var = *get_var(L, 2); + lua_pushboolean(L, s->solver.hasEditVariable(var)); 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) { - 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) { @@ -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) { - 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) { @@ -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) { - 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) { @@ -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) { - 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) { @@ -1378,7 +1374,7 @@ static int lkiwi_solver_remove_edit_vars(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); // 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); 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) { 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)) { lua_replace(L, 4); lua_settop(L, 4); @@ -1434,12 +1430,12 @@ static int lkiwi_solver_set_error_mask(lua_State* L) { 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)); return 1; } -static int lkiwi_solver_del(lua_State* L) { +static int lkiwi_solver_m_gc(lua_State* L) { get_solver(L, 1)->~KiwiSolver(); return 0; } @@ -1462,8 +1458,8 @@ static const struct luaL_Reg kiwi_solver_m[] = { {"dump", lkiwi_solver_dump}, {"dumps", lkiwi_solver_dumps}, {"set_error_mask", lkiwi_solver_set_error_mask}, - {"__tostring", lkiwi_solver_tostring}, - {"__gc", lkiwi_solver_del}, + {"__tostring", lkiwi_solver_m_tostring}, + {"__gc", lkiwi_solver_m_gc}, {0, 0}}; 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); } - KiwiSolver* sp = static_cast(lua_newuserdata(L, sizeof(KiwiSolver))); + auto* sp = static_cast(lua_newuserdata(L, sizeof(KiwiSolver))); new (sp) KiwiSolver {error_mask}; push_type(L, SOLVER);