diff --git a/ckiwi/.clang-format b/.clang-format similarity index 99% rename from ckiwi/.clang-format rename to .clang-format index f9132f8..76a9a41 100644 --- a/ckiwi/.clang-format +++ b/.clang-format @@ -65,7 +65,7 @@ PointerAlignment: Left ReferenceAlignment: Left # New in v13. int &name ==> int& name ReflowComments: false SeparateDefinitionBlocks: Always # New in v14. -SortIncludes: true +SortIncludes: false SortUsingDeclarations: true SpaceAfterCStyleCast: false SpaceAfterLogicalNot: false diff --git a/.gitignore b/.gitignore index 067b483..98b74ee 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ /lua /lua_modules /.luarocks +*.pch +*.gch *.so *.o .cache/ diff --git a/.luarc.json b/.luarc.json index 86b45b7..73dc269 100644 --- a/.luarc.json +++ b/.luarc.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json", - "runtime.version": "Lua 5.4", + "runtime.version": "LuaJIT", "runtime.path": [ "./?/init.lua", "./?.lua", diff --git a/Makefile b/Makefile index c5be3ea..5b2cf88 100644 --- a/Makefile +++ b/Makefile @@ -1,56 +1,85 @@ -SRCDIR := . CC := $(CROSS)gcc -CFLAGS := -fPIC -O3 -CXXFLAGS := -I$(SRCDIR)/kiwi -fno-rtti -#F_LTO := -flto=auto -CXXFLAGS_EXTRA := -std=c++14 -Wall $(F_LTO) -fstrict-flex-arrays=3 -CFLAGS_EXTRA := -pedantic -std=c99 -Wall $(F_LTO) +CP := cp +RM := rm LIBFLAG := -shared LIB_EXT := so LUA_INCDIR := /usr/include -ifeq ($(findstring gcc,$(CC)),gcc) - CXX := $(subst gcc,g++,$(CC)) - CXXFLAGS += -std=c++14 - ifneq ($(SANITIZE),) - CFLAGS += -fsanitize=undefined -fsanitize=address - endif +SRCDIR := . + +OPTFLAG := -O2 +CCFLAGS += $(OPTFLAG) -fPIC -Wall -fstrict-flex-arrays -fvisibility=hidden -Wformat=2 -Wconversion -Wimplicit-fallthrough + +SANITIZE_FLAGS := -fsanitize=undefined -fsanitize=address +LTO_FLAGS := -flto=auto + +ifdef SANITIZE + CCFLAGS += $(SANITIZE_FLAGS) +endif +ifdef LTO + CCFLAGS += $(LTO_FLAGS) +endif + +override CPPFLAGS += -I$(SRCDIR) -I$(SRCDIR)/kiwi -I$(LUA_INCDIR) +override CXXFLAGS += -std=c++14 -fno-rtti $(CCFLAGS) +override CFLAGS += -std=c99 $(CCFLAGS) + +ifneq ($(filter %gcc,$(CC)),) + CXX := $(patsubst %gcc,%g++,$(CC)) + PCH := ljkiwi.hpp.gch else -ifeq ($(CC),clang) - CXX := clang++ - CXXFLAGS += -std=c++14 - ifneq ($(SANITIZE),) - CFLAGS += -fsanitize=undefined -fsanitize=address - endif -else - CXX := $(CC) + ifneq ($(filter %clang,$(CC)),) + CXX := $(patsubst %clang,%clang++,$(CC)) + override CXXFLAGS += -pedantic -Wno-c99-extensions + PCH := ljkiwi.hpp.pch endif endif -OBJS := ckiwi.o luakiwi.o +ifdef LUA +LUA_VERSION ?= $(lastword $(shell $(LUA) -e "print(_VERSION)")) +endif -VPATH = $(SRCDIR)/ckiwi $(SRCDIR)/luakiwi +ifndef LUA_VERSION +LJKIWI_CKIWI := 1 +else + ifneq ($(LUA_VERSION),5.1) + LJKIWI_CKIWI := + endif +endif -all: ckiwi.$(LIB_EXT) +OBJS := luakiwi.o +ifdef LJKIWI_CKIWI + OBJS += ckiwi.o +endif + +vpath %.cpp $(SRCDIR)/ckiwi $(SRCDIR)/luakiwi +vpath %.h $(SRCDIR)/ckiwi $(SRCDIR)/luakiwi + +all: ljkiwi.$(LIB_EXT) install: - cp -f ckiwi.$(LIB_EXT) $(INST_LIBDIR)/ckiwi.$(LIB_EXT) - cp -f kiwi.lua $(INST_LUADIR)/kiwi.lua + $(CP) -f ljkiwi.$(LIB_EXT) $(INST_LIBDIR)/ljkiwi.$(LIB_EXT) + $(CP) -f kiwi.lua $(INST_LUADIR)/kiwi.lua clean: - rm -f ckiwi.$(LIB_EXT) $(OBJS) + $(RM) -f ljkiwi.$(LIB_EXT) $(OBJS) $(PCH) +ckiwi.o: $(PCH) ckiwi.cpp ckiwi.h +luakiwi.o: $(PCH) luakiwi-int.h luacompat.h -ckiwi.$(LIB_EXT): $(OBJS) - $(CXX) $(CXXFLAGS) $(CFLAGS) $(CFLAGS_EXTRA) -I$(SRCDIR)/kiwi $(LIBFLAG) -o $@ $^ +ljkiwi.$(LIB_EXT): $(OBJS) + $(CXX) $(CCFLAGS) $(LIBFLAG) -o $@ $(OBJS) -ckiwi.o: ckiwi.h -luakiwi.o: ckiwi.h luakiwi-int.h luacompat.h +%.hpp.gch: %.hpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -x c++-header -o $@ $< + +%.hpp.pch: %.hpp + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -x c++-header -o $@ $< %.o: %.c - $(CC) -I$(LUA_INCDIR) $(CFLAGS) $(CFLAGS_EXTRA) -c -o $@ $< + $(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $< %.o: %.cpp - $(CXX) -I$(LUA_INCDIR) $(CXXFLAGS) $(CFLAGS) $(CXXFLAGS_EXTRA) -c -o $@ $< + $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $< .PHONY: all install clean diff --git a/ckiwi/ckiwi.cpp b/ckiwi/ckiwi.cpp index f20398f..f4fdc7e 100644 --- a/ckiwi/ckiwi.cpp +++ b/ckiwi/ckiwi.cpp @@ -1,3 +1,4 @@ +#include "ljkiwi.hpp" #include "ckiwi.h" #include @@ -5,99 +6,17 @@ #include #include -using namespace kiwi; +#if defined(__GNUC__) && !defined(LJKIWI_NO_BUILTIN) + #define lk_likely(x) (__builtin_expect(((x) != 0), 1)) + #define lk_unlikely(x) (__builtin_expect(((x) != 0), 0)) +#else + #define lk_likely(x) (x) + #define lk_unlikely(x) (x) +#endif namespace { -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; +using namespace kiwi; const KiwiErr* new_error(const KiwiErr* base, const std::exception& ex) { if (!std::strcmp(ex.what(), base->message)) @@ -117,18 +36,15 @@ const KiwiErr* new_error(const KiwiErr* base, const std::exception& ex) { static const constexpr KiwiErr kKiwiErrUnhandledCxxException { KiwiErrUnknown, - "An unhandled C++ exception occurred." -}; + "An unhandled C++ exception occurred."}; static const constexpr KiwiErr kKiwiErrNullObjectArg0 { KiwiErrNullObject, - "null object passed as argument #0 (self)" -}; + "null object passed as argument #0 (self)"}; static const constexpr KiwiErr kKiwiErrNullObjectArg1 { KiwiErrNullObject, - "null object passed as argument #1" -}; + "null object passed as argument #1"}; template inline const KiwiErr* wrap_err(F&& f) { @@ -137,49 +53,42 @@ inline const KiwiErr* wrap_err(F&& f) { } catch (const UnsatisfiableConstraint& ex) { static const constexpr KiwiErr err { KiwiErrUnsatisfiableConstraint, - "The constraint cannot be satisfied." - }; + "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." - }; + "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." - }; + "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." - }; + "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." - }; + "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." - }; + "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." - }; + "An internal solver error occurred."}; return new_error(&base, ex); } catch (std::bad_alloc&) { static const constexpr KiwiErr err {KiwiErrAlloc, "A memory allocation failed."}; @@ -193,82 +102,96 @@ inline const KiwiErr* wrap_err(F&& f) { } template -inline const KiwiErr* wrap_err(P ptr, F&& f) { - if (!ptr) { +inline const KiwiErr* wrap_err(P self, F&& f) { + if (lk_unlikely(!self)) { return &kKiwiErrNullObjectArg0; } - return wrap_err([&]() { f(ptr); }); + return wrap_err([&]() { f(self->solver); }); } template -inline const KiwiErr* wrap_err(P ptr, R ref, F&& f) { - if (!ptr) { +inline const KiwiErr* wrap_err(P self, R item, F&& f) { + if (lk_unlikely(!self)) { return &kKiwiErrNullObjectArg0; - } else if (!ref) { + } else if (lk_unlikely(!item)) { return &kKiwiErrNullObjectArg1; } - return wrap_err([&]() { f(ptr, ref); }); + return wrap_err([&]() { f(self->solver, *item); }); } } // namespace extern "C" { -KiwiVarRef kiwi_var_new(const char* name) { - return make_var_cref(name ? name : ""); +KiwiTypeInfo kiwi_ti_KiwiVar = {sizeof(KiwiVar), alignof(KiwiVar)}; +KiwiTypeInfo kiwi_ti_KiwiConstraint = {sizeof(KiwiConstraint), alignof(KiwiConstraint)}; + +void kiwi_var_construct(const char* name, void* mem) { + new (mem) KiwiVar {lk_likely(name) ? name : ""}; } -void kiwi_var_del(KiwiVarRef var) { - VariableRef(var).release(); +void kiwi_var_release(KiwiVar* var) { + if (lk_likely(var)) + var->~KiwiVar(); } -KiwiVarRef kiwi_var_clone(KiwiVarRef var) { - return VariableRef(var).clone(); -} - -const char* kiwi_var_name(KiwiVarRef var) { - const VariableRef self(var); - return self ? self->name().c_str() : "()"; -} - -void kiwi_var_set_name(KiwiVarRef var, const char* name) { - VariableRef self(var); - if (self) - self->setName(name); -} - -double kiwi_var_value(KiwiVarRef var) { - const VariableRef self(var); - return self ? self->value() : std::numeric_limits::quiet_NaN(); -} - -void kiwi_var_set_value(KiwiVarRef var, double value) { - VariableRef self(var); - if (self) - self->setValue(value); -} - -bool kiwi_var_eq(KiwiVarRef var, KiwiVarRef other) { - ConstVariableRef self(var); // const defect in upstream - const VariableRef other_ref(other); - - return self && other_ref && self->equals(other_ref); -} - -void kiwi_expression_del_vars(KiwiExpression* expr) { - if (!expr) - return; - - for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) { - VariableRef(t->var).release(); +void kiwi_var_retain(KiwiVar* var) { + if (lk_likely(var)) { + alignas(KiwiVar) unsigned char buf[sizeof(KiwiVar)]; + new (buf) KiwiVar(*var); } } -KiwiConstraintRef kiwi_constraint_new( +const char* kiwi_var_name(const KiwiVar* var) { + return lk_likely(var) ? var->name().c_str() : "()"; +} + +void kiwi_var_set_name(KiwiVar* var, const char* name) { + if (lk_likely(var)) + var->setName(name); +} + +double kiwi_var_value(const KiwiVar* var) { + return lk_likely(var) ? var->value() : std::numeric_limits::quiet_NaN(); +} + +void kiwi_var_set_value(KiwiVar* var, double value) { + if (lk_likely(var)) + var->setValue(value); +} + +bool kiwi_var_eq(const KiwiVar* var, const KiwiVar* other) { + return lk_likely(var && other) && var->equals(*other); +} + +void kiwi_expression_retain(KiwiExpression* expr) { + if (lk_unlikely(!expr)) + return; + alignas(KiwiVar) unsigned char buf[sizeof(KiwiVar)]; + for (auto* t = expr->terms_; t != expr->terms_ + expr->term_count; ++t) { + new (buf) KiwiVar(*t->var); + } +} + +void kiwi_expression_destroy(KiwiExpression* expr) { + if (lk_unlikely(!expr)) + return; + + if (expr->owner) { + expr->owner->~KiwiConstraint(); + } else { + for (auto* t = expr->terms_; t != expr->terms_ + expr->term_count; ++t) { + t->var->~KiwiVar(); + } + } +} + +void kiwi_constraint_construct( const KiwiExpression* lhs, const KiwiExpression* rhs, enum KiwiRelOp op, - double strength + double strength, + void* mem ) { if (strength < 0.0) { strength = kiwi::strength::required; @@ -278,69 +201,69 @@ KiwiConstraintRef kiwi_constraint_new( 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) { - ConstVariableRef var(t->var); - if (var) - terms.emplace_back(var.cref(), t->coefficient); + for (auto* t = lhs->terms_; t != lhs->terms_ + lhs->term_count; ++t) { + if (t->var) + terms.emplace_back(*t->var, t->coefficient); } } if (rhs) { - for (auto* t = rhs->terms; t != rhs->terms + rhs->term_count; ++t) { - ConstVariableRef var(t->var); - if (var) - terms.emplace_back(var.cref(), -t->coefficient); + for (auto* t = rhs->terms_; t != rhs->terms_ + rhs->term_count; ++t) { + if (t->var) + terms.emplace_back(*t->var, -t->coefficient); } } - return make_constraint_cref( + new (mem) Constraint( Expression(std::move(terms), (lhs ? lhs->constant : 0.0) - (rhs ? rhs->constant : 0.0)), static_cast(op), strength ); } -void kiwi_constraint_del(KiwiConstraintRef constraint) { - ConstraintRef(constraint).release(); +void kiwi_constraint_release(KiwiConstraint* c) { + if (lk_likely(c)) + c->~KiwiConstraint(); } -KiwiConstraintRef kiwi_constraint_clone(KiwiConstraintRef constraint) { - return ConstraintRef(constraint).clone(); -} - -double kiwi_constraint_strength(KiwiConstraintRef constraint) { - const ConstraintRef self(constraint); - return self ? self->strength() : std::numeric_limits::quiet_NaN(); -} - -enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint) { - const ConstraintRef self(constraint); - return self ? static_cast(self->op()) : KiwiRelOp::KIWI_OP_EQ; -} - -bool kiwi_constraint_violated(KiwiConstraintRef constraint) { - const ConstraintRef self(constraint); - return self ? self->violated() : 0; -} - -int kiwi_constraint_expression(KiwiConstraintRef constraint, KiwiExpression* out, int out_size) { - const ConstraintRef self(constraint); - if (!self) - return 0; - const auto& expr = self->expression(); - const auto& terms = expr.terms(); - const int n_terms = terms.size(); - if (!out || out_size < n_terms) - return n_terms; - - auto* p = out->terms; - for (const auto& t : terms) { - *p = KiwiTerm {make_var_cref(t.variable()), t.coefficient()}; - ++p; +void kiwi_constraint_retain(KiwiConstraint* c) { + if (lk_likely(c)) { + alignas(KiwiConstraint) unsigned char buf[sizeof(KiwiConstraint)]; + new (buf) KiwiConstraint(*c); } - out->term_count = p - out->terms; - out->constant = expr.constant(); +} - return n_terms; +double kiwi_constraint_strength(const KiwiConstraint* c) { + return lk_likely(c) ? c->strength() : std::numeric_limits::quiet_NaN(); +} + +enum KiwiRelOp kiwi_constraint_op(const KiwiConstraint* c) { + return lk_likely(c) ? static_cast(c->op()) : KiwiRelOp::KIWI_OP_EQ; +} + +bool kiwi_constraint_violated(const KiwiConstraint* c) { + return lk_likely(c) ? c->violated() : false; +} + +int kiwi_constraint_expression(KiwiConstraint* c, KiwiExpression* out, int out_size) { + if (lk_unlikely(!c)) + return 0; + + const auto& expr = c->expression(); + const auto& terms = expr.terms(); + const auto term_count = static_cast(terms.size()); + if (!out || out_size < term_count) + return term_count; + + for (int i = 0; i < term_count; ++i) { + out->terms_[i].var = const_cast(&terms[i].variable()); + out->terms_[i].coefficient = terms[i].coefficient(); + } + out->constant = expr.constant(); + out->term_count = term_count; + out->owner = c; + kiwi_constraint_retain(c); + + return term_count; } struct KiwiSolver { @@ -348,79 +271,80 @@ struct KiwiSolver { Solver solver; }; -KiwiSolver* kiwi_solver_new(unsigned error_mask) { - return new KiwiSolver {error_mask}; +KiwiTypeInfo kiwi_ti_KiwiSolver = {sizeof(KiwiSolver), alignof(KiwiSolver)}; + +void kiwi_solver_construct(unsigned error_mask, void* mem) { + new (mem) KiwiSolver {error_mask}; } -void kiwi_solver_del(KiwiSolver* s) { - if (s) - delete s; +void kiwi_solver_destroy(KiwiSolver* s) { + if (lk_likely(s)) + s->~KiwiSolver(); } -const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, KiwiConstraintRef constraint) { - return wrap_err(s, ConstraintRef(constraint), [](auto* s, const auto c) { - s->solver.addConstraint(c); - }); +unsigned kiwi_solver_get_error_mask(const KiwiSolver* s) { + return lk_likely(s) ? s->error_mask : 0; } -const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, KiwiConstraintRef constraint) { - return wrap_err(s, ConstraintRef(constraint), [](auto* s, const auto c) { - s->solver.removeConstraint(c); - }); +void kiwi_solver_set_error_mask(KiwiSolver* s, unsigned mask) { + if (lk_likely(s)) + s->error_mask = mask; } -bool kiwi_solver_has_constraint(const KiwiSolver* s, KiwiConstraintRef constraint) { - ConstraintRef c(constraint); - if (!s || !c) +const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, const KiwiConstraint* constraint) { + return wrap_err(s, constraint, [](auto& s, const auto& c) { s.addConstraint(c); }); +} + +const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, const KiwiConstraint* constraint) { + return wrap_err(s, constraint, [](auto& s, const auto& c) { s.removeConstraint(c); }); +} + +bool kiwi_solver_has_constraint(const KiwiSolver* s, const KiwiConstraint* constraint) { + if (lk_unlikely(!s || !constraint)) return 0; - return s->solver.hasConstraint(c); + return s->solver.hasConstraint(*constraint); } -const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, KiwiVarRef var, double strength) { - return wrap_err(s, VariableRef(var), [strength](auto* s, const auto v) { - s->solver.addEditVariable(v, strength); +const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, const KiwiVar* var, double strength) { + return wrap_err(s, var, [strength](auto& s, const auto& v) { + s.addEditVariable(v, strength); }); } -const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, KiwiVarRef var) { - return wrap_err(s, VariableRef(var), [](auto* s, const auto v) { - s->solver.removeEditVariable(v); - }); +const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, const KiwiVar* var) { + return wrap_err(s, var, [](auto& s, const auto& v) { s.removeEditVariable(v); }); } -bool kiwi_solver_has_edit_var(const KiwiSolver* s, KiwiVarRef var) { - VariableRef v(var); - if (!s || !v) +bool kiwi_solver_has_edit_var(const KiwiSolver* s, const KiwiVar* var) { + if (lk_unlikely(!s || !var)) return 0; - return s->solver.hasEditVariable(v); + return s->solver.hasEditVariable(*var); } -const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* s, KiwiVarRef var, double value) { - return wrap_err(s, VariableRef(var), [value](auto* s, const auto v) { - s->solver.suggestValue(v, value); - }); +const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* s, const KiwiVar* var, double value) { + return wrap_err(s, var, [value](auto& s, const auto& v) { s.suggestValue(v, value); }); } void kiwi_solver_update_vars(KiwiSolver* s) { - if (s) + if (lk_likely(s)) s->solver.updateVariables(); } void kiwi_solver_reset(KiwiSolver* s) { - if (s) + if (lk_likely(s)) s->solver.reset(); } void kiwi_solver_dump(const KiwiSolver* s) { - if (s) + if (lk_likely(s)) s->solver.dump(); } char* kiwi_solver_dumps(const KiwiSolver* s) { - if (!s) + if (lk_unlikely(!s)) return nullptr; - const auto str = s->solver.dumps(); // upstream library defect + const auto& str = s->solver.dumps(); const auto buf_size = str.size() + 1; auto* buf = static_cast(std::malloc(buf_size)); if (!buf) diff --git a/ckiwi/ckiwi.h b/ckiwi/ckiwi.h index add40a4..58a4bbe 100644 --- a/ckiwi/ckiwi.h +++ b/ckiwi/ckiwi.h @@ -1,13 +1,38 @@ -#ifndef KIWI_CKIWI_H_ -#define KIWI_CKIWI_H_ +#ifndef LJKIWI_CKIWI_H_ +#define LJKIWI_CKIWI_H_ -#ifdef __cplusplus -extern "C" { +#if !defined(_MSC_VER) || _MSC_VER >= 1900 + #undef LJKIWI_USE_FAM_1 #else - #include + #define LJKIWI_USE_FAM_1 #endif -#define KIWI_REF_ISNULL(ref) ((ref).impl_ == NULL) +#ifdef __cplusplus + +namespace kiwi { +class Variable; +class Constraint; +} // namespace kiwi + +extern "C" { + +typedef kiwi::Variable KiwiVar; +typedef kiwi::Constraint KiwiConstraint; +#else +typedef struct KiwiVar KiwiVar; +typedef struct KiwiConstraint KiwiConstraint; +#endif + +typedef struct KiwiTypeInfo { + unsigned size; + unsigned align; +} KiwiTypeInfo; + +#if __GNUC__ + #pragma GCC visibility push(default) +#endif + +extern KiwiTypeInfo kiwi_ti_KiwiVar, kiwi_ti_KiwiConstraint, kiwi_ti_KiwiSolver; // LuaJIT start enum KiwiErrKind { @@ -26,18 +51,24 @@ enum KiwiErrKind { enum KiwiRelOp { KIWI_OP_LE, KIWI_OP_GE, KIWI_OP_EQ }; -typedef struct KiwiVarRefType* KiwiVarRef; -typedef struct KiwiConstraintRefType* KiwiConstraintRef; - typedef struct KiwiTerm { - KiwiVarRef var; + KiwiVar* var; double coefficient; } KiwiTerm; typedef struct KiwiExpression { double constant; int term_count; - KiwiTerm terms[1]; // LuaJIT: struct KiwiTerm terms_[?]; + KiwiConstraint* owner; + +#if defined(LJKIWI_LUAJIT_DEF) + KiwiTerm terms_[?]; +#elif defined(LJKIWI_USE_FAM_1) + KiwiTerm terms_[1]; // LuaJIT: struct KiwiTerm terms_[?]; +#else + KiwiTerm terms_[]; +#endif + } KiwiExpression; typedef struct KiwiErr { @@ -46,56 +77,63 @@ typedef struct KiwiErr { bool must_free; } KiwiErr; -typedef struct KiwiSolver - KiwiSolver; // LuaJIT: typedef struct { unsigned error_mask; } KiwiSolver; -KiwiVarRef kiwi_var_new(const char* name); -void kiwi_var_del(KiwiVarRef var); -KiwiVarRef kiwi_var_clone(KiwiVarRef var); +struct KiwiSolver; -const char* kiwi_var_name(KiwiVarRef var); -void kiwi_var_set_name(KiwiVarRef var, const char* name); -double kiwi_var_value(KiwiVarRef var); -void kiwi_var_set_value(KiwiVarRef var, double value); -bool kiwi_var_eq(KiwiVarRef var, KiwiVarRef other); +void kiwi_var_construct(const char* name, void* mem); +void kiwi_var_release(KiwiVar* var); +void kiwi_var_retain(KiwiVar* var); -void kiwi_expression_del_vars(KiwiExpression* expr); +const char* kiwi_var_name(const KiwiVar* var); +void kiwi_var_set_name(KiwiVar* var, const char* name); +double kiwi_var_value(const KiwiVar* var); +void kiwi_var_set_value(KiwiVar* var, double value); +bool kiwi_var_eq(const KiwiVar* var, const KiwiVar* other); -KiwiConstraintRef kiwi_constraint_new( +void kiwi_expression_retain(KiwiExpression* expr); +void kiwi_expression_destroy(KiwiExpression* expr); + +void kiwi_constraint_construct( const KiwiExpression* lhs, const KiwiExpression* rhs, enum KiwiRelOp op, - double strength + double strength, + void* mem ); -void kiwi_constraint_del(KiwiConstraintRef constraint); -KiwiConstraintRef kiwi_constraint_clone(KiwiConstraintRef constraint); +void kiwi_constraint_release(KiwiConstraint* c); +void kiwi_constraint_retain(KiwiConstraint* c); -double kiwi_constraint_strength(KiwiConstraintRef constraint); -enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint); -bool kiwi_constraint_violated(KiwiConstraintRef constraint); -int kiwi_constraint_expression(KiwiConstraintRef constraint, KiwiExpression* out, int out_size); +double kiwi_constraint_strength(const KiwiConstraint* c); +enum KiwiRelOp kiwi_constraint_op(const KiwiConstraint* c); +bool kiwi_constraint_violated(const KiwiConstraint* c); +int kiwi_constraint_expression(KiwiConstraint* c, KiwiExpression* out, int out_size); -KiwiSolver* kiwi_solver_new(unsigned error_mask); -void kiwi_solver_del(KiwiSolver* s); +void kiwi_solver_construct(unsigned error_mask, void* mem); +void kiwi_solver_destroy(KiwiSolver* s); +unsigned kiwi_solver_get_error_mask(const KiwiSolver* s); +void kiwi_solver_set_error_mask(KiwiSolver* s, unsigned mask); -const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* sp, KiwiConstraintRef constraint); -const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* sp, KiwiConstraintRef constraint); -bool kiwi_solver_has_constraint(const KiwiSolver* sp, KiwiConstraintRef constraint); -const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* sp, KiwiVarRef var, double strength); -const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* sp, KiwiVarRef var); -bool kiwi_solver_has_edit_var(const KiwiSolver* sp, KiwiVarRef var); -const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* sp, KiwiVarRef var, double value); +const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, const KiwiConstraint* constraint); +const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, const KiwiConstraint* constraint); +bool kiwi_solver_has_constraint(const KiwiSolver* s, const KiwiConstraint* constraint); +const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, const KiwiVar* var, double strength); +const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, const KiwiVar* var); +bool kiwi_solver_has_edit_var(const KiwiSolver* s, const KiwiVar* var); +const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* s, const KiwiVar* var, double value); void kiwi_solver_update_vars(KiwiSolver* sp); void kiwi_solver_reset(KiwiSolver* sp); void kiwi_solver_dump(const KiwiSolver* sp); char* kiwi_solver_dumps(const KiwiSolver* sp); - // LuaJIT end +#if __GNUC__ + #pragma GCC visibility pop +#endif + #ifdef __cplusplus -} +} // extern "C" #endif // Local Variables: // mode: c++ // End: -#endif // KIWI_CKIWI_H_ +#endif // LJKIWI_CKIWI_H_ diff --git a/kiwi-scm-1.rockspec b/kiwi-scm-1.rockspec index 29c8550..749b688 100644 --- a/kiwi-scm-1.rockspec +++ b/kiwi-scm-1.rockspec @@ -21,6 +21,7 @@ dependencies = { build = { type = "make", build_variables = { + LUA = "$(LUA)", CFLAGS = "$(CFLAGS)", LUA_INCDIR = "$(LUA_INCDIR)", LIBFLAG = "$(LIBFLAG)", diff --git a/kiwi.lua b/kiwi.lua index 50e894e..08d280a 100644 --- a/kiwi.lua +++ b/kiwi.lua @@ -4,20 +4,48 @@ local ffi do local ffi_loader = package.preload["ffi"] if ffi_loader == nil then - return require("ckiwi") + return require("ljkiwi") end ffi = ffi_loader() --[[@as ffilib]] end local kiwi = {} -local ckiwi +local ljkiwi do - local cpath, err = package.searchpath("ckiwi", package.cpath) + local cpath, err = package.searchpath("ljkiwi", package.cpath) if cpath == nil then - error("kiwi dynamic library 'ckiwi' not found\n" .. err) + error("kiwi dynamic library 'ljkiwi' not found\n" .. err) end - ckiwi = ffi.load(cpath) + ljkiwi = ffi.load(cpath) +end +kiwi.ljkiwi = ljkiwi + +ffi.cdef([[ +void free(void *); + +typedef struct KiwiTypeInfo { +unsigned size; +unsigned align; +} KiwiTypeInfo; + +extern KiwiTypeInfo kiwi_ti_KiwiVar, kiwi_ti_KiwiConstraint, kiwi_ti_KiwiSolver; + +]]) + +for _, t in ipairs({ "KiwiVar", "KiwiConstraint", "KiwiSolver" }) do + local tinfo = ljkiwi[("kiwi_ti_%s"):format(t)] --[[@as any]] + ffi.cdef( + [[ +typedef struct $ { + unsigned char b_[$]; +} __attribute__((aligned($))) $; +]], + t, + tinfo.size, + tinfo.align, + t + ) end ffi.cdef([[ @@ -37,17 +65,15 @@ enum KiwiErrKind { enum KiwiRelOp { LE, GE, EQ }; -typedef struct KiwiVarRefType* KiwiVarRef; -typedef struct KiwiConstraintRefType* KiwiConstraintRef; - typedef struct KiwiTerm { - KiwiVarRef var; + KiwiVar* var; double coefficient; } KiwiTerm; typedef struct KiwiExpression { double constant; int term_count; + KiwiConstraint* owner; KiwiTerm terms_[?]; } KiwiExpression; @@ -57,49 +83,52 @@ typedef struct KiwiErr { bool must_free; } KiwiErr; -typedef struct KiwiSolver { unsigned error_mask_; } KiwiSolver; +struct KiwiSolver; -KiwiVarRef kiwi_var_new(const char* name); -void kiwi_var_del(KiwiVarRef var); -KiwiVarRef kiwi_var_clone(KiwiVarRef var); +void kiwi_var_construct(const char* name, void* mem); +void kiwi_var_release(KiwiVar* var); +void kiwi_var_retain(KiwiVar* var); -const char* kiwi_var_name(KiwiVarRef var); -void kiwi_var_set_name(KiwiVarRef var, const char* name); -double kiwi_var_value(KiwiVarRef var); -void kiwi_var_set_value(KiwiVarRef var, double value); -bool kiwi_var_eq(KiwiVarRef var, KiwiVarRef other); +const char* kiwi_var_name(const KiwiVar* var); +void kiwi_var_set_name(KiwiVar* var, const char* name); +double kiwi_var_value(const KiwiVar* var); +void kiwi_var_set_value(KiwiVar* var, double value); +bool kiwi_var_eq(const KiwiVar* var, const KiwiVar* other); -void kiwi_expression_del_vars(KiwiExpression* expr); +void kiwi_expression_retain(KiwiExpression* expr); +void kiwi_expression_destroy(KiwiExpression* expr); -KiwiConstraintRef kiwi_constraint_new( +void kiwi_constraint_construct( const KiwiExpression* lhs, const KiwiExpression* rhs, enum KiwiRelOp op, - double strength + double strength, + void* mem ); -void kiwi_constraint_del(KiwiConstraintRef constraint); +void kiwi_constraint_release(KiwiConstraint* c); +void kiwi_constraint_retain(KiwiConstraint* c); -double kiwi_constraint_strength(KiwiConstraintRef constraint); -enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint); -bool kiwi_constraint_violated(KiwiConstraintRef constraint); -int kiwi_constraint_expression(KiwiConstraintRef constraint, KiwiExpression* out, int out_size); +double kiwi_constraint_strength(const KiwiConstraint* c); +enum KiwiRelOp kiwi_constraint_op(const KiwiConstraint* c); +bool kiwi_constraint_violated(const KiwiConstraint* c); +int kiwi_constraint_expression(KiwiConstraint* c, KiwiExpression* out, int out_size); -KiwiSolver* kiwi_solver_new(unsigned error_mask); -void kiwi_solver_del(KiwiSolver* s); +void kiwi_solver_construct(unsigned error_mask, void* mem); +void kiwi_solver_destroy(KiwiSolver* s); +unsigned kiwi_solver_get_error_mask(const KiwiSolver* s); +void kiwi_solver_set_error_mask(KiwiSolver* s, unsigned mask); -const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* sp, KiwiConstraintRef constraint); -const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* sp, KiwiConstraintRef constraint); -bool kiwi_solver_has_constraint(const KiwiSolver* sp, KiwiConstraintRef constraint); -const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* sp, KiwiVarRef var, double strength); -const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* sp, KiwiVarRef var); -bool kiwi_solver_has_edit_var(const KiwiSolver* sp, KiwiVarRef var); -const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* sp, KiwiVarRef var, double value); +const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, const KiwiConstraint* constraint); +const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, const KiwiConstraint* constraint); +bool kiwi_solver_has_constraint(const KiwiSolver* s, const KiwiConstraint* constraint); +const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, const KiwiVar* var, double strength); +const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, const KiwiVar* var); +bool kiwi_solver_has_edit_var(const KiwiSolver* s, const KiwiVar* var); +const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* s, const KiwiVar* var, double value); void kiwi_solver_update_vars(KiwiSolver* sp); void kiwi_solver_reset(KiwiSolver* sp); void kiwi_solver_dump(const KiwiSolver* sp); char* kiwi_solver_dumps(const KiwiSolver* sp); - -void free(void *); ]]) local strformat = string.format @@ -159,7 +188,7 @@ do end end -local Var = ffi.typeof("struct KiwiVarRefType") --[[@as kiwi.Var]] +local Var = ffi.typeof("struct KiwiVar") --[[@as kiwi.Var]] kiwi.Var = Var function kiwi.is_var(o) @@ -173,14 +202,14 @@ function kiwi.is_term(o) return ffi_istype(Term, o) end -local Expression = ffi.typeof("struct KiwiExpression") --[[@as kiwi.Expression]] +local Expression = ffi.typeof("KiwiExpression") --[[@as kiwi.Expression]] kiwi.Expression = Expression function kiwi.is_expression(o) return ffi_istype(Expression, o) end -local Constraint = ffi.typeof("struct KiwiConstraintRefType") --[[@as kiwi.Constraint]] +local Constraint = ffi.typeof("KiwiConstraint") --[[@as kiwi.Constraint]] kiwi.Constraint = Constraint function kiwi.is_constraint(o) @@ -192,18 +221,19 @@ end ---@param coeff number? ---@nodiscard local function add_expr_term(expr, var, coeff) - local ret = ffi_gc(ffi_new(Expression, expr.term_count + 1), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + local ret = ffi_gc(ffi_new(Expression, expr.term_count + 1), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] for i = 0, expr.term_count - 1 do local st = expr.terms_[i] --[[@as kiwi.Term]] local dt = ret.terms_[i] --[[@as kiwi.Term]] - dt.var = ckiwi.kiwi_var_clone(st.var) + dt.var = st.var dt.coefficient = st.coefficient end local dt = ret.terms_[expr.term_count] - dt.var = ckiwi.kiwi_var_clone(var) + dt.var = var dt.coefficient = coeff or 1.0 ret.constant = expr.constant ret.term_count = expr.term_count + 1 + ljkiwi.kiwi_expression_retain(ret) return ret end @@ -212,12 +242,13 @@ end ---@param coeff number? ---@nodiscard local function new_expr_one(constant, var, coeff) - local ret = ffi_gc(ffi_new(Expression, 1), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + local ret = ffi_gc(ffi_new(Expression, 1), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] local dt = ret.terms_[0] - dt.var = ckiwi.kiwi_var_clone(var) + dt.var = var dt.coefficient = coeff or 1.0 ret.constant = constant ret.term_count = 1 + ljkiwi.kiwi_var_retain(var) return ret end @@ -228,15 +259,16 @@ end ---@param coeff2 number? ---@nodiscard local function new_expr_pair(constant, var1, var2, coeff1, coeff2) - local ret = ffi_gc(ffi_new(Expression, 2), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + local ret = ffi_gc(ffi_new(Expression, 2), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] local dt = ret.terms_[0] - dt.var = ckiwi.kiwi_var_clone(var1) + dt.var = var1 dt.coefficient = coeff1 or 1.0 dt = ret.terms_[1] - dt.var = ckiwi.kiwi_var_clone(var2) + dt.var = var2 dt.coefficient = coeff2 or 1.0 ret.constant = constant ret.term_count = 2 + ljkiwi.kiwi_expression_retain(ret) return ret end @@ -311,7 +343,9 @@ local function rel(lhs, rhs, op, strength) op_error(lhs, rhs, OP_NAMES[op]) end - return ffi_gc(ckiwi.kiwi_constraint_new(el, er, op, strength or REQUIRED), ckiwi.kiwi_constraint_del) --[[@as kiwi.Constraint]] + local c = ffi_new(Constraint) + ljkiwi.kiwi_constraint_construct(el, er, op, strength or REQUIRED, c) + return ffi_gc(c, ljkiwi.kiwi_constraint_release) --[[@as kiwi.Constraint]] end --- Define a constraint with expressions as `a <= b`. @@ -357,22 +391,22 @@ do --- Change the name of the variable. ---@type fun(self: kiwi.Var, name: string) - set_name = ckiwi.kiwi_var_set_name, + set_name = ljkiwi.kiwi_var_set_name, --- Get the current value of the variable. ---@type fun(self: kiwi.Var): number - value = ckiwi.kiwi_var_value, + value = ljkiwi.kiwi_var_value, --- Set the value of the variable. ---@type fun(self: kiwi.Var, value: number) - set = ckiwi.kiwi_var_set_value, + set = ljkiwi.kiwi_var_set_value, } --- Get the name of the variable. ---@return string ---@nodiscard function Var_cls:name() - return ffi_string(ckiwi.kiwi_var_name(self)) + return ffi_string(ljkiwi.kiwi_var_name(self)) end --- Create a term from this variable. @@ -397,7 +431,9 @@ do } function Var_mt:__new(name) - return ffi_gc(ckiwi.kiwi_var_new(name), ckiwi.kiwi_var_del) + local v = ffi_new(self) + ljkiwi.kiwi_var_construct(name, v) + return ffi_gc(v, ljkiwi.kiwi_var_release) end function Var_mt.__mul(a, b) @@ -441,6 +477,10 @@ do return a + -b end + function Var_mt:__eq(other) + return ljkiwi.kiwi_var_eq(self, other) + end + function Var_mt:__tostring() return self:name() .. "(" .. self:value() .. ")" end @@ -482,11 +522,13 @@ do local Term_mt = { __index = Term_cls } local function term_gc(term) - ckiwi.kiwi_var_del(term.var) + ljkiwi.kiwi_var_release(term.var) end function Term_mt.__new(T, var, coefficient) - return ffi_gc(ffi_new(T, ckiwi.kiwi_var_clone(var), coefficient or 1.0), term_gc) + local t = ffi_gc(ffi_new(T, var, coefficient or 1.0), term_gc) + ljkiwi.kiwi_var_retain(var) + return t end function Term_mt.__mul(a, b) @@ -542,6 +584,7 @@ do ---@class kiwi.Expression: ffi.cdata* ---@overload fun(constant: number, ...: kiwi.Term): kiwi.Expression ---@field constant number + ---@field package owner ffi.cdata* ---@field package term_count number ---@field package terms_ ffi.cdata* ---@operator mul(number): kiwi.Expression @@ -559,15 +602,16 @@ do ---@param constant number ---@nodiscard local function mul_expr_coeff(expr, constant) - local ret = ffi_gc(ffi_new(Expression, expr.term_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + local ret = ffi_gc(ffi_new(Expression, expr.term_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] for i = 0, expr.term_count - 1 do local st = expr.terms_[i] --[[@as kiwi.Term]] local dt = ret.terms_[i] --[[@as kiwi.Term]] - dt.var = ckiwi.kiwi_var_clone(st.var) + dt.var = st.var dt.coefficient = st.coefficient * constant end ret.constant = expr.constant * constant ret.term_count = expr.term_count + ljkiwi.kiwi_expression_retain(ret) return ret end @@ -577,22 +621,23 @@ do local function add_expr_expr(a, b) local a_count = a.term_count local b_count = b.term_count - local ret = ffi_gc(ffi_new(Expression, a_count + b_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + local ret = ffi_gc(ffi_new(Expression, a_count + b_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] for i = 0, a_count - 1 do local dt = ret.terms_[i] --[[@as kiwi.Term]] local st = a.terms_[i] --[[@as kiwi.Term]] - dt.var = ckiwi.kiwi_var_clone(st.var) + dt.var = st.var dt.coefficient = st.coefficient end for i = 0, b_count - 1 do local dt = ret.terms_[a_count + i] --[[@as kiwi.Term]] local st = b.terms_[i] --[[@as kiwi.Term]] - dt.var = ckiwi.kiwi_var_clone(st.var) + dt.var = st.var dt.coefficient = st.coefficient end ret.constant = a.constant + b.constant ret.term_count = a_count + b_count + ljkiwi.kiwi_expression_retain(ret) return ret end @@ -600,16 +645,17 @@ do ---@param constant number ---@nodiscard local function new_expr_constant(expr, constant) - local ret = ffi_gc(ffi_new(Expression, expr.term_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + local ret = ffi_gc(ffi_new(Expression, expr.term_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] for i = 0, expr.term_count - 1 do local dt = ret.terms_[i] --[[@as kiwi.Term]] local st = expr.terms_[i] --[[@as kiwi.Term]] - dt.var = ckiwi.kiwi_var_clone(st.var) + dt.var = st.var dt.coefficient = st.coefficient end ret.constant = constant ret.term_count = expr.term_count + ljkiwi.kiwi_expression_retain(ret) return ret end @@ -645,17 +691,18 @@ do __index = Expression_cls, } - function Expression_mt.__new(T, constant, ...) + function Expression_mt:__new(constant, ...) local term_count = select("#", ...) - local e = ffi_gc(ffi_new(T, term_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + local e = ffi_gc(ffi_new(self, term_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] e.term_count = term_count e.constant = constant for i = 1, term_count do local t = select(i, ...) local dt = e.terms_[i - 1] --[[@as kiwi.Term]] - dt.var = ckiwi.kiwi_var_clone(t.var) + dt.var = t.var dt.coefficient = t.coefficient end + ljkiwi.kiwi_expression_retain(e) return e end @@ -722,29 +769,29 @@ do local Constraint_cls = { --- The strength of the constraint. ---@type fun(self: kiwi.Constraint): number - strength = ckiwi.kiwi_constraint_strength, + strength = ljkiwi.kiwi_constraint_strength, --- The relational operator of the constraint. ---@type fun(self: kiwi.Constraint): kiwi.RelOp - op = ckiwi.kiwi_constraint_op, + op = ljkiwi.kiwi_constraint_op, --- Whether the constraint is violated in the current solution. ---@type fun(self: kiwi.Constraint): boolean - violated = ckiwi.kiwi_constraint_violated, + violated = ljkiwi.kiwi_constraint_violated, } --- The reduced expression defining the constraint. ---@return kiwi.Expression ---@nodiscard function Constraint_cls:expression() - local SZ = 7 -- 2**7 bytes on x64 + local SZ = 7 local expr = ffi_new(Expression, SZ) --[[@as kiwi.Expression]] - local n = ckiwi.kiwi_constraint_expression(self, expr, SZ) + local n = ljkiwi.kiwi_constraint_expression(self, expr, SZ) if n > SZ then expr = ffi_new(Expression, n) --[[@as kiwi.Expression]] - n = ckiwi.kiwi_constraint_expression(self, expr, n) + n = ljkiwi.kiwi_constraint_expression(self, expr, n) end - return ffi_gc(expr, ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]] + return ffi_gc(expr, ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]] end --- Add the constraint to the solver. @@ -773,10 +820,9 @@ do } function Constraint_mt:__new(lhs, rhs, op, strength) - return ffi_gc( - ckiwi.kiwi_constraint_new(lhs, rhs, op or "EQ", strength or REQUIRED), - ckiwi.kiwi_constraint_del - ) + local c = ffi_new(self) + ljkiwi.kiwi_constraint_construct(lhs, rhs, op or "EQ", strength or REQUIRED, c) + return ffi_gc(c, ljkiwi.kiwi_constraint_release) end local OPS = { [0] = "<=", ">=", "==" } @@ -822,10 +868,9 @@ do tmpexpr.constant = constant ~= nil and constant or 0 tmpexpr.term_count = 2 - return ffi_gc( - ckiwi.kiwi_constraint_new(tmpexpr, nil, op or "EQ", strength or REQUIRED), - ckiwi.kiwi_constraint_del - ) --[[@as kiwi.Constraint]] + local c = ffi_new(Constraint) + ljkiwi.kiwi_constraint_construct(tmpexpr, nil, op or "EQ", strength or REQUIRED, c) + return ffi_gc(c, ljkiwi.kiwi_constraint_release) --[[@as kiwi.Constraint]] end local pair_ratio = constraints.pair_ratio @@ -858,10 +903,10 @@ do local t = tmpexpr.terms_[0] t.var = var t.coefficient = 1.0 - return ffi_gc( - ckiwi.kiwi_constraint_new(tmpexpr, nil, op or "EQ", strength or REQUIRED), - ckiwi.kiwi_constraint_del - ) --[[@as kiwi.Constraint]] + + local c = ffi_new(Constraint) + ljkiwi.kiwi_constraint_construct(tmpexpr, nil, op or "EQ", strength or REQUIRED, c) + return ffi_gc(c, ljkiwi.kiwi_constraint_release) --[[@as kiwi.Constraint]] end end @@ -947,7 +992,7 @@ do C.free(err) end local errdata = new_error(kind, message, solver, item) - local error_mask = solver and solver.error_mask_ or 0 + local error_mask = ljkiwi.kiwi_solver_get_error_mask(solver) return item, band(error_mask, lshift(1, kind --[[@as integer]])) == 0 and error(errdata) or errdata @@ -955,20 +1000,19 @@ do return item end ---@class kiwi.Solver: ffi.cdata* - ---@field package error_mask_ integer ---@overload fun(error_mask: (integer|(kiwi.ErrKind|integer)[] )?): kiwi.Solver local Solver_cls = { --- Test whether a constraint is in the solver. ---@type fun(self: kiwi.Solver, constraint: kiwi.Constraint): boolean - has_constraint = ckiwi.kiwi_solver_has_constraint, + has_constraint = ljkiwi.kiwi_solver_has_constraint, --- Test whether an edit variable has been added to the solver. ---@type fun(self: kiwi.Solver, var: kiwi.Var): boolean - has_edit_var = ckiwi.kiwi_solver_has_edit_var, + has_edit_var = ljkiwi.kiwi_solver_has_edit_var, --- Update the values of the external solver variables. ---@type fun(self: kiwi.Solver) - update_vars = ckiwi.kiwi_solver_update_vars, + update_vars = ljkiwi.kiwi_solver_update_vars, --- Reset the solver to the empty starting conditions. --- @@ -978,11 +1022,11 @@ do --- when the entire system must change, since it can avoid unecessary --- heap (de)allocations. ---@type fun(self: kiwi.Solver) - reset = ckiwi.kiwi_solver_reset, + reset = ljkiwi.kiwi_solver_reset, --- Dump a representation of the solver to stdout. ---@type fun(self: kiwi.Solver) - dump = ckiwi.kiwi_solver_dump, + dump = ljkiwi.kiwi_solver_dump, } --- Sets the error mask for the solver. @@ -992,7 +1036,7 @@ do if type(mask) == "table" then mask = kiwi.error_mask(mask, invert) end - self.error_mask_ = mask + ljkiwi.kiwi_solver_set_error_mask(self, mask) end ---@generic T @@ -1017,7 +1061,7 @@ do ---@param constraint kiwi.Constraint ---@return kiwi.Constraint constraint, kiwi.Error? function Solver_cls:add_constraint(constraint) - return try_solver(ckiwi.kiwi_solver_add_constraint, self, constraint) + return try_solver(ljkiwi.kiwi_solver_add_constraint, self, constraint) end --- Add constraints to the solver. @@ -1027,7 +1071,7 @@ do ---@param constraints kiwi.Constraint[] ---@return kiwi.Constraint[] constraints, kiwi.Error? function Solver_cls:add_constraints(constraints) - return add_remove_items(self, constraints, ckiwi.kiwi_solver_add_constraint) + return add_remove_items(self, constraints, ljkiwi.kiwi_solver_add_constraint) end --- Remove a constraint from the solver. @@ -1036,7 +1080,7 @@ do ---@param constraint kiwi.Constraint ---@return kiwi.Constraint constraint, kiwi.Error? function Solver_cls:remove_constraint(constraint) - return try_solver(ckiwi.kiwi_solver_remove_constraint, self, constraint) + return try_solver(ljkiwi.kiwi_solver_remove_constraint, self, constraint) end --- Remove constraints from the solver. @@ -1045,7 +1089,7 @@ do ---@param constraints kiwi.Constraint[] ---@return kiwi.Constraint[] constraints, kiwi.Error? function Solver_cls:remove_constraints(constraints) - return add_remove_items(self, constraints, ckiwi.kiwi_solver_remove_constraint) + return add_remove_items(self, constraints, ljkiwi.kiwi_solver_remove_constraint) end --- Add an edit variables to the solver. @@ -1059,7 +1103,7 @@ do ---@param strength number the strength of the edit variable (must be less than `Strength.REQUIRED`) ---@return kiwi.Var var, kiwi.Error? function Solver_cls:add_edit_var(var, strength) - return try_solver(ckiwi.kiwi_solver_add_edit_var, self, var, strength) + return try_solver(ljkiwi.kiwi_solver_add_edit_var, self, var, strength) end --- Add edit variables to the solver. @@ -1073,7 +1117,7 @@ do ---@param strength number the strength of the edit variables (must be less than `Strength.REQUIRED`) ---@return kiwi.Var[] vars, kiwi.Error? function Solver_cls:add_edit_vars(vars, strength) - return add_remove_items(self, vars, ckiwi.kiwi_solver_add_edit_var, strength) + return add_remove_items(self, vars, ljkiwi.kiwi_solver_add_edit_var, strength) end --- Remove an edit variable from the solver. @@ -1082,7 +1126,7 @@ do ---@param var kiwi.Var the edit variable to remove ---@return kiwi.Var var, kiwi.Error? function Solver_cls:remove_edit_var(var) - return try_solver(ckiwi.kiwi_solver_remove_edit_var, self, var) + return try_solver(ljkiwi.kiwi_solver_remove_edit_var, self, var) end --- Removes edit variables from the solver. @@ -1091,7 +1135,7 @@ do ---@param vars kiwi.Var[] the edit variables to remove ---@return kiwi.Var[] vars, kiwi.Error? function Solver_cls:remove_edit_vars(vars) - return add_remove_items(self, vars, ckiwi.kiwi_solver_remove_edit_var) + return add_remove_items(self, vars, ljkiwi.kiwi_solver_remove_edit_var) end --- Suggest a value for the given edit variable. @@ -1104,7 +1148,7 @@ do ---@param value number the suggested value ---@return kiwi.Var var, kiwi.Error? function Solver_cls:suggest_value(var, value) - return try_solver(ckiwi.kiwi_solver_suggest_value, self, var, value) + return try_solver(ljkiwi.kiwi_solver_suggest_value, self, var, value) end --- Suggest values for the given edit variables. @@ -1116,7 +1160,7 @@ do ---@return kiwi.Var[] vars, number[] values, kiwi.Error? function Solver_cls:suggest_values(vars, values) for i, var in ipairs(vars) do - local _, err = try_solver(ckiwi.kiwi_solver_suggest_value, self, var, values[i]) + local _, err = try_solver(ljkiwi.kiwi_solver_suggest_value, self, var, values[i]) if err ~= nil then return vars, values, err end @@ -1128,7 +1172,7 @@ do ---@return string ---@nodiscard function Solver_cls:dumps() - local cs = ckiwi.kiwi_solver_dumps(self) + local cs = ljkiwi.kiwi_solver_dumps(self) local s = ffi_string(cs) C.free(cs) return s @@ -1138,17 +1182,23 @@ do __index = Solver_cls, } + local Solver = ffi.typeof("struct KiwiSolver") --[[@as kiwi.Solver]] + kiwi.Solver = Solver + function Solver_mt:__new(error_mask) if type(error_mask) == "table" then error_mask = kiwi.error_mask(error_mask) end - return ffi_gc(ckiwi.kiwi_solver_new(error_mask or 0), ckiwi.kiwi_solver_del) + + local s = ffi_new(Solver) + ljkiwi.kiwi_solver_construct(error_mask or 0, s) + return ffi_gc(s, ljkiwi.kiwi_solver_destroy) --[[@as kiwi.Constraint]] end - kiwi.Solver = ffi.metatype("struct KiwiSolver", Solver_mt) --[[@as kiwi.Solver]] + kiwi.Solver = ffi.metatype(Solver, Solver_mt) --[[@as kiwi.Solver]] function kiwi.is_solver(s) - return ffi_istype(kiwi.Solver, s) + return ffi_istype(Solver, s) end end diff --git a/ljkiwi.def b/ljkiwi.def new file mode 100644 index 0000000..37d39b7 --- /dev/null +++ b/ljkiwi.def @@ -0,0 +1,37 @@ +EXPORTS +luaopen_ljkiwi + +kiwi_ti_KiwiVar +kiwi_ti_KiwiConstraint +kiwi_ti_KiwiSolver + +kiwi_constraint_construct +kiwi_constraint_expression +kiwi_constraint_op +kiwi_constraint_release +kiwi_constraint_retain +kiwi_constraint_strength +kiwi_constraint_violated +kiwi_expression_destroy +kiwi_solver_add_constraint +kiwi_solver_add_edit_var +kiwi_solver_construct +kiwi_solver_destroy +kiwi_solver_dump +kiwi_solver_dumps +kiwi_solver_has_constraint +kiwi_solver_has_edit_var +kiwi_solver_remove_constraint +kiwi_solver_remove_edit_var +kiwi_solver_reset +kiwi_solver_suggest_value +kiwi_solver_update_vars +kiwi_var_construct +kiwi_var_destroy +kiwi_var_eq +kiwi_var_name +kiwi_var_release +kiwi_var_retain +kiwi_var_set_name +kiwi_var_set_value +kiwi_var_value diff --git a/ljkiwi.hpp b/ljkiwi.hpp new file mode 100644 index 0000000..d222c8d --- /dev/null +++ b/ljkiwi.hpp @@ -0,0 +1 @@ +#include diff --git a/luakiwi.def b/luakiwi.def deleted file mode 100644 index 24aea45..0000000 --- a/luakiwi.def +++ /dev/null @@ -1,2 +0,0 @@ -EXPORTS -luaopen_ckiwi \ No newline at end of file diff --git a/luakiwi/.clang-format b/luakiwi/.clang-format deleted file mode 100644 index f9132f8..0000000 --- a/luakiwi/.clang-format +++ /dev/null @@ -1,88 +0,0 @@ -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: '^' - 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 diff --git a/luakiwi/luakiwi-int.h b/luakiwi/luakiwi-int.h index 727fe95..fb22c7d 100644 --- a/luakiwi/luakiwi-int.h +++ b/luakiwi/luakiwi-int.h @@ -8,7 +8,7 @@ #include "luacompat.h" -#if defined(__GNUC__) && !defined(LKIWI_NO_BUILTIN) +#if defined(__GNUC__) && !defined(LJKIWI_NO_BUILTIN) #define lk_likely(x) (__builtin_expect(((x) != 0), 1)) #define lk_unlikely(x) (__builtin_expect(((x) != 0), 0)) #else @@ -58,7 +58,7 @@ constexpr int array_count(T (&)[N]) { return static_cast(N); } -void newlib(lua_State* L, const luaL_Reg* l) { +inline void newlib(lua_State* L, const luaL_Reg* l) { lua_newtable(L); setfuncs(L, l, 0); } diff --git a/luakiwi/luakiwi.cpp b/luakiwi/luakiwi.cpp index 9fdde07..8a4f02b 100644 --- a/luakiwi/luakiwi.cpp +++ b/luakiwi/luakiwi.cpp @@ -1,3 +1,4 @@ +#include "ljkiwi.hpp" #include #include #include @@ -955,7 +956,7 @@ int lkiwi_constraint_expression(lua_State* L) { auto* c = get_constraint(L, 1); const auto& expr = c->expression(); const auto& terms = expr.terms(); - const int term_count = terms.size(); + const auto term_count = static_cast(terms.size()); auto* ne = expr_new(L, term_count); ne->owner = kiwi_constraint_retain(c); @@ -1562,7 +1563,7 @@ void register_type_n( const luaL_Reg* m, size_t mcnt ) { - lua_createtable(L, 0, mcnt + 2); + lua_createtable(L, 0, static_cast(mcnt + 2)); lua_pushvalue(L, -2); // no_member_mt lua_setmetatable(L, -2); lua_pushstring(L, name); @@ -1605,7 +1606,11 @@ void compat_init(lua_State*, int) {} } // namespace -extern "C" int luaopen_ckiwi(lua_State* L) { +#if defined __GNUC__ && (!defined _WIN32 || defined __CYGWIN__) + #define LJKIWI_EXPORT __attribute__((__visibility__("default"))) +#endif + +extern "C" LJKIWI_EXPORT int luaopen_ljkiwi(lua_State* L) { luaL_checkversion(L); /* context table */