skin this cat

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

88
luakiwi/.clang-format Normal file
View File

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

331
luakiwi/kiwibridge.cpp Normal file
View File

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

147
luakiwi/luacompat.h Normal file
View File

@@ -0,0 +1,147 @@
#ifndef LKIWI_LUACOMPAT_H_
#define LKIWI_LUACOMPAT_H_
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include <lauxlib.h>
#include <lua.h>
#include <lualib.h>
#ifdef __cplusplus
}
#endif // __cplusplus
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
#define LUA_OPADD 0
#define LUA_OPSUB 1
#define LUA_OPMUL 2
#define LUA_OPDIV 3
#define LUA_OPMOD 4
#define LUA_OPPOW 5
#define LUA_OPUNM 6
static int lua_absindex(lua_State* L, int i) {
if (i < 0 && i > LUA_REGISTRYINDEX)
i += lua_gettop(L) + 1;
return i;
}
static lua_Number lua_tonumberx(lua_State* L, int i, int* isnum) {
lua_Number n = lua_tonumber(L, i);
if (isnum != NULL) {
*isnum = (n != 0 || lua_isnumber(L, i));
}
return n;
}
static lua_Integer lua_tointegerx(lua_State* L, int i, int* isnum) {
int ok = 0;
lua_Number n = lua_tonumberx(L, i, &ok);
if (ok) {
if (n == (lua_Integer)n) {
if (isnum)
*isnum = 1;
return (lua_Integer)n;
}
}
if (isnum)
*isnum = 0;
return 0;
}
static const char* luaL_tolstring(lua_State* L, int idx, size_t* len) {
if (!luaL_callmeta(L, idx, "__tostring")) {
int t = lua_type(L, idx), tt = 0;
char const* name = NULL;
switch (t) {
case LUA_TNIL:
lua_pushliteral(L, "nil");
break;
case LUA_TSTRING:
case LUA_TNUMBER:
lua_pushvalue(L, idx);
break;
case LUA_TBOOLEAN:
if (lua_toboolean(L, idx))
lua_pushliteral(L, "true");
else
lua_pushliteral(L, "false");
break;
default:
tt = luaL_getmetafield(L, idx, "__name");
name = (tt == LUA_TSTRING) ? lua_tostring(L, -1) : lua_typename(L, t);
lua_pushfstring(L, "%s: %p", name, lua_topointer(L, idx));
if (tt != LUA_TNIL)
lua_replace(L, -2);
break;
}
} else {
if (!lua_isstring(L, -1))
luaL_error(L, "'__tostring' must return a string");
}
return lua_tolstring(L, -1, len);
}
#endif /* LUA_VERSION_NUM == 501 */
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 502
static void compat_reverse(lua_State* L, int a, int b) {
for (; a < b; ++a, --b) {
lua_pushvalue(L, a);
lua_pushvalue(L, b);
lua_replace(L, a);
lua_replace(L, b);
}
}
static void lua_rotate(lua_State* L, int idx, int n) {
int n_elems = 0;
idx = lua_absindex(L, idx);
n_elems = lua_gettop(L) - idx + 1;
if (n < 0)
n += n_elems;
if (n > 0 && n < n_elems) {
luaL_checkstack(L, 2, "not enough stack slots available");
n = n_elems - n;
compat_reverse(L, idx, idx + n - 1);
compat_reverse(L, idx + n, idx + n_elems - 1);
compat_reverse(L, idx, idx + n_elems - 1);
}
}
static int lua_geti(lua_State* L, int index, lua_Integer i) {
index = lua_absindex(L, index);
lua_pushinteger(L, i);
lua_gettable(L, index);
return lua_type(L, -1);
}
#endif /* LUA_VERSION_NUM <= 502 */
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM <= 503
static int luaL_typeerror(lua_State* L, int arg, const char* tname) {
const char* msg;
const char* typearg; /* name for the type of the actual argument */
if (luaL_getmetafield(L, arg, "__name") == LUA_TSTRING)
typearg = lua_tostring(L, -1); /* use the given type name */
else if (lua_type(L, arg) == LUA_TLIGHTUSERDATA)
typearg = "light userdata"; /* special name for messages */
else
typearg = luaL_typename(L, arg); /* standard name */
msg = lua_pushfstring(L, "%s expected, got %s", tname, typearg);
return luaL_argerror(L, arg, msg);
}
#endif /* LUA_VERSION_NUM <= 503 */
#if !defined(luaL_newlibtable)
#define luaL_newlibtable(L, l) lua_createtable(L, 0, sizeof(l) / sizeof((l)[0]) - 1)
#endif
#if !defined(luaL_checkversion)
#define luaL_checkversion(L) ((void)0)
#endif
#endif // LKIWI_LUACOMPAT_H_

84
luakiwi/luakiwi-int.h Normal file
View File

@@ -0,0 +1,84 @@
#ifndef LUAKIWI_INT_H_
#define LUAKIWI_INT_H_
#include "luacompat.h"
#define ARR_COUNT(x) ((int)(sizeof(x) / sizeof((x)[0])))
#if defined(__GNUC__) && !defined(LKIWI_NO_BUILTIN)
#define l_likely(x) (__builtin_expect(((x) != 0), 1))
#define l_unlikely(x) (__builtin_expect(((x) != 0), 0))
#else
#define l_likely(x) (x)
#define l_unlikely(x) (x)
#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.
static void compat_arith_unm(lua_State* L) {
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
lua_Number n = lua_tonumber(L, -1);
if (n != 0 || lua_isnumber(L, -1)) {
lua_pop(L, 1);
lua_pushnumber(L, -n);
} else {
if (!luaL_callmeta(L, -1, "__unm"))
luaL_error(L, "attempt to perform arithmetic on a %s value", luaL_typename(L, -1));
lua_replace(L, -2);
}
#else
lua_arith(L, LUA_OPUNM);
#endif
}
// This version supports placeholders.
static void setfuncs(lua_State* L, const luaL_Reg* l, int nup) {
luaL_checkstack(L, nup, "too many upvalues");
for (; l->name != NULL; l++) { /* fill the table with given functions */
if (l->func == NULL) /* place holder? */
lua_pushboolean(L, 0);
else {
int i;
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(L, -nup);
lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
}
lua_setfield(L, -(nup + 2), l->name);
}
lua_pop(L, nup); /* remove upvalues */
}
#define newlib(L, l) (lua_newtable((L)), setfuncs((L), (l), 0))
#endif // LUAKIWI_INT_H_

1702
luakiwi/luakiwi.cpp Normal file

File diff suppressed because it is too large Load Diff