Compare commits
27 Commits
c35cea6213
...
lua-api-cp
| Author | SHA1 | Date | |
|---|---|---|---|
| 579d671a77 | |||
| 61ba76c5a3 | |||
| 8854c0edbe | |||
| 00a9fda814 | |||
| a8c1a10cab | |||
| 2a71914ed8 | |||
| dea448e46b | |||
| 3811d82212 | |||
| 2baee14c5d | |||
| 198265ee36 | |||
| 604e3df41f | |||
| 6a99504835 | |||
| 9b00e62d43 | |||
| 3631704544 | |||
| 17f67b8879 | |||
| d83cc3468c | |||
| b3cf6136a4 | |||
| 2ffc5a333b | |||
| d85796a038 | |||
| 37833f7b2b | |||
| 59465d3142 | |||
| 8b57e0c441 | |||
| bc948d1a61 | |||
| 3311b582a1 | |||
| 84a01179cd | |||
| e43272487f | |||
| 59bdeedc18 |
34
.github/workflows/busted.yml
vendored
34
.github/workflows/busted.yml
vendored
@@ -7,25 +7,13 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
lua_version:
|
lua_version: ["luajit-openresty", "luajit-2.1.0-beta3", "luajit-git"]
|
||||||
[
|
|
||||||
"luajit-openresty",
|
|
||||||
"luajit-2.1.0-beta3",
|
|
||||||
"luajit-git",
|
|
||||||
"5.4.6",
|
|
||||||
"5.1.5",
|
|
||||||
"5.3.6",
|
|
||||||
]
|
|
||||||
os: ["ubuntu-latest", "windows-latest", "macos-latest"]
|
|
||||||
|
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
- uses: ilammy/msvc-dev-cmd@v1
|
|
||||||
if: ${{ !startsWith(matrix.lua_version, 'luajit-') }}
|
|
||||||
|
|
||||||
- name: Setup ‘lua’
|
- name: Setup ‘lua’
|
||||||
uses: jkl1337/gh-actions-lua@master
|
uses: jkl1337/gh-actions-lua@master
|
||||||
with:
|
with:
|
||||||
@@ -37,24 +25,12 @@ jobs:
|
|||||||
luarocks install busted
|
luarocks install busted
|
||||||
luarocks install luacov-coveralls
|
luarocks install luacov-coveralls
|
||||||
- name: Build C library
|
- name: Build C library
|
||||||
run: |
|
run: make
|
||||||
${{ matrix.os == 'ubuntu-latest' && 'FSANITIZE=1' || '' }} luarocks make --no-install
|
|
||||||
- name: Run busted tests
|
- name: Run busted tests
|
||||||
run: |
|
run: busted -c -v
|
||||||
${{ matrix.os == 'ubuntu-latest' && 'LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libasan.so.6:/usr/lib/x86_64-linux-gnu/libstdc++.so.6:/usr/lib/x86_64-linux-gnu/libubsan.so.1' || '' }} busted -c -v
|
|
||||||
- name: Report test coverage
|
- name: Report test coverage
|
||||||
if: success() && !startsWith(matrix.os, 'windows-') && startsWith(matrix.lua_version, 'luajit-')
|
if: success()
|
||||||
continue-on-error: true
|
continue-on-error: true
|
||||||
run: luacov-coveralls -e .luarocks -e spec
|
run: luacov-coveralls -e .luarocks -e spec
|
||||||
env:
|
env:
|
||||||
COVERALLS_REPO_TOKEN: ${{ github.token }}
|
COVERALLS_REPO_TOKEN: ${{ github.token }}
|
||||||
|
|
||||||
finish:
|
|
||||||
if: always()
|
|
||||||
needs: busted
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Close coveralls build
|
|
||||||
uses: coverallsapp/github-action@v2
|
|
||||||
with:
|
|
||||||
parallel-finished: true
|
|
||||||
|
|||||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -2,14 +2,7 @@
|
|||||||
/lua
|
/lua
|
||||||
/lua_modules
|
/lua_modules
|
||||||
/.luarocks
|
/.luarocks
|
||||||
/config.mk
|
|
||||||
*.pch
|
|
||||||
*.gch
|
|
||||||
*.lib
|
|
||||||
*.so
|
*.so
|
||||||
*.o
|
*.o
|
||||||
*.obj
|
|
||||||
*.exp
|
|
||||||
*.dll
|
|
||||||
.cache/
|
.cache/
|
||||||
compile_commands.json
|
compile_commands.json
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
"$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
|
||||||
"runtime.version": "LuaJIT",
|
"runtime.version": "Lua 5.4",
|
||||||
"runtime.path": [
|
"runtime.path": [
|
||||||
"./?/init.lua",
|
"./?/init.lua",
|
||||||
"./?.lua",
|
"./?.lua",
|
||||||
|
|||||||
145
Makefile
145
Makefile
@@ -1,131 +1,56 @@
|
|||||||
CXX := $(CROSS)g++
|
SRCDIR := .
|
||||||
CP := cp
|
CC := $(CROSS)gcc
|
||||||
RM := rm
|
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)
|
||||||
LIBFLAG := -shared
|
LIBFLAG := -shared
|
||||||
LIB_EXT := $(if $(filter Windows_NT,$(OS)),dll,so)
|
LIB_EXT := so
|
||||||
LUA_INCDIR := /usr/include
|
LUA_INCDIR := /usr/include
|
||||||
|
|
||||||
SRCDIR := $(dir $(realpath $(lastword $(MAKEFILE_LIST))))
|
ifeq ($(findstring gcc,$(CC)),gcc)
|
||||||
|
CXX := $(subst gcc,g++,$(CC))
|
||||||
ifeq ($(OS),Windows_NT)
|
CXXFLAGS += -std=c++14
|
||||||
is_clang = $(filter %clang++,$(CXX))
|
ifneq ($(SANITIZE),)
|
||||||
is_gcc = $(filter %g++,$(CXX))
|
CFLAGS += -fsanitize=undefined -fsanitize=address
|
||||||
else
|
|
||||||
uname_s := $(shell uname -s)
|
|
||||||
ifeq ($(uname_s),Darwin)
|
|
||||||
CC := env MACOSX_DEPLOYMENT_TARGET=11.0 gcc
|
|
||||||
CXX := env MACOSX_DEPLOYMENT_TARGET=11.0 g++
|
|
||||||
LIBFLAG := -bundle -undefined dynamic_lookup
|
|
||||||
is_clang = 1
|
|
||||||
is_gcc =
|
|
||||||
else
|
|
||||||
is_clang = $(filter %clang++,$(CXX))
|
|
||||||
is_gcc = $(filter %g++,$(CXX))
|
|
||||||
endif
|
endif
|
||||||
endif
|
else
|
||||||
|
ifeq ($(CC),clang)
|
||||||
OPTFLAG := -O2
|
CXX := clang++
|
||||||
SANITIZE_FLAGS := -fsanitize=undefined -fsanitize=address -fsanitize=alignment -fsanitize=bounds-strict \
|
CXXFLAGS += -std=c++14
|
||||||
-fsanitize=shift -fsanitize=unreachable -fsanitize=bool \
|
ifneq ($(SANITIZE),)
|
||||||
-fsanitize=enum
|
CFLAGS += -fsanitize=undefined -fsanitize=address
|
||||||
|
|
||||||
LTO_FLAGS := -flto=auto
|
|
||||||
|
|
||||||
-include config.mk
|
|
||||||
|
|
||||||
ifeq ($(origin LUAROCKS), command line)
|
|
||||||
CCFLAGS := $(CFLAGS)
|
|
||||||
override CFLAGS := -std=c99 $(CCFLAGS)
|
|
||||||
|
|
||||||
ifneq ($(filter %gcc,$(CC)),)
|
|
||||||
CXX := $(patsubst %gcc,%g++,$(CC))
|
|
||||||
else
|
|
||||||
ifneq ($(filter %clang,$(CC)),)
|
|
||||||
CXX := $(patsubst %clang,%clang++,$(CC))
|
|
||||||
endif
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
else
|
else
|
||||||
CCFLAGS += -fPIC $(OPTFLAG)
|
CXX := $(CC)
|
||||||
override CFLAGS += -std=c99 $(CCFLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
CCFLAGS += -Wall -fvisibility=hidden -Wformat=2 -Wconversion -Wimplicit-fallthrough
|
|
||||||
|
|
||||||
ifdef FSANITIZE
|
|
||||||
CCFLAGS += $(SANITIZE_FLAGS)
|
|
||||||
endif
|
|
||||||
ifndef FNOLTO
|
|
||||||
CCFLAGS += $(LTO_FLAGS)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifneq ($(is_gcc),)
|
|
||||||
#PCH := ljkiwi.hpp.gch
|
|
||||||
else
|
|
||||||
ifneq ($(is_clang),)
|
|
||||||
override CXXFLAGS += -pedantic -Wno-c99-extensions
|
|
||||||
#PCH := ljkiwi.hpp.pch
|
|
||||||
endif
|
|
||||||
endif
|
|
||||||
|
|
||||||
override CPPFLAGS += -I$(SRCDIR) -I$(SRCDIR)/kiwi -I"$(LUA_INCDIR)"
|
|
||||||
override CXXFLAGS += -std=c++14 -fno-rtti $(CCFLAGS)
|
|
||||||
|
|
||||||
ifeq ($(OS),Windows_NT)
|
|
||||||
override CPPFLAGS += -DLUA_BUILD_AS_DLL
|
|
||||||
override LIBFLAG += "$(LUA_LIBDIR)/$(LUALIB)"
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifdef LUA
|
|
||||||
LUA_VERSION ?= $(lastword $(shell "$(LUA)" -e "print(_VERSION)"))
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifndef LUA_VERSION
|
|
||||||
LJKIWI_CKIWI := 1
|
|
||||||
else
|
|
||||||
ifeq ($(LUA_VERSION),5.1)
|
|
||||||
LJKIWI_CKIWI := 1
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
kiwi_lib_srcs := AssocVector.h constraint.h debug.h errors.h expression.h kiwi.h maptype.h \
|
OBJS := ckiwi.o luakiwi.o
|
||||||
row.h shareddata.h solver.h solverimpl.h strength.h symbol.h symbolics.h term.h \
|
|
||||||
util.h variable.h version.h
|
|
||||||
|
|
||||||
objs := luakiwi.o
|
VPATH = $(SRCDIR)/ckiwi $(SRCDIR)/luakiwi
|
||||||
ifdef LJKIWI_CKIWI
|
|
||||||
objs += ckiwi.o
|
|
||||||
endif
|
|
||||||
|
|
||||||
vpath %.cpp $(SRCDIR)/ckiwi $(SRCDIR)/luakiwi
|
all: ckiwi.$(LIB_EXT)
|
||||||
vpath %.h $(SRCDIR)/ckiwi $(SRCDIR)/luakiwi $(SRCDIR)/kiwi/kiwi
|
|
||||||
|
|
||||||
all: ljkiwi.$(LIB_EXT)
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
$(CP) -f ljkiwi.$(LIB_EXT) $(INST_LIBDIR)/ljkiwi.$(LIB_EXT)
|
cp -f ckiwi.$(LIB_EXT) $(INST_LIBDIR)/ckiwi.$(LIB_EXT)
|
||||||
$(CP) -f kiwi.lua $(INST_LUADIR)/kiwi.lua
|
cp -f kiwi.lua $(INST_LUADIR)/kiwi.lua
|
||||||
|
|
||||||
mostlyclean:
|
clean:
|
||||||
$(RM) -f ljkiwi.$(LIB_EXT) $(objs)
|
rm -f ckiwi.$(LIB_EXT) $(OBJS)
|
||||||
|
|
||||||
clean: mostlyclean
|
|
||||||
$(RM) -f $(PCH)
|
|
||||||
|
|
||||||
ckiwi.o: $(PCH) ckiwi.cpp ckiwi.h $(kiwi_lib_srcs)
|
ckiwi.$(LIB_EXT): $(OBJS)
|
||||||
luakiwi.o: $(PCH) luakiwi-int.h luacompat.h $(kiwi_lib_srcs)
|
$(CXX) $(CXXFLAGS) $(CFLAGS) $(CFLAGS_EXTRA) -I$(SRCDIR)/kiwi $(LIBFLAG) -o $@ $^
|
||||||
$(PCH): $(kiwi_lib_srcs)
|
|
||||||
|
|
||||||
ljkiwi.$(LIB_EXT): $(objs)
|
ckiwi.o: ckiwi.h
|
||||||
$(CXX) $(CCFLAGS) $(LIBFLAG) -o $@ $(objs)
|
luakiwi.o: ckiwi.h luakiwi-int.h luacompat.h
|
||||||
|
|
||||||
%.hpp.gch: %.hpp
|
%.o: %.c
|
||||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -x c++-header -o $@ $<
|
$(CC) -I$(LUA_INCDIR) $(CFLAGS) $(CFLAGS_EXTRA) -c -o $@ $<
|
||||||
|
|
||||||
%.hpp.pch: %.hpp
|
|
||||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ -x c++-header $<
|
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c -o $@ $<
|
$(CXX) -I$(LUA_INCDIR) $(CXXFLAGS) $(CFLAGS) $(CXXFLAGS_EXTRA) -c -o $@ $<
|
||||||
|
|
||||||
.PHONY: all install clean mostlyclean
|
.PHONY: all install clean
|
||||||
|
|||||||
21
Makefile.win
21
Makefile.win
@@ -1,21 +0,0 @@
|
|||||||
T= ljkiwi
|
|
||||||
|
|
||||||
OBJS= luakiwi.obj
|
|
||||||
|
|
||||||
lib: $T.dll
|
|
||||||
|
|
||||||
{luakiwi\}.cpp.obj:
|
|
||||||
$(CC) $(CFLAGS) /W4 /wd4200 /c /D_CRT_SECURE_NO_DEPRECATE /I. /I kiwi /I"$(LUA_INCDIR)" /EHs /Fo$@ $(CFLAGS) $<
|
|
||||||
|
|
||||||
$T.dll: $(OBJS)
|
|
||||||
link $(LIBFLAG) /out:$T.dll "$(LUA_LIBDIR)\$(LUALIB)" $(OBJS)
|
|
||||||
IF EXIST $T.dll.manifest mt -manifest $T.dll.manifest -outputresource:$T.dll;2
|
|
||||||
|
|
||||||
install: $T.dll
|
|
||||||
IF NOT EXIST "$(INST_LIBDIR)" mkdir "$(INST_LIBDIR)"
|
|
||||||
copy $T.dll "$(INST_LIBDIR)"
|
|
||||||
copy kiwi.lua "$(INST_LUADIR)"
|
|
||||||
|
|
||||||
clean:
|
|
||||||
del $T.dll $(OBJS) $T.lib $T.exp
|
|
||||||
IF EXIST $T.dll.manifest del $T.dll.manifest
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
ljkiwi - Free LuaJIT FFI and Lua C API kiwi (Cassowary derived) constraint solver.
|
ljkiwi - Free LuaJIT FFI kiwi (Cassowary derived) constraint solver.
|
||||||
|
|
||||||
[](https://github.com/jkl1337/ljkiwi/actions/workflows/busted.yml)
|
[](https://github.com/jkl1337/ljkiwi/actions/workflows/busted.yml)
|
||||||
[](https://coveralls.io/github/jkl1337/ljkiwi?branch=master)
|
[](https://coveralls.io/github/jkl1337/ljkiwi?branch=master)
|
||||||
[](https://luarocks.org/modules/jkl/kiwi)
|
[](https://luarocks.org/modules/jkl/ljkiwi)
|
||||||
|
|
||||||
# Introduction
|
# Introduction
|
||||||
|
|
||||||
@@ -10,8 +10,8 @@ Kiwi is a reasonably efficient C++ implementation of the Cassowary constraint so
|
|||||||
Cassowary constraint solving is a technique that is particularly well suited to user interface layout. It is the algorithm Apple uses for iOS and OS X Auto Layout.
|
Cassowary constraint solving is a technique that is particularly well suited to user interface layout. It is the algorithm Apple uses for iOS and OS X Auto Layout.
|
||||||
|
|
||||||
There are a few Lua implementations or attempts. The SILE typesetting system has a pure Lua implementation of the original Cassowary code, which appears to be correct but is quite slow. There are two extant Lua ports of Kiwi, one that is based on a C rewrite of Kiwi. However testing of these was not encouraging with either segfaults or incorrect results.
|
There are a few Lua implementations or attempts. The SILE typesetting system has a pure Lua implementation of the original Cassowary code, which appears to be correct but is quite slow. There are two extant Lua ports of Kiwi, one that is based on a C rewrite of Kiwi. However testing of these was not encouraging with either segfaults or incorrect results.
|
||||||
Since the C++ Kiwi library is well tested and widely used it was simpler to provide a LuaJIT FFI wrapper. There is also a Lua C API binding with support for 5.1 through 5.4.
|
Since the C++ Kiwi library is well tested and widely used it was simpler to provide a LuaJIT FFI wrapper and use that.
|
||||||
This package has no dependencies other than a supported C++14 compiler to compile the included Kiwi library and a small C wrapper.
|
This package has no dependencies other than a C++14 toolchain to compile the included Kiwi library and a small C wrapper.
|
||||||
|
|
||||||
The Lua API has a pure Lua expression builder. There is of course some overhead to this, however in most cases expression building is infrequent and the underlying structures can be reused.
|
The Lua API has a pure Lua expression builder. There is of course some overhead to this, however in most cases expression building is infrequent and the underlying structures can be reused.
|
||||||
|
|
||||||
|
|||||||
2
build.bat
Normal file
2
build.bat
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
cl /nologo /O2 /W4 /wd4200 /c /D_CRT_SECURE_NO_DEPRECATE /I "C:\Program Files\luarocks\include" /EHs /I kiwi luakiwi\luakiwi.cpp
|
||||||
|
link /DLL /out:ckiwi.dll /def:luakiwi.def /LIBPATH:"C:\Program Files\luarocks\lib" luakiwi.obj lua54.lib
|
||||||
356
ckiwi/ckiwi.cpp
356
ckiwi/ckiwi.cpp
@@ -2,22 +2,102 @@
|
|||||||
|
|
||||||
#include <kiwi/kiwi.h>
|
#include <kiwi/kiwi.h>
|
||||||
|
|
||||||
#include <climits>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(LJKIWI_NO_BUILTIN)
|
using namespace kiwi;
|
||||||
#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 {
|
namespace {
|
||||||
|
|
||||||
using namespace kiwi;
|
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) {
|
const KiwiErr* new_error(const KiwiErr* base, const std::exception& ex) {
|
||||||
if (!std::strcmp(ex.what(), base->message))
|
if (!std::strcmp(ex.what(), base->message))
|
||||||
@@ -51,7 +131,7 @@ static const constexpr KiwiErr kKiwiErrNullObjectArg1 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
const KiwiErr* wrap_err(F&& f) {
|
inline const KiwiErr* wrap_err(F&& f) {
|
||||||
try {
|
try {
|
||||||
f();
|
f();
|
||||||
} catch (const UnsatisfiableConstraint& ex) {
|
} catch (const UnsatisfiableConstraint& ex) {
|
||||||
@@ -113,102 +193,78 @@ const KiwiErr* wrap_err(F&& f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename P, typename R, typename F>
|
template<typename P, typename R, typename F>
|
||||||
const KiwiErr* wrap_err(P self, F&& f) {
|
inline const KiwiErr* wrap_err(P ptr, F&& f) {
|
||||||
if (lk_unlikely(!self)) {
|
if (!ptr) {
|
||||||
return &kKiwiErrNullObjectArg0;
|
return &kKiwiErrNullObjectArg0;
|
||||||
}
|
}
|
||||||
return wrap_err([&]() { f(self->solver); });
|
return wrap_err([&]() { f(ptr); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename P, typename R, typename F>
|
template<typename P, typename R, typename F>
|
||||||
const KiwiErr* wrap_err(P* self, R* item, F&& f) {
|
inline const KiwiErr* wrap_err(P ptr, R ref, F&& f) {
|
||||||
if (lk_unlikely(!self)) {
|
if (!ptr) {
|
||||||
return &kKiwiErrNullObjectArg0;
|
return &kKiwiErrNullObjectArg0;
|
||||||
} else if (lk_unlikely(!item)) {
|
} else if (!ref) {
|
||||||
return &kKiwiErrNullObjectArg1;
|
return &kKiwiErrNullObjectArg1;
|
||||||
}
|
}
|
||||||
return wrap_err([&]() { f(self->solver, item); });
|
return wrap_err([&]() { f(ptr, ref); });
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
|
||||||
T* make_unmanaged(Args... args) {
|
|
||||||
auto* o = new T(std::forward<Args>(args)...);
|
|
||||||
o->m_refcount = 1;
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
void release_unmanaged(T* p) {
|
|
||||||
if (lk_likely(p)) {
|
|
||||||
if (--p->m_refcount == 0)
|
|
||||||
delete p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
T* retain_unmanaged(T* p) {
|
|
||||||
if (lk_likely(p))
|
|
||||||
p->m_refcount++;
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
KiwiVar* kiwi_var_construct(const char* name) {
|
KiwiVarRef kiwi_var_new(const char* name) {
|
||||||
return make_unmanaged<VariableData>(lk_likely(name) ? name : "");
|
return make_var_cref(name ? name : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_var_release(KiwiVar* var) {
|
void kiwi_var_del(KiwiVarRef var) {
|
||||||
release_unmanaged(var);
|
VariableRef(var).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_var_retain(KiwiVar* var) {
|
KiwiVarRef kiwi_var_clone(KiwiVarRef var) {
|
||||||
retain_unmanaged(var);
|
return VariableRef(var).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* kiwi_var_name(const KiwiVar* var) {
|
const char* kiwi_var_name(KiwiVarRef var) {
|
||||||
return lk_likely(var) ? var->name().c_str() : "(<null>)";
|
const VariableRef self(var);
|
||||||
|
return self ? self->name().c_str() : "(<null>)";
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_var_set_name(KiwiVar* var, const char* name) {
|
void kiwi_var_set_name(KiwiVarRef var, const char* name) {
|
||||||
if (lk_likely(var && name))
|
VariableRef self(var);
|
||||||
var->setName(name);
|
if (self)
|
||||||
|
self->setName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
double kiwi_var_value(const KiwiVar* var) {
|
double kiwi_var_value(KiwiVarRef var) {
|
||||||
return lk_likely(var) ? var->value() : std::numeric_limits<double>::quiet_NaN();
|
const VariableRef self(var);
|
||||||
|
return self ? self->value() : std::numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_var_set_value(KiwiVar* var, double value) {
|
void kiwi_var_set_value(KiwiVarRef var, double value) {
|
||||||
if (lk_likely(var))
|
VariableRef self(var);
|
||||||
var->setValue(value);
|
if (self)
|
||||||
|
self->setValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_expression_retain(KiwiExpression* expr) {
|
bool kiwi_var_eq(KiwiVarRef var, KiwiVarRef other) {
|
||||||
if (lk_unlikely(!expr))
|
ConstVariableRef self(var); // const defect in upstream
|
||||||
return;
|
const VariableRef other_ref(other);
|
||||||
for (auto* t = expr->terms_; t != expr->terms_ + expr->term_count; ++t) {
|
|
||||||
retain_unmanaged(t->var);
|
return self && other_ref && self->equals(other_ref);
|
||||||
}
|
|
||||||
expr->owner = expr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_expression_destroy(KiwiExpression* expr) {
|
void kiwi_expression_del_vars(KiwiExpression* expr) {
|
||||||
if (lk_unlikely(!expr || !expr->owner))
|
if (!expr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (expr->owner == expr) {
|
for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) {
|
||||||
for (auto* t = expr->terms_; t != expr->terms_ + expr->term_count; ++t) {
|
VariableRef(t->var).release();
|
||||||
release_unmanaged(t->var);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
release_unmanaged(static_cast<ConstraintData*>(expr->owner));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
KiwiConstraint* kiwi_constraint_construct(
|
KiwiConstraintRef kiwi_constraint_new(
|
||||||
const KiwiExpression* lhs,
|
const KiwiExpression* lhs,
|
||||||
const KiwiExpression* rhs,
|
const KiwiExpression* rhs,
|
||||||
enum KiwiRelOp op,
|
enum KiwiRelOp op,
|
||||||
@@ -219,73 +275,72 @@ KiwiConstraint* kiwi_constraint_construct(
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<Term> terms;
|
std::vector<Term> terms;
|
||||||
terms.reserve(static_cast<decltype(terms)::size_type>(
|
terms.reserve((lhs ? lhs->term_count : 0) + (rhs ? rhs->term_count : 0));
|
||||||
(lhs && lhs->term_count > 0 ? lhs->term_count : 0)
|
|
||||||
+ (rhs && rhs->term_count > 0 ? rhs->term_count : 0)
|
|
||||||
));
|
|
||||||
|
|
||||||
if (lhs) {
|
if (lhs) {
|
||||||
for (int i = 0; i < lhs->term_count; ++i) {
|
for (auto* t = lhs->terms; t != lhs->terms + lhs->term_count; ++t) {
|
||||||
const auto& t = lhs->terms_[i];
|
ConstVariableRef var(t->var);
|
||||||
if (t.var)
|
if (var)
|
||||||
terms.emplace_back(Variable(t.var), t.coefficient);
|
terms.emplace_back(var.cref(), t->coefficient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (rhs) {
|
if (rhs) {
|
||||||
for (int i = 0; i < rhs->term_count; ++i) {
|
for (auto* t = rhs->terms; t != rhs->terms + rhs->term_count; ++t) {
|
||||||
const auto& t = rhs->terms_[i];
|
ConstVariableRef var(t->var);
|
||||||
if (t.var)
|
if (var)
|
||||||
terms.emplace_back(Variable(t.var), -t.coefficient);
|
terms.emplace_back(var.cref(), -t->coefficient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return make_unmanaged<ConstraintData>(
|
return make_constraint_cref(
|
||||||
Expression(std::move(terms), (lhs ? lhs->constant : 0.0) - (rhs ? rhs->constant : 0.0)),
|
Expression(std::move(terms), (lhs ? lhs->constant : 0.0) - (rhs ? rhs->constant : 0.0)),
|
||||||
static_cast<RelationalOperator>(op),
|
static_cast<RelationalOperator>(op),
|
||||||
strength
|
strength
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_constraint_release(KiwiConstraint* c) {
|
void kiwi_constraint_del(KiwiConstraintRef constraint) {
|
||||||
release_unmanaged(c);
|
ConstraintRef(constraint).release();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_constraint_retain(KiwiConstraint* c) {
|
KiwiConstraintRef kiwi_constraint_clone(KiwiConstraintRef constraint) {
|
||||||
retain_unmanaged(c);
|
return ConstraintRef(constraint).clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
double kiwi_constraint_strength(const KiwiConstraint* c) {
|
double kiwi_constraint_strength(KiwiConstraintRef constraint) {
|
||||||
return lk_likely(c) ? c->strength() : std::numeric_limits<double>::quiet_NaN();
|
const ConstraintRef self(constraint);
|
||||||
|
return self ? self->strength() : std::numeric_limits<double>::quiet_NaN();
|
||||||
}
|
}
|
||||||
|
|
||||||
enum KiwiRelOp kiwi_constraint_op(const KiwiConstraint* c) {
|
enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint) {
|
||||||
return lk_likely(c) ? static_cast<KiwiRelOp>(c->op()) : KiwiRelOp::KIWI_OP_EQ;
|
const ConstraintRef self(constraint);
|
||||||
|
return self ? static_cast<KiwiRelOp>(self->op()) : KiwiRelOp::KIWI_OP_EQ;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool kiwi_constraint_violated(const KiwiConstraint* c) {
|
bool kiwi_constraint_violated(KiwiConstraintRef constraint) {
|
||||||
return lk_likely(c) ? c->violated() : false;
|
const ConstraintRef self(constraint);
|
||||||
|
return self ? self->violated() : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int kiwi_constraint_expression(KiwiConstraint* c, KiwiExpression* out, int out_size) {
|
int kiwi_constraint_expression(KiwiConstraintRef constraint, KiwiExpression* out, int out_size) {
|
||||||
if (lk_unlikely(!c))
|
const ConstraintRef self(constraint);
|
||||||
|
if (!self)
|
||||||
return 0;
|
return 0;
|
||||||
|
const auto& expr = self->expression();
|
||||||
const auto& expr = c->expression();
|
|
||||||
const auto& terms = expr.terms();
|
const auto& terms = expr.terms();
|
||||||
int n = terms.size() < INT_MAX ? static_cast<int>(terms.size()) : INT_MAX;
|
const int n_terms = terms.size();
|
||||||
if (!out || out_size < n)
|
if (!out || out_size < n_terms)
|
||||||
return n;
|
return n_terms;
|
||||||
|
|
||||||
for (int i = 0; i < n; ++i) {
|
auto* p = out->terms;
|
||||||
const auto& t = terms[static_cast<std::size_t>(i)];
|
for (const auto& t : terms) {
|
||||||
out->terms_[i].var = const_cast<Variable&>(t.variable()).ptr();
|
*p = KiwiTerm {make_var_cref(t.variable()), t.coefficient()};
|
||||||
out->terms_[i].coefficient = t.coefficient();
|
++p;
|
||||||
}
|
}
|
||||||
|
out->term_count = p - out->terms;
|
||||||
out->constant = expr.constant();
|
out->constant = expr.constant();
|
||||||
out->term_count = n;
|
|
||||||
out->owner = retain_unmanaged(c);
|
|
||||||
|
|
||||||
return n;
|
return n_terms;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct KiwiSolver {
|
struct KiwiSolver {
|
||||||
@@ -293,78 +348,79 @@ struct KiwiSolver {
|
|||||||
Solver solver;
|
Solver solver;
|
||||||
};
|
};
|
||||||
|
|
||||||
KiwiSolver* kiwi_solver_construct(unsigned error_mask) {
|
KiwiSolver* kiwi_solver_new(unsigned error_mask) {
|
||||||
return new KiwiSolver {error_mask};
|
return new KiwiSolver {error_mask};
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_solver_destroy(KiwiSolver* s) {
|
void kiwi_solver_del(KiwiSolver* s) {
|
||||||
if (lk_likely(s))
|
if (s)
|
||||||
delete s;
|
delete s;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned kiwi_solver_get_error_mask(const KiwiSolver* s) {
|
const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, KiwiConstraintRef constraint) {
|
||||||
return lk_likely(s) ? s->error_mask : 0;
|
return wrap_err(s, ConstraintRef(constraint), [](auto* s, const auto c) {
|
||||||
}
|
s->solver.addConstraint(c);
|
||||||
|
|
||||||
void kiwi_solver_set_error_mask(KiwiSolver* s, unsigned mask) {
|
|
||||||
if (lk_likely(s))
|
|
||||||
s->error_mask = mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, KiwiConstraint* constraint) {
|
|
||||||
return wrap_err(s, constraint, [](auto&& s, auto&& c) { s.addConstraint(Constraint(c)); });
|
|
||||||
}
|
|
||||||
|
|
||||||
const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, KiwiConstraint* constraint) {
|
|
||||||
return wrap_err(s, constraint, [](auto&& s, auto&& c) { s.removeConstraint(Constraint(c)); });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool kiwi_solver_has_constraint(const KiwiSolver* s, KiwiConstraint* constraint) {
|
|
||||||
if (lk_unlikely(!s || !constraint))
|
|
||||||
return 0;
|
|
||||||
return s->solver.hasConstraint(Constraint(constraint));
|
|
||||||
}
|
|
||||||
|
|
||||||
const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, KiwiVar* var, double strength) {
|
|
||||||
return wrap_err(s, var, [strength](auto& s, auto&& v) {
|
|
||||||
s.addEditVariable(Variable(v), strength);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, KiwiVar* var) {
|
const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, KiwiConstraintRef constraint) {
|
||||||
return wrap_err(s, var, [](auto&& s, auto&& v) { s.removeEditVariable(Variable(v)); });
|
return wrap_err(s, ConstraintRef(constraint), [](auto* s, const auto c) {
|
||||||
|
s->solver.removeConstraint(c);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool kiwi_solver_has_edit_var(const KiwiSolver* s, KiwiVar* var) {
|
bool kiwi_solver_has_constraint(const KiwiSolver* s, KiwiConstraintRef constraint) {
|
||||||
if (lk_unlikely(!s || !var))
|
ConstraintRef c(constraint);
|
||||||
|
if (!s || !c)
|
||||||
return 0;
|
return 0;
|
||||||
return s->solver.hasEditVariable(Variable(var));
|
return s->solver.hasConstraint(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* s, KiwiVar* var, double value) {
|
const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, KiwiVarRef var, double strength) {
|
||||||
return wrap_err(s, var, [value](auto&& s, auto&& v) { s.suggestValue(Variable(v), value); });
|
return wrap_err(s, VariableRef(var), [strength](auto* s, const auto v) {
|
||||||
|
s->solver.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);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool kiwi_solver_has_edit_var(const KiwiSolver* s, KiwiVarRef var) {
|
||||||
|
VariableRef v(var);
|
||||||
|
if (!s || !v)
|
||||||
|
return 0;
|
||||||
|
return s->solver.hasEditVariable(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_solver_update_vars(KiwiSolver* s) {
|
void kiwi_solver_update_vars(KiwiSolver* s) {
|
||||||
if (lk_likely(s))
|
if (s)
|
||||||
s->solver.updateVariables();
|
s->solver.updateVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_solver_reset(KiwiSolver* s) {
|
void kiwi_solver_reset(KiwiSolver* s) {
|
||||||
if (lk_likely(s))
|
if (s)
|
||||||
s->solver.reset();
|
s->solver.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void kiwi_solver_dump(const KiwiSolver* s) {
|
void kiwi_solver_dump(const KiwiSolver* s) {
|
||||||
if (lk_likely(s))
|
if (s)
|
||||||
s->solver.dump();
|
s->solver.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
char* kiwi_solver_dumps(const KiwiSolver* s) {
|
char* kiwi_solver_dumps(const KiwiSolver* s) {
|
||||||
if (lk_unlikely(!s))
|
if (!s)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
const auto& str = s->solver.dumps();
|
const auto str = s->solver.dumps(); // upstream library defect
|
||||||
const auto buf_size = str.size() + 1;
|
const auto buf_size = str.size() + 1;
|
||||||
auto* buf = static_cast<char*>(std::malloc(buf_size));
|
auto* buf = static_cast<char*>(std::malloc(buf_size));
|
||||||
if (!buf)
|
if (!buf)
|
||||||
|
|||||||
116
ckiwi/ckiwi.h
116
ckiwi/ckiwi.h
@@ -1,35 +1,13 @@
|
|||||||
#ifndef LJKIWI_CKIWI_H_
|
#ifndef KIWI_CKIWI_H_
|
||||||
#define LJKIWI_CKIWI_H_
|
#define KIWI_CKIWI_H_
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || _MSC_VER >= 1900
|
|
||||||
#undef LJKIWI_USE_FAM_1
|
|
||||||
#else
|
|
||||||
#define LJKIWI_USE_FAM_1
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|
||||||
namespace kiwi {
|
|
||||||
class VariableData;
|
|
||||||
class ConstraintData;
|
|
||||||
} // namespace kiwi
|
|
||||||
|
|
||||||
typedef kiwi::VariableData KiwiVar;
|
|
||||||
typedef kiwi::ConstraintData KiwiConstraint;
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
#else
|
#else
|
||||||
typedef struct KiwiVar KiwiVar;
|
#include <stdbool.h>
|
||||||
typedef struct KiwiConstraint KiwiConstraint;
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined __GNUC__ && (!defined _WIN32 || defined __CYGWIN__)
|
#define KIWI_REF_ISNULL(ref) ((ref).impl_ == NULL)
|
||||||
#define LJKIWI_EXP __attribute__((visibility("default")))
|
|
||||||
#elif defined _WIN32
|
|
||||||
#define LJKIWI_EXP __declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// LuaJIT start
|
// LuaJIT start
|
||||||
enum KiwiErrKind {
|
enum KiwiErrKind {
|
||||||
@@ -48,24 +26,18 @@ enum KiwiErrKind {
|
|||||||
|
|
||||||
enum KiwiRelOp { KIWI_OP_LE, KIWI_OP_GE, KIWI_OP_EQ };
|
enum KiwiRelOp { KIWI_OP_LE, KIWI_OP_GE, KIWI_OP_EQ };
|
||||||
|
|
||||||
|
typedef struct KiwiVarRefType* KiwiVarRef;
|
||||||
|
typedef struct KiwiConstraintRefType* KiwiConstraintRef;
|
||||||
|
|
||||||
typedef struct KiwiTerm {
|
typedef struct KiwiTerm {
|
||||||
KiwiVar* var;
|
KiwiVarRef var;
|
||||||
double coefficient;
|
double coefficient;
|
||||||
} KiwiTerm;
|
} KiwiTerm;
|
||||||
|
|
||||||
typedef struct KiwiExpression {
|
typedef struct KiwiExpression {
|
||||||
double constant;
|
double constant;
|
||||||
int term_count;
|
int term_count;
|
||||||
void* owner;
|
KiwiTerm terms[1]; // LuaJIT: struct KiwiTerm terms_[?];
|
||||||
|
|
||||||
#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;
|
} KiwiExpression;
|
||||||
|
|
||||||
typedef struct KiwiErr {
|
typedef struct KiwiErr {
|
||||||
@@ -74,58 +46,56 @@ typedef struct KiwiErr {
|
|||||||
bool must_free;
|
bool must_free;
|
||||||
} KiwiErr;
|
} KiwiErr;
|
||||||
|
|
||||||
struct KiwiSolver;
|
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);
|
||||||
|
|
||||||
LJKIWI_EXP KiwiVar* kiwi_var_construct(const char* name);
|
const char* kiwi_var_name(KiwiVarRef var);
|
||||||
LJKIWI_EXP void kiwi_var_release(KiwiVar* var);
|
void kiwi_var_set_name(KiwiVarRef var, const char* name);
|
||||||
LJKIWI_EXP void kiwi_var_retain(KiwiVar* var);
|
double kiwi_var_value(KiwiVarRef var);
|
||||||
|
void kiwi_var_set_value(KiwiVarRef var, double value);
|
||||||
|
bool kiwi_var_eq(KiwiVarRef var, KiwiVarRef other);
|
||||||
|
|
||||||
LJKIWI_EXP const char* kiwi_var_name(const KiwiVar* var);
|
void kiwi_expression_del_vars(KiwiExpression* expr);
|
||||||
LJKIWI_EXP void kiwi_var_set_name(KiwiVar* var, const char* name);
|
|
||||||
LJKIWI_EXP double kiwi_var_value(const KiwiVar* var);
|
|
||||||
LJKIWI_EXP void kiwi_var_set_value(KiwiVar* var, double value);
|
|
||||||
|
|
||||||
LJKIWI_EXP void kiwi_expression_retain(KiwiExpression* expr);
|
KiwiConstraintRef kiwi_constraint_new(
|
||||||
LJKIWI_EXP void kiwi_expression_destroy(KiwiExpression* expr);
|
|
||||||
|
|
||||||
LJKIWI_EXP KiwiConstraint* kiwi_constraint_construct(
|
|
||||||
const KiwiExpression* lhs,
|
const KiwiExpression* lhs,
|
||||||
const KiwiExpression* rhs,
|
const KiwiExpression* rhs,
|
||||||
enum KiwiRelOp op,
|
enum KiwiRelOp op,
|
||||||
double strength
|
double strength
|
||||||
);
|
);
|
||||||
LJKIWI_EXP void kiwi_constraint_release(KiwiConstraint* c);
|
void kiwi_constraint_del(KiwiConstraintRef constraint);
|
||||||
LJKIWI_EXP void kiwi_constraint_retain(KiwiConstraint* c);
|
KiwiConstraintRef kiwi_constraint_clone(KiwiConstraintRef constraint);
|
||||||
|
|
||||||
LJKIWI_EXP double kiwi_constraint_strength(const KiwiConstraint* c);
|
double kiwi_constraint_strength(KiwiConstraintRef constraint);
|
||||||
LJKIWI_EXP enum KiwiRelOp kiwi_constraint_op(const KiwiConstraint* c);
|
enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint);
|
||||||
LJKIWI_EXP bool kiwi_constraint_violated(const KiwiConstraint* c);
|
bool kiwi_constraint_violated(KiwiConstraintRef constraint);
|
||||||
LJKIWI_EXP int kiwi_constraint_expression(KiwiConstraint* c, KiwiExpression* out, int out_size);
|
int kiwi_constraint_expression(KiwiConstraintRef constraint, KiwiExpression* out, int out_size);
|
||||||
|
|
||||||
LJKIWI_EXP KiwiSolver* kiwi_solver_construct(unsigned error_mask);
|
KiwiSolver* kiwi_solver_new(unsigned error_mask);
|
||||||
LJKIWI_EXP void kiwi_solver_destroy(KiwiSolver* s);
|
void kiwi_solver_del(KiwiSolver* s);
|
||||||
LJKIWI_EXP unsigned kiwi_solver_get_error_mask(const KiwiSolver* s);
|
|
||||||
LJKIWI_EXP 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);
|
||||||
|
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);
|
||||||
|
|
||||||
LJKIWI_EXP const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* s, KiwiConstraint* constraint);
|
|
||||||
LJKIWI_EXP const KiwiErr*
|
|
||||||
kiwi_solver_remove_constraint(KiwiSolver* s, KiwiConstraint* constraint);
|
|
||||||
LJKIWI_EXP bool kiwi_solver_has_constraint(const KiwiSolver* s, KiwiConstraint* constraint);
|
|
||||||
LJKIWI_EXP const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, KiwiVar* var, double strength);
|
|
||||||
LJKIWI_EXP const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, KiwiVar* var);
|
|
||||||
LJKIWI_EXP bool kiwi_solver_has_edit_var(const KiwiSolver* s, KiwiVar* var);
|
|
||||||
LJKIWI_EXP const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* s, KiwiVar* var, double value);
|
|
||||||
LJKIWI_EXP void kiwi_solver_update_vars(KiwiSolver* sp);
|
|
||||||
LJKIWI_EXP void kiwi_solver_reset(KiwiSolver* sp);
|
|
||||||
LJKIWI_EXP void kiwi_solver_dump(const KiwiSolver* sp);
|
|
||||||
LJKIWI_EXP char* kiwi_solver_dumps(const KiwiSolver* sp);
|
|
||||||
// LuaJIT end
|
// LuaJIT end
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Local Variables:
|
// Local Variables:
|
||||||
// mode: c++
|
// mode: c++
|
||||||
// End:
|
// End:
|
||||||
#endif // LJKIWI_CKIWI_H_
|
#endif // KIWI_CKIWI_H_
|
||||||
|
|||||||
@@ -21,12 +21,8 @@ dependencies = {
|
|||||||
build = {
|
build = {
|
||||||
type = "make",
|
type = "make",
|
||||||
build_variables = {
|
build_variables = {
|
||||||
LUAROCKS = "1",
|
|
||||||
LUA = "$(LUA)",
|
|
||||||
CFLAGS = "$(CFLAGS)",
|
CFLAGS = "$(CFLAGS)",
|
||||||
LUA_INCDIR = "$(LUA_INCDIR)",
|
LUA_INCDIR = "$(LUA_INCDIR)",
|
||||||
LUA_LIBDIR = "$(LUA_LIBDIR)",
|
|
||||||
LUALIB = "$(LUALIB)",
|
|
||||||
LIBFLAG = "$(LIBFLAG)",
|
LIBFLAG = "$(LIBFLAG)",
|
||||||
LIB_EXT = "$(LIB_EXTENSION)",
|
LIB_EXT = "$(LIB_EXTENSION)",
|
||||||
OBJ_EXT = "$(OBJ_EXTENSION)",
|
OBJ_EXT = "$(OBJ_EXTENSION)",
|
||||||
223
kiwi.lua
223
kiwi.lua
@@ -4,29 +4,21 @@ local ffi
|
|||||||
do
|
do
|
||||||
local ffi_loader = package.preload["ffi"]
|
local ffi_loader = package.preload["ffi"]
|
||||||
if ffi_loader == nil then
|
if ffi_loader == nil then
|
||||||
return require("ljkiwi")
|
return require("ckiwi")
|
||||||
end
|
end
|
||||||
ffi = ffi_loader() --[[@as ffilib]]
|
ffi = ffi_loader() --[[@as ffilib]]
|
||||||
end
|
end
|
||||||
|
|
||||||
local kiwi = {}
|
local kiwi = {}
|
||||||
|
|
||||||
local ljkiwi
|
local ckiwi
|
||||||
do
|
do
|
||||||
local cpath, err = package.searchpath("ljkiwi", package.cpath)
|
local cpath, err = package.searchpath("ckiwi", package.cpath)
|
||||||
if cpath == nil then
|
if cpath == nil then
|
||||||
error("kiwi dynamic library 'ljkiwi' not found\n" .. err)
|
error("kiwi dynamic library 'ckiwi' not found\n" .. err)
|
||||||
end
|
end
|
||||||
ljkiwi = ffi.load(cpath)
|
ckiwi = ffi.load(cpath)
|
||||||
end
|
end
|
||||||
kiwi.ljkiwi = ljkiwi
|
|
||||||
|
|
||||||
ffi.cdef([[
|
|
||||||
void free(void *);
|
|
||||||
|
|
||||||
typedef struct KiwiVar KiwiVar;
|
|
||||||
typedef struct KiwiConstraint KiwiConstraint;
|
|
||||||
typedef struct KiwiSolver KiwiSolver;]])
|
|
||||||
|
|
||||||
ffi.cdef([[
|
ffi.cdef([[
|
||||||
enum KiwiErrKind {
|
enum KiwiErrKind {
|
||||||
@@ -45,16 +37,17 @@ enum KiwiErrKind {
|
|||||||
|
|
||||||
enum KiwiRelOp { LE, GE, EQ };
|
enum KiwiRelOp { LE, GE, EQ };
|
||||||
|
|
||||||
|
typedef struct KiwiVarRefType* KiwiVarRef;
|
||||||
|
typedef struct KiwiConstraintRefType* KiwiConstraintRef;
|
||||||
|
|
||||||
typedef struct KiwiTerm {
|
typedef struct KiwiTerm {
|
||||||
KiwiVar* var;
|
KiwiVarRef var;
|
||||||
double coefficient;
|
double coefficient;
|
||||||
} KiwiTerm;
|
} KiwiTerm;
|
||||||
|
|
||||||
typedef struct KiwiExpression {
|
typedef struct KiwiExpression {
|
||||||
double constant;
|
double constant;
|
||||||
int term_count;
|
int term_count;
|
||||||
void* owner;
|
|
||||||
|
|
||||||
KiwiTerm terms_[?];
|
KiwiTerm terms_[?];
|
||||||
} KiwiExpression;
|
} KiwiExpression;
|
||||||
|
|
||||||
@@ -64,50 +57,49 @@ typedef struct KiwiErr {
|
|||||||
bool must_free;
|
bool must_free;
|
||||||
} KiwiErr;
|
} KiwiErr;
|
||||||
|
|
||||||
struct KiwiSolver;
|
typedef struct KiwiSolver { unsigned error_mask_; } KiwiSolver;
|
||||||
|
|
||||||
KiwiVar* kiwi_var_construct(const char* name);
|
KiwiVarRef kiwi_var_new(const char* name);
|
||||||
void kiwi_var_release(KiwiVar* var);
|
void kiwi_var_del(KiwiVarRef var);
|
||||||
void kiwi_var_retain(KiwiVar* var);
|
KiwiVarRef kiwi_var_clone(KiwiVarRef var);
|
||||||
|
|
||||||
const char* kiwi_var_name(const KiwiVar* var);
|
const char* kiwi_var_name(KiwiVarRef var);
|
||||||
void kiwi_var_set_name(KiwiVar* var, const char* name);
|
void kiwi_var_set_name(KiwiVarRef var, const char* name);
|
||||||
double kiwi_var_value(const KiwiVar* var);
|
double kiwi_var_value(KiwiVarRef var);
|
||||||
void kiwi_var_set_value(KiwiVar* var, double value);
|
void kiwi_var_set_value(KiwiVarRef var, double value);
|
||||||
|
bool kiwi_var_eq(KiwiVarRef var, KiwiVarRef other);
|
||||||
|
|
||||||
void kiwi_expression_retain(KiwiExpression* expr);
|
void kiwi_expression_del_vars(KiwiExpression* expr);
|
||||||
void kiwi_expression_destroy(KiwiExpression* expr);
|
|
||||||
|
|
||||||
KiwiConstraint* kiwi_constraint_construct(
|
KiwiConstraintRef kiwi_constraint_new(
|
||||||
const KiwiExpression* lhs,
|
const KiwiExpression* lhs,
|
||||||
const KiwiExpression* rhs,
|
const KiwiExpression* rhs,
|
||||||
enum KiwiRelOp op,
|
enum KiwiRelOp op,
|
||||||
double strength
|
double strength
|
||||||
);
|
);
|
||||||
void kiwi_constraint_release(KiwiConstraint* c);
|
void kiwi_constraint_del(KiwiConstraintRef constraint);
|
||||||
void kiwi_constraint_retain(KiwiConstraint* c);
|
|
||||||
|
|
||||||
double kiwi_constraint_strength(const KiwiConstraint* c);
|
double kiwi_constraint_strength(KiwiConstraintRef constraint);
|
||||||
enum KiwiRelOp kiwi_constraint_op(const KiwiConstraint* c);
|
enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint);
|
||||||
bool kiwi_constraint_violated(const KiwiConstraint* c);
|
bool kiwi_constraint_violated(KiwiConstraintRef constraint);
|
||||||
int kiwi_constraint_expression(KiwiConstraint* c, KiwiExpression* out, int out_size);
|
int kiwi_constraint_expression(KiwiConstraintRef constraint, KiwiExpression* out, int out_size);
|
||||||
|
|
||||||
KiwiSolver* kiwi_solver_construct(unsigned error_mask);
|
KiwiSolver* kiwi_solver_new(unsigned error_mask);
|
||||||
void kiwi_solver_destroy(KiwiSolver* s);
|
void kiwi_solver_del(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* s, KiwiConstraint* constraint);
|
const KiwiErr* kiwi_solver_add_constraint(KiwiSolver* sp, KiwiConstraintRef constraint);
|
||||||
const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* s, KiwiConstraint* constraint);
|
const KiwiErr* kiwi_solver_remove_constraint(KiwiSolver* sp, KiwiConstraintRef constraint);
|
||||||
bool kiwi_solver_has_constraint(const KiwiSolver* s, KiwiConstraint* constraint);
|
bool kiwi_solver_has_constraint(const KiwiSolver* sp, KiwiConstraintRef constraint);
|
||||||
const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* s, KiwiVar* var, double strength);
|
const KiwiErr* kiwi_solver_add_edit_var(KiwiSolver* sp, KiwiVarRef var, double strength);
|
||||||
const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* s, KiwiVar* var);
|
const KiwiErr* kiwi_solver_remove_edit_var(KiwiSolver* sp, KiwiVarRef var);
|
||||||
bool kiwi_solver_has_edit_var(const KiwiSolver* s, KiwiVar* var);
|
bool kiwi_solver_has_edit_var(const KiwiSolver* sp, KiwiVarRef var);
|
||||||
const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* s, KiwiVar* var, double value);
|
const KiwiErr* kiwi_solver_suggest_value(KiwiSolver* sp, KiwiVarRef var, double value);
|
||||||
void kiwi_solver_update_vars(KiwiSolver* sp);
|
void kiwi_solver_update_vars(KiwiSolver* sp);
|
||||||
void kiwi_solver_reset(KiwiSolver* sp);
|
void kiwi_solver_reset(KiwiSolver* sp);
|
||||||
void kiwi_solver_dump(const KiwiSolver* sp);
|
void kiwi_solver_dump(const KiwiSolver* sp);
|
||||||
char* kiwi_solver_dumps(const KiwiSolver* sp);
|
char* kiwi_solver_dumps(const KiwiSolver* sp);
|
||||||
|
|
||||||
|
void free(void *);
|
||||||
]])
|
]])
|
||||||
|
|
||||||
local strformat = string.format
|
local strformat = string.format
|
||||||
@@ -167,7 +159,7 @@ do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local Var = ffi.typeof("struct KiwiVar") --[[@as kiwi.Var]]
|
local Var = ffi.typeof("struct KiwiVarRefType") --[[@as kiwi.Var]]
|
||||||
kiwi.Var = Var
|
kiwi.Var = Var
|
||||||
|
|
||||||
function kiwi.is_var(o)
|
function kiwi.is_var(o)
|
||||||
@@ -188,7 +180,7 @@ function kiwi.is_expression(o)
|
|||||||
return ffi_istype(Expression, o)
|
return ffi_istype(Expression, o)
|
||||||
end
|
end
|
||||||
|
|
||||||
local Constraint = ffi.typeof("struct KiwiConstraint") --[[@as kiwi.Constraint]]
|
local Constraint = ffi.typeof("struct KiwiConstraintRefType") --[[@as kiwi.Constraint]]
|
||||||
kiwi.Constraint = Constraint
|
kiwi.Constraint = Constraint
|
||||||
|
|
||||||
function kiwi.is_constraint(o)
|
function kiwi.is_constraint(o)
|
||||||
@@ -200,19 +192,18 @@ end
|
|||||||
---@param coeff number?
|
---@param coeff number?
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function add_expr_term(expr, var, coeff)
|
local function add_expr_term(expr, var, coeff)
|
||||||
local ret = ffi_gc(ffi_new(Expression, expr.term_count + 1), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, expr.term_count + 1), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
for i = 0, expr.term_count - 1 do
|
for i = 0, expr.term_count - 1 do
|
||||||
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
||||||
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
dt.var = st.var
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
dt.coefficient = st.coefficient
|
dt.coefficient = st.coefficient
|
||||||
end
|
end
|
||||||
local dt = ret.terms_[expr.term_count]
|
local dt = ret.terms_[expr.term_count]
|
||||||
dt.var = var
|
dt.var = ckiwi.kiwi_var_clone(var)
|
||||||
dt.coefficient = coeff or 1.0
|
dt.coefficient = coeff or 1.0
|
||||||
ret.constant = expr.constant
|
ret.constant = expr.constant
|
||||||
ret.term_count = expr.term_count + 1
|
ret.term_count = expr.term_count + 1
|
||||||
ljkiwi.kiwi_expression_retain(ret)
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -221,13 +212,12 @@ end
|
|||||||
---@param coeff number?
|
---@param coeff number?
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function new_expr_one(constant, var, coeff)
|
local function new_expr_one(constant, var, coeff)
|
||||||
local ret = ffi_gc(ffi_new(Expression, 1), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, 1), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
local dt = ret.terms_[0]
|
local dt = ret.terms_[0]
|
||||||
dt.var = var
|
dt.var = ckiwi.kiwi_var_clone(var)
|
||||||
dt.coefficient = coeff or 1.0
|
dt.coefficient = coeff or 1.0
|
||||||
ret.constant = constant
|
ret.constant = constant
|
||||||
ret.term_count = 1
|
ret.term_count = 1
|
||||||
ljkiwi.kiwi_expression_retain(ret)
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -238,16 +228,15 @@ end
|
|||||||
---@param coeff2 number?
|
---@param coeff2 number?
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function new_expr_pair(constant, var1, var2, coeff1, coeff2)
|
local function new_expr_pair(constant, var1, var2, coeff1, coeff2)
|
||||||
local ret = ffi_gc(ffi_new(Expression, 2), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, 2), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
local dt = ret.terms_[0]
|
local dt = ret.terms_[0]
|
||||||
dt.var = var1
|
dt.var = ckiwi.kiwi_var_clone(var1)
|
||||||
dt.coefficient = coeff1 or 1.0
|
dt.coefficient = coeff1 or 1.0
|
||||||
dt = ret.terms_[1]
|
dt = ret.terms_[1]
|
||||||
dt.var = var2
|
dt.var = ckiwi.kiwi_var_clone(var2)
|
||||||
dt.coefficient = coeff2 or 1.0
|
dt.coefficient = coeff2 or 1.0
|
||||||
ret.constant = constant
|
ret.constant = constant
|
||||||
ret.term_count = 2
|
ret.term_count = 2
|
||||||
ljkiwi.kiwi_expression_retain(ret)
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -322,10 +311,7 @@ local function rel(lhs, rhs, op, strength)
|
|||||||
op_error(lhs, rhs, OP_NAMES[op])
|
op_error(lhs, rhs, OP_NAMES[op])
|
||||||
end
|
end
|
||||||
|
|
||||||
return ffi_gc(
|
return ffi_gc(ckiwi.kiwi_constraint_new(el, er, op, strength or REQUIRED), ckiwi.kiwi_constraint_del) --[[@as kiwi.Constraint]]
|
||||||
ljkiwi.kiwi_constraint_construct(el, er, op, strength or REQUIRED),
|
|
||||||
ljkiwi.kiwi_constraint_release
|
|
||||||
) --[[@as kiwi.Constraint]]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Define a constraint with expressions as `a <= b`.
|
--- Define a constraint with expressions as `a <= b`.
|
||||||
@@ -371,22 +357,22 @@ do
|
|||||||
|
|
||||||
--- Change the name of the variable.
|
--- Change the name of the variable.
|
||||||
---@type fun(self: kiwi.Var, name: string)
|
---@type fun(self: kiwi.Var, name: string)
|
||||||
set_name = ljkiwi.kiwi_var_set_name,
|
set_name = ckiwi.kiwi_var_set_name,
|
||||||
|
|
||||||
--- Get the current value of the variable.
|
--- Get the current value of the variable.
|
||||||
---@type fun(self: kiwi.Var): number
|
---@type fun(self: kiwi.Var): number
|
||||||
value = ljkiwi.kiwi_var_value,
|
value = ckiwi.kiwi_var_value,
|
||||||
|
|
||||||
--- Set the value of the variable.
|
--- Set the value of the variable.
|
||||||
---@type fun(self: kiwi.Var, value: number)
|
---@type fun(self: kiwi.Var, value: number)
|
||||||
set = ljkiwi.kiwi_var_set_value,
|
set = ckiwi.kiwi_var_set_value,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Get the name of the variable.
|
--- Get the name of the variable.
|
||||||
---@return string
|
---@return string
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function Var_cls:name()
|
function Var_cls:name()
|
||||||
return ffi_string(ljkiwi.kiwi_var_name(self))
|
return ffi_string(ckiwi.kiwi_var_name(self))
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Create a term from this variable.
|
--- Create a term from this variable.
|
||||||
@@ -411,7 +397,7 @@ do
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Var_mt:__new(name)
|
function Var_mt:__new(name)
|
||||||
return ffi_gc(ljkiwi.kiwi_var_construct(name), ljkiwi.kiwi_var_release)
|
return ffi_gc(ckiwi.kiwi_var_new(name), ckiwi.kiwi_var_del)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Var_mt.__mul(a, b)
|
function Var_mt.__mul(a, b)
|
||||||
@@ -496,15 +482,11 @@ do
|
|||||||
local Term_mt = { __index = Term_cls }
|
local Term_mt = { __index = Term_cls }
|
||||||
|
|
||||||
local function term_gc(term)
|
local function term_gc(term)
|
||||||
ljkiwi.kiwi_var_release(term.var)
|
ckiwi.kiwi_var_del(term.var)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Term_mt.__new(T, var, coefficient)
|
function Term_mt.__new(T, var, coefficient)
|
||||||
local t = ffi_gc(ffi_new(T), term_gc) --[[@as kiwi.Term]]
|
return ffi_gc(ffi_new(T, ckiwi.kiwi_var_clone(var), coefficient or 1.0), term_gc)
|
||||||
ljkiwi.kiwi_var_retain(var)
|
|
||||||
t.var = var
|
|
||||||
t.coefficient = coefficient or 1.0
|
|
||||||
return t
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Term_mt.__mul(a, b)
|
function Term_mt.__mul(a, b)
|
||||||
@@ -560,7 +542,6 @@ do
|
|||||||
---@class kiwi.Expression: ffi.cdata*
|
---@class kiwi.Expression: ffi.cdata*
|
||||||
---@overload fun(constant: number, ...: kiwi.Term): kiwi.Expression
|
---@overload fun(constant: number, ...: kiwi.Term): kiwi.Expression
|
||||||
---@field constant number
|
---@field constant number
|
||||||
---@field package owner ffi.cdata*
|
|
||||||
---@field package term_count number
|
---@field package term_count number
|
||||||
---@field package terms_ ffi.cdata*
|
---@field package terms_ ffi.cdata*
|
||||||
---@operator mul(number): kiwi.Expression
|
---@operator mul(number): kiwi.Expression
|
||||||
@@ -578,16 +559,15 @@ do
|
|||||||
---@param constant number
|
---@param constant number
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function mul_expr_coeff(expr, constant)
|
local function mul_expr_coeff(expr, constant)
|
||||||
local ret = ffi_gc(ffi_new(Expression, expr.term_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, expr.term_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
for i = 0, expr.term_count - 1 do
|
for i = 0, expr.term_count - 1 do
|
||||||
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
||||||
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
dt.var = st.var
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
dt.coefficient = st.coefficient * constant
|
dt.coefficient = st.coefficient * constant
|
||||||
end
|
end
|
||||||
ret.constant = expr.constant * constant
|
ret.constant = expr.constant * constant
|
||||||
ret.term_count = expr.term_count
|
ret.term_count = expr.term_count
|
||||||
ljkiwi.kiwi_expression_retain(ret)
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -597,23 +577,22 @@ do
|
|||||||
local function add_expr_expr(a, b)
|
local function add_expr_expr(a, b)
|
||||||
local a_count = a.term_count
|
local a_count = a.term_count
|
||||||
local b_count = b.term_count
|
local b_count = b.term_count
|
||||||
local ret = ffi_gc(ffi_new(Expression, a_count + b_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, a_count + b_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
|
|
||||||
for i = 0, a_count - 1 do
|
for i = 0, a_count - 1 do
|
||||||
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
local st = a.terms_[i] --[[@as kiwi.Term]]
|
local st = a.terms_[i] --[[@as kiwi.Term]]
|
||||||
dt.var = st.var
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
dt.coefficient = st.coefficient
|
dt.coefficient = st.coefficient
|
||||||
end
|
end
|
||||||
for i = 0, b_count - 1 do
|
for i = 0, b_count - 1 do
|
||||||
local dt = ret.terms_[a_count + i] --[[@as kiwi.Term]]
|
local dt = ret.terms_[a_count + i] --[[@as kiwi.Term]]
|
||||||
local st = b.terms_[i] --[[@as kiwi.Term]]
|
local st = b.terms_[i] --[[@as kiwi.Term]]
|
||||||
dt.var = st.var
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
dt.coefficient = st.coefficient
|
dt.coefficient = st.coefficient
|
||||||
end
|
end
|
||||||
ret.constant = a.constant + b.constant
|
ret.constant = a.constant + b.constant
|
||||||
ret.term_count = a_count + b_count
|
ret.term_count = a_count + b_count
|
||||||
ljkiwi.kiwi_expression_retain(ret)
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -621,17 +600,16 @@ do
|
|||||||
---@param constant number
|
---@param constant number
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
local function new_expr_constant(expr, constant)
|
local function new_expr_constant(expr, constant)
|
||||||
local ret = ffi_gc(ffi_new(Expression, expr.term_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
local ret = ffi_gc(ffi_new(Expression, expr.term_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
|
|
||||||
for i = 0, expr.term_count - 1 do
|
for i = 0, expr.term_count - 1 do
|
||||||
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
local dt = ret.terms_[i] --[[@as kiwi.Term]]
|
||||||
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
local st = expr.terms_[i] --[[@as kiwi.Term]]
|
||||||
dt.var = st.var
|
dt.var = ckiwi.kiwi_var_clone(st.var)
|
||||||
dt.coefficient = st.coefficient
|
dt.coefficient = st.coefficient
|
||||||
end
|
end
|
||||||
ret.constant = constant
|
ret.constant = constant
|
||||||
ret.term_count = expr.term_count
|
ret.term_count = expr.term_count
|
||||||
ljkiwi.kiwi_expression_retain(ret)
|
|
||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -667,18 +645,17 @@ do
|
|||||||
__index = Expression_cls,
|
__index = Expression_cls,
|
||||||
}
|
}
|
||||||
|
|
||||||
function Expression_mt:__new(constant, ...)
|
function Expression_mt.__new(T, constant, ...)
|
||||||
local term_count = select("#", ...)
|
local term_count = select("#", ...)
|
||||||
local e = ffi_gc(ffi_new(self, term_count), ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
local e = ffi_gc(ffi_new(T, term_count), ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
e.term_count = term_count
|
e.term_count = term_count
|
||||||
e.constant = constant
|
e.constant = constant
|
||||||
for i = 1, term_count do
|
for i = 1, term_count do
|
||||||
local t = select(i, ...)
|
local t = select(i, ...)
|
||||||
local dt = e.terms_[i - 1] --[[@as kiwi.Term]]
|
local dt = e.terms_[i - 1] --[[@as kiwi.Term]]
|
||||||
dt.var = t.var
|
dt.var = ckiwi.kiwi_var_clone(t.var)
|
||||||
dt.coefficient = t.coefficient
|
dt.coefficient = t.coefficient
|
||||||
end
|
end
|
||||||
ljkiwi.kiwi_expression_retain(e)
|
|
||||||
return e
|
return e
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -745,29 +722,29 @@ do
|
|||||||
local Constraint_cls = {
|
local Constraint_cls = {
|
||||||
--- The strength of the constraint.
|
--- The strength of the constraint.
|
||||||
---@type fun(self: kiwi.Constraint): number
|
---@type fun(self: kiwi.Constraint): number
|
||||||
strength = ljkiwi.kiwi_constraint_strength,
|
strength = ckiwi.kiwi_constraint_strength,
|
||||||
|
|
||||||
--- The relational operator of the constraint.
|
--- The relational operator of the constraint.
|
||||||
---@type fun(self: kiwi.Constraint): kiwi.RelOp
|
---@type fun(self: kiwi.Constraint): kiwi.RelOp
|
||||||
op = ljkiwi.kiwi_constraint_op,
|
op = ckiwi.kiwi_constraint_op,
|
||||||
|
|
||||||
--- Whether the constraint is violated in the current solution.
|
--- Whether the constraint is violated in the current solution.
|
||||||
---@type fun(self: kiwi.Constraint): boolean
|
---@type fun(self: kiwi.Constraint): boolean
|
||||||
violated = ljkiwi.kiwi_constraint_violated,
|
violated = ckiwi.kiwi_constraint_violated,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- The reduced expression defining the constraint.
|
--- The reduced expression defining the constraint.
|
||||||
---@return kiwi.Expression
|
---@return kiwi.Expression
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function Constraint_cls:expression()
|
function Constraint_cls:expression()
|
||||||
local SZ = 7
|
local SZ = 7 -- 2**7 bytes on x64
|
||||||
local expr = ffi_new(Expression, SZ) --[[@as kiwi.Expression]]
|
local expr = ffi_new(Expression, SZ) --[[@as kiwi.Expression]]
|
||||||
local n = ljkiwi.kiwi_constraint_expression(self, expr, SZ)
|
local n = ckiwi.kiwi_constraint_expression(self, expr, SZ)
|
||||||
if n > SZ then
|
if n > SZ then
|
||||||
expr = ffi_new(Expression, n) --[[@as kiwi.Expression]]
|
expr = ffi_new(Expression, n) --[[@as kiwi.Expression]]
|
||||||
n = ljkiwi.kiwi_constraint_expression(self, expr, n)
|
n = ckiwi.kiwi_constraint_expression(self, expr, n)
|
||||||
end
|
end
|
||||||
return ffi_gc(expr, ljkiwi.kiwi_expression_destroy) --[[@as kiwi.Expression]]
|
return ffi_gc(expr, ckiwi.kiwi_expression_del_vars) --[[@as kiwi.Expression]]
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add the constraint to the solver.
|
--- Add the constraint to the solver.
|
||||||
@@ -797,8 +774,8 @@ do
|
|||||||
|
|
||||||
function Constraint_mt:__new(lhs, rhs, op, strength)
|
function Constraint_mt:__new(lhs, rhs, op, strength)
|
||||||
return ffi_gc(
|
return ffi_gc(
|
||||||
ljkiwi.kiwi_constraint_construct(lhs, rhs, op or "EQ", strength or REQUIRED),
|
ckiwi.kiwi_constraint_new(lhs, rhs, op or "EQ", strength or REQUIRED),
|
||||||
ljkiwi.kiwi_constraint_release
|
ckiwi.kiwi_constraint_del
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -846,8 +823,8 @@ do
|
|||||||
tmpexpr.term_count = 2
|
tmpexpr.term_count = 2
|
||||||
|
|
||||||
return ffi_gc(
|
return ffi_gc(
|
||||||
ljkiwi.kiwi_constraint_construct(tmpexpr, nil, op or "EQ", strength or REQUIRED),
|
ckiwi.kiwi_constraint_new(tmpexpr, nil, op or "EQ", strength or REQUIRED),
|
||||||
ljkiwi.kiwi_constraint_release
|
ckiwi.kiwi_constraint_del
|
||||||
) --[[@as kiwi.Constraint]]
|
) --[[@as kiwi.Constraint]]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -881,10 +858,9 @@ do
|
|||||||
local t = tmpexpr.terms_[0]
|
local t = tmpexpr.terms_[0]
|
||||||
t.var = var
|
t.var = var
|
||||||
t.coefficient = 1.0
|
t.coefficient = 1.0
|
||||||
|
|
||||||
return ffi_gc(
|
return ffi_gc(
|
||||||
ljkiwi.kiwi_constraint_construct(tmpexpr, nil, op or "EQ", strength or REQUIRED),
|
ckiwi.kiwi_constraint_new(tmpexpr, nil, op or "EQ", strength or REQUIRED),
|
||||||
ljkiwi.kiwi_constraint_release
|
ckiwi.kiwi_constraint_del
|
||||||
) --[[@as kiwi.Constraint]]
|
) --[[@as kiwi.Constraint]]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -971,7 +947,7 @@ do
|
|||||||
C.free(err)
|
C.free(err)
|
||||||
end
|
end
|
||||||
local errdata = new_error(kind, message, solver, item)
|
local errdata = new_error(kind, message, solver, item)
|
||||||
local error_mask = ljkiwi.kiwi_solver_get_error_mask(solver)
|
local error_mask = solver and solver.error_mask_ or 0
|
||||||
return item,
|
return item,
|
||||||
band(error_mask, lshift(1, kind --[[@as integer]])) == 0 and error(errdata)
|
band(error_mask, lshift(1, kind --[[@as integer]])) == 0 and error(errdata)
|
||||||
or errdata
|
or errdata
|
||||||
@@ -979,19 +955,20 @@ do
|
|||||||
return item
|
return item
|
||||||
end
|
end
|
||||||
---@class kiwi.Solver: ffi.cdata*
|
---@class kiwi.Solver: ffi.cdata*
|
||||||
|
---@field package error_mask_ integer
|
||||||
---@overload fun(error_mask: (integer|(kiwi.ErrKind|integer)[] )?): kiwi.Solver
|
---@overload fun(error_mask: (integer|(kiwi.ErrKind|integer)[] )?): kiwi.Solver
|
||||||
local Solver_cls = {
|
local Solver_cls = {
|
||||||
--- Test whether a constraint is in the solver.
|
--- Test whether a constraint is in the solver.
|
||||||
---@type fun(self: kiwi.Solver, constraint: kiwi.Constraint): boolean
|
---@type fun(self: kiwi.Solver, constraint: kiwi.Constraint): boolean
|
||||||
has_constraint = ljkiwi.kiwi_solver_has_constraint,
|
has_constraint = ckiwi.kiwi_solver_has_constraint,
|
||||||
|
|
||||||
--- Test whether an edit variable has been added to the solver.
|
--- Test whether an edit variable has been added to the solver.
|
||||||
---@type fun(self: kiwi.Solver, var: kiwi.Var): boolean
|
---@type fun(self: kiwi.Solver, var: kiwi.Var): boolean
|
||||||
has_edit_var = ljkiwi.kiwi_solver_has_edit_var,
|
has_edit_var = ckiwi.kiwi_solver_has_edit_var,
|
||||||
|
|
||||||
--- Update the values of the external solver variables.
|
--- Update the values of the external solver variables.
|
||||||
---@type fun(self: kiwi.Solver)
|
---@type fun(self: kiwi.Solver)
|
||||||
update_vars = ljkiwi.kiwi_solver_update_vars,
|
update_vars = ckiwi.kiwi_solver_update_vars,
|
||||||
|
|
||||||
--- Reset the solver to the empty starting conditions.
|
--- Reset the solver to the empty starting conditions.
|
||||||
---
|
---
|
||||||
@@ -1001,11 +978,11 @@ do
|
|||||||
--- when the entire system must change, since it can avoid unecessary
|
--- when the entire system must change, since it can avoid unecessary
|
||||||
--- heap (de)allocations.
|
--- heap (de)allocations.
|
||||||
---@type fun(self: kiwi.Solver)
|
---@type fun(self: kiwi.Solver)
|
||||||
reset = ljkiwi.kiwi_solver_reset,
|
reset = ckiwi.kiwi_solver_reset,
|
||||||
|
|
||||||
--- Dump a representation of the solver to stdout.
|
--- Dump a representation of the solver to stdout.
|
||||||
---@type fun(self: kiwi.Solver)
|
---@type fun(self: kiwi.Solver)
|
||||||
dump = ljkiwi.kiwi_solver_dump,
|
dump = ckiwi.kiwi_solver_dump,
|
||||||
}
|
}
|
||||||
|
|
||||||
--- Sets the error mask for the solver.
|
--- Sets the error mask for the solver.
|
||||||
@@ -1015,7 +992,7 @@ do
|
|||||||
if type(mask) == "table" then
|
if type(mask) == "table" then
|
||||||
mask = kiwi.error_mask(mask, invert)
|
mask = kiwi.error_mask(mask, invert)
|
||||||
end
|
end
|
||||||
ljkiwi.kiwi_solver_set_error_mask(self, mask)
|
self.error_mask_ = mask
|
||||||
end
|
end
|
||||||
|
|
||||||
---@generic T
|
---@generic T
|
||||||
@@ -1040,7 +1017,7 @@ do
|
|||||||
---@param constraint kiwi.Constraint
|
---@param constraint kiwi.Constraint
|
||||||
---@return kiwi.Constraint constraint, kiwi.Error?
|
---@return kiwi.Constraint constraint, kiwi.Error?
|
||||||
function Solver_cls:add_constraint(constraint)
|
function Solver_cls:add_constraint(constraint)
|
||||||
return try_solver(ljkiwi.kiwi_solver_add_constraint, self, constraint)
|
return try_solver(ckiwi.kiwi_solver_add_constraint, self, constraint)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add constraints to the solver.
|
--- Add constraints to the solver.
|
||||||
@@ -1050,7 +1027,7 @@ do
|
|||||||
---@param constraints kiwi.Constraint[]
|
---@param constraints kiwi.Constraint[]
|
||||||
---@return kiwi.Constraint[] constraints, kiwi.Error?
|
---@return kiwi.Constraint[] constraints, kiwi.Error?
|
||||||
function Solver_cls:add_constraints(constraints)
|
function Solver_cls:add_constraints(constraints)
|
||||||
return add_remove_items(self, constraints, ljkiwi.kiwi_solver_add_constraint)
|
return add_remove_items(self, constraints, ckiwi.kiwi_solver_add_constraint)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove a constraint from the solver.
|
--- Remove a constraint from the solver.
|
||||||
@@ -1059,7 +1036,7 @@ do
|
|||||||
---@param constraint kiwi.Constraint
|
---@param constraint kiwi.Constraint
|
||||||
---@return kiwi.Constraint constraint, kiwi.Error?
|
---@return kiwi.Constraint constraint, kiwi.Error?
|
||||||
function Solver_cls:remove_constraint(constraint)
|
function Solver_cls:remove_constraint(constraint)
|
||||||
return try_solver(ljkiwi.kiwi_solver_remove_constraint, self, constraint)
|
return try_solver(ckiwi.kiwi_solver_remove_constraint, self, constraint)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove constraints from the solver.
|
--- Remove constraints from the solver.
|
||||||
@@ -1068,7 +1045,7 @@ do
|
|||||||
---@param constraints kiwi.Constraint[]
|
---@param constraints kiwi.Constraint[]
|
||||||
---@return kiwi.Constraint[] constraints, kiwi.Error?
|
---@return kiwi.Constraint[] constraints, kiwi.Error?
|
||||||
function Solver_cls:remove_constraints(constraints)
|
function Solver_cls:remove_constraints(constraints)
|
||||||
return add_remove_items(self, constraints, ljkiwi.kiwi_solver_remove_constraint)
|
return add_remove_items(self, constraints, ckiwi.kiwi_solver_remove_constraint)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add an edit variables to the solver.
|
--- Add an edit variables to the solver.
|
||||||
@@ -1082,7 +1059,7 @@ do
|
|||||||
---@param strength number the strength of the edit variable (must be less than `Strength.REQUIRED`)
|
---@param strength number the strength of the edit variable (must be less than `Strength.REQUIRED`)
|
||||||
---@return kiwi.Var var, kiwi.Error?
|
---@return kiwi.Var var, kiwi.Error?
|
||||||
function Solver_cls:add_edit_var(var, strength)
|
function Solver_cls:add_edit_var(var, strength)
|
||||||
return try_solver(ljkiwi.kiwi_solver_add_edit_var, self, var, strength)
|
return try_solver(ckiwi.kiwi_solver_add_edit_var, self, var, strength)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Add edit variables to the solver.
|
--- Add edit variables to the solver.
|
||||||
@@ -1096,7 +1073,7 @@ do
|
|||||||
---@param strength number the strength of the edit variables (must be less than `Strength.REQUIRED`)
|
---@param strength number the strength of the edit variables (must be less than `Strength.REQUIRED`)
|
||||||
---@return kiwi.Var[] vars, kiwi.Error?
|
---@return kiwi.Var[] vars, kiwi.Error?
|
||||||
function Solver_cls:add_edit_vars(vars, strength)
|
function Solver_cls:add_edit_vars(vars, strength)
|
||||||
return add_remove_items(self, vars, ljkiwi.kiwi_solver_add_edit_var, strength)
|
return add_remove_items(self, vars, ckiwi.kiwi_solver_add_edit_var, strength)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Remove an edit variable from the solver.
|
--- Remove an edit variable from the solver.
|
||||||
@@ -1105,7 +1082,7 @@ do
|
|||||||
---@param var kiwi.Var the edit variable to remove
|
---@param var kiwi.Var the edit variable to remove
|
||||||
---@return kiwi.Var var, kiwi.Error?
|
---@return kiwi.Var var, kiwi.Error?
|
||||||
function Solver_cls:remove_edit_var(var)
|
function Solver_cls:remove_edit_var(var)
|
||||||
return try_solver(ljkiwi.kiwi_solver_remove_edit_var, self, var)
|
return try_solver(ckiwi.kiwi_solver_remove_edit_var, self, var)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Removes edit variables from the solver.
|
--- Removes edit variables from the solver.
|
||||||
@@ -1114,7 +1091,7 @@ do
|
|||||||
---@param vars kiwi.Var[] the edit variables to remove
|
---@param vars kiwi.Var[] the edit variables to remove
|
||||||
---@return kiwi.Var[] vars, kiwi.Error?
|
---@return kiwi.Var[] vars, kiwi.Error?
|
||||||
function Solver_cls:remove_edit_vars(vars)
|
function Solver_cls:remove_edit_vars(vars)
|
||||||
return add_remove_items(self, vars, ljkiwi.kiwi_solver_remove_edit_var)
|
return add_remove_items(self, vars, ckiwi.kiwi_solver_remove_edit_var)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Suggest a value for the given edit variable.
|
--- Suggest a value for the given edit variable.
|
||||||
@@ -1127,7 +1104,7 @@ do
|
|||||||
---@param value number the suggested value
|
---@param value number the suggested value
|
||||||
---@return kiwi.Var var, kiwi.Error?
|
---@return kiwi.Var var, kiwi.Error?
|
||||||
function Solver_cls:suggest_value(var, value)
|
function Solver_cls:suggest_value(var, value)
|
||||||
return try_solver(ljkiwi.kiwi_solver_suggest_value, self, var, value)
|
return try_solver(ckiwi.kiwi_solver_suggest_value, self, var, value)
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Suggest values for the given edit variables.
|
--- Suggest values for the given edit variables.
|
||||||
@@ -1139,7 +1116,7 @@ do
|
|||||||
---@return kiwi.Var[] vars, number[] values, kiwi.Error?
|
---@return kiwi.Var[] vars, number[] values, kiwi.Error?
|
||||||
function Solver_cls:suggest_values(vars, values)
|
function Solver_cls:suggest_values(vars, values)
|
||||||
for i, var in ipairs(vars) do
|
for i, var in ipairs(vars) do
|
||||||
local _, err = try_solver(ljkiwi.kiwi_solver_suggest_value, self, var, values[i])
|
local _, err = try_solver(ckiwi.kiwi_solver_suggest_value, self, var, values[i])
|
||||||
if err ~= nil then
|
if err ~= nil then
|
||||||
return vars, values, err
|
return vars, values, err
|
||||||
end
|
end
|
||||||
@@ -1151,7 +1128,7 @@ do
|
|||||||
---@return string
|
---@return string
|
||||||
---@nodiscard
|
---@nodiscard
|
||||||
function Solver_cls:dumps()
|
function Solver_cls:dumps()
|
||||||
local cs = ljkiwi.kiwi_solver_dumps(self)
|
local cs = ckiwi.kiwi_solver_dumps(self)
|
||||||
local s = ffi_string(cs)
|
local s = ffi_string(cs)
|
||||||
C.free(cs)
|
C.free(cs)
|
||||||
return s
|
return s
|
||||||
@@ -1165,15 +1142,13 @@ do
|
|||||||
if type(error_mask) == "table" then
|
if type(error_mask) == "table" then
|
||||||
error_mask = kiwi.error_mask(error_mask)
|
error_mask = kiwi.error_mask(error_mask)
|
||||||
end
|
end
|
||||||
|
return ffi_gc(ckiwi.kiwi_solver_new(error_mask or 0), ckiwi.kiwi_solver_del)
|
||||||
return ffi_gc(ljkiwi.kiwi_solver_construct(error_mask or 0), ljkiwi.kiwi_solver_destroy) --[[@as kiwi.Constraint]]
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local Solver = ffi.metatype(ffi.typeof("struct KiwiSolver"), Solver_mt) --[[@as kiwi.Solver]]
|
kiwi.Solver = ffi.metatype("struct KiwiSolver", Solver_mt) --[[@as kiwi.Solver]]
|
||||||
kiwi.Solver = Solver
|
|
||||||
|
|
||||||
function kiwi.is_solver(s)
|
function kiwi.is_solver(s)
|
||||||
return ffi_istype(Solver, s)
|
return ffi_istype(kiwi.Solver, s)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -26,70 +26,17 @@ enum RelationalOperator
|
|||||||
OP_EQ
|
OP_EQ
|
||||||
};
|
};
|
||||||
|
|
||||||
class Constraint;
|
|
||||||
class ConstraintData : public SharedData
|
|
||||||
{
|
|
||||||
static Expression reduce(const Expression &expr)
|
|
||||||
{
|
|
||||||
std::map<Variable, double> vars;
|
|
||||||
for (const auto & term : expr.terms())
|
|
||||||
vars[term.variable()] += term.coefficient();
|
|
||||||
|
|
||||||
std::vector<Term> terms(vars.begin(), vars.end());
|
|
||||||
return Expression(std::move(terms), expr.constant());
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
ConstraintData(const Expression &expr,
|
|
||||||
RelationalOperator op,
|
|
||||||
double strength) : SharedData(),
|
|
||||||
m_expression(reduce(expr)),
|
|
||||||
m_strength(strength::clip(strength)),
|
|
||||||
m_op(op) {}
|
|
||||||
|
|
||||||
ConstraintData(const ConstraintData &other, double strength) : SharedData(),
|
|
||||||
m_expression(other.m_expression),
|
|
||||||
m_strength(strength::clip(strength)),
|
|
||||||
m_op(other.m_op) {}
|
|
||||||
|
|
||||||
~ConstraintData() = default;
|
|
||||||
|
|
||||||
const Expression &expression() const { return m_expression; }
|
|
||||||
RelationalOperator op() const { return m_op; }
|
|
||||||
double strength() const { return m_strength; }
|
|
||||||
|
|
||||||
bool violated() const
|
|
||||||
{
|
|
||||||
switch (m_op)
|
|
||||||
{
|
|
||||||
case OP_EQ: return !impl::nearZero(m_expression.value());
|
|
||||||
case OP_GE: return m_expression.value() < 0.0;
|
|
||||||
case OP_LE: return m_expression.value() > 0.0;
|
|
||||||
}
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
Expression m_expression;
|
|
||||||
double m_strength;
|
|
||||||
RelationalOperator m_op;
|
|
||||||
|
|
||||||
ConstraintData(const ConstraintData &other) = delete;
|
|
||||||
ConstraintData &operator=(const ConstraintData &other) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Constraint
|
class Constraint
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
explicit Constraint(ConstraintData *p) : m_data(p) {}
|
|
||||||
|
|
||||||
|
public:
|
||||||
Constraint() = default;
|
Constraint() = default;
|
||||||
|
|
||||||
Constraint(const Expression &expr,
|
Constraint(const Expression &expr,
|
||||||
RelationalOperator op,
|
RelationalOperator op,
|
||||||
double strength = strength::required) : m_data(new ConstraintData(expr, op, strength)) {}
|
double strength = strength::required) : m_data(new ConstraintData(expr, op, strength)) {}
|
||||||
|
|
||||||
Constraint(const Constraint &other, double strength) : m_data(new ConstraintData(*other.m_data, strength)) {}
|
Constraint(const Constraint &other, double strength) : m_data(new ConstraintData(other, strength)) {}
|
||||||
|
|
||||||
Constraint(const Constraint &) = default;
|
Constraint(const Constraint &) = default;
|
||||||
|
|
||||||
@@ -97,10 +44,32 @@ public:
|
|||||||
|
|
||||||
~Constraint() = default;
|
~Constraint() = default;
|
||||||
|
|
||||||
const Expression &expression() const { return m_data->expression(); }
|
const Expression &expression() const
|
||||||
RelationalOperator op() const { return m_data->op(); }
|
{
|
||||||
double strength() const { return m_data->strength(); }
|
return m_data->m_expression;
|
||||||
bool violated() const { return m_data->violated(); }
|
}
|
||||||
|
|
||||||
|
RelationalOperator op() const
|
||||||
|
{
|
||||||
|
return m_data->m_op;
|
||||||
|
}
|
||||||
|
|
||||||
|
double strength() const
|
||||||
|
{
|
||||||
|
return m_data->m_strength;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool violated() const
|
||||||
|
{
|
||||||
|
switch (m_data->m_op)
|
||||||
|
{
|
||||||
|
case OP_EQ: return !impl::nearZero(m_data->m_expression.value());
|
||||||
|
case OP_GE: return m_data->m_expression.value() < 0.0;
|
||||||
|
case OP_LE: return m_data->m_expression.value() > 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::abort();
|
||||||
|
}
|
||||||
|
|
||||||
bool operator!() const
|
bool operator!() const
|
||||||
{
|
{
|
||||||
@@ -112,9 +81,45 @@ public:
|
|||||||
Constraint& operator=(Constraint &&) noexcept = default;
|
Constraint& operator=(Constraint &&) noexcept = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SharedDataPtr<ConstraintData> m_data;
|
static Expression reduce(const Expression &expr)
|
||||||
|
{
|
||||||
|
std::map<Variable, double> vars;
|
||||||
|
for (const auto & term : expr.terms())
|
||||||
|
vars[term.variable()] += term.coefficient();
|
||||||
|
|
||||||
public:
|
std::vector<Term> terms(vars.begin(), vars.end());
|
||||||
|
return Expression(std::move(terms), expr.constant());
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConstraintData : public SharedData
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
ConstraintData(const Expression &expr,
|
||||||
|
RelationalOperator op,
|
||||||
|
double strength) : SharedData(),
|
||||||
|
m_expression(reduce(expr)),
|
||||||
|
m_strength(strength::clip(strength)),
|
||||||
|
m_op(op) {}
|
||||||
|
|
||||||
|
ConstraintData(const Constraint &other, double strength) : SharedData(),
|
||||||
|
m_expression(other.expression()),
|
||||||
|
m_strength(strength::clip(strength)),
|
||||||
|
m_op(other.op()) {}
|
||||||
|
|
||||||
|
~ConstraintData() = default;
|
||||||
|
|
||||||
|
Expression m_expression;
|
||||||
|
double m_strength;
|
||||||
|
RelationalOperator m_op;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ConstraintData(const ConstraintData &other);
|
||||||
|
|
||||||
|
ConstraintData &operator=(const ConstraintData &other);
|
||||||
|
};
|
||||||
|
|
||||||
|
SharedDataPtr<ConstraintData> m_data;
|
||||||
|
|
||||||
friend bool operator<(const Constraint &lhs, const Constraint &rhs)
|
friend bool operator<(const Constraint &lhs, const Constraint &rhs)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -13,55 +13,63 @@
|
|||||||
namespace kiwi
|
namespace kiwi
|
||||||
{
|
{
|
||||||
|
|
||||||
class VariableData : public SharedData
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
VariableData(std::string name) : SharedData(),
|
|
||||||
m_name(std::move(name)),
|
|
||||||
m_value(0.0) {}
|
|
||||||
|
|
||||||
VariableData(const char *name) : SharedData(),
|
|
||||||
m_name(name),
|
|
||||||
m_value(0.0) {}
|
|
||||||
|
|
||||||
~VariableData() = default;
|
|
||||||
|
|
||||||
const std::string &name() const { return m_name; }
|
|
||||||
void setName(const char *name) { m_name = name; }
|
|
||||||
void setName(const std::string &name) { m_name = name; }
|
|
||||||
|
|
||||||
double value() const { return m_value; }
|
|
||||||
void setValue(double value) { m_value = value; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_name;
|
|
||||||
double m_value;
|
|
||||||
|
|
||||||
VariableData(const VariableData &other) = delete;
|
|
||||||
VariableData &operator=(const VariableData &other) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Variable
|
class Variable
|
||||||
{
|
{
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Variable(VariableData *p) : m_data(p) {}
|
class Context
|
||||||
VariableData *ptr() { return m_data; }
|
{
|
||||||
|
public:
|
||||||
|
Context() = default;
|
||||||
|
virtual ~Context() {} // LCOV_EXCL_LINE
|
||||||
|
};
|
||||||
|
|
||||||
Variable() : m_data(new VariableData("")) {}
|
Variable(Context *context = 0) : m_data(new VariableData("", context)) {}
|
||||||
|
|
||||||
|
Variable(std::string name, Context *context = 0) : m_data(new VariableData(std::move(name), context)) {}
|
||||||
|
|
||||||
|
Variable(const char *name, Context *context = 0) : m_data(new VariableData(name, context)) {}
|
||||||
|
|
||||||
Variable(std::string name) : m_data(new VariableData(std::move(name))) {}
|
|
||||||
Variable(const char *name) : m_data(new VariableData(name)) {}
|
|
||||||
Variable(const Variable&) = default;
|
Variable(const Variable&) = default;
|
||||||
|
|
||||||
Variable(Variable&&) noexcept = default;
|
Variable(Variable&&) noexcept = default;
|
||||||
|
|
||||||
~Variable() = default;
|
~Variable() = default;
|
||||||
|
|
||||||
const std::string &name() const { return m_data->name(); }
|
const std::string &name() const
|
||||||
void setName(const char *name) { m_data->setName(name); }
|
{
|
||||||
void setName(const std::string &name) { m_data->setName(name); }
|
return m_data->m_name;
|
||||||
|
}
|
||||||
|
|
||||||
double value() const { return m_data->value(); }
|
void setName(const char *name)
|
||||||
void setValue(double value) { m_data->setValue(value); }
|
{
|
||||||
|
m_data->m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setName(const std::string &name)
|
||||||
|
{
|
||||||
|
m_data->m_name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context *context() const
|
||||||
|
{
|
||||||
|
return m_data->m_context.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void setContext(Context *context)
|
||||||
|
{
|
||||||
|
m_data->m_context.reset(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
double value() const
|
||||||
|
{
|
||||||
|
return m_data->m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setValue(double value)
|
||||||
|
{
|
||||||
|
m_data->m_value = value;
|
||||||
|
}
|
||||||
|
|
||||||
// operator== is used for symbolics
|
// operator== is used for symbolics
|
||||||
bool equals(const Variable &other) const
|
bool equals(const Variable &other) const
|
||||||
@@ -74,6 +82,32 @@ public:
|
|||||||
Variable& operator=(Variable&&) noexcept = default;
|
Variable& operator=(Variable&&) noexcept = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
class VariableData : public SharedData
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
VariableData(std::string name, Context *context) : SharedData(),
|
||||||
|
m_name(std::move(name)),
|
||||||
|
m_context(context),
|
||||||
|
m_value(0.0) {}
|
||||||
|
|
||||||
|
VariableData(const char *name, Context *context) : SharedData(),
|
||||||
|
m_name(name),
|
||||||
|
m_context(context),
|
||||||
|
m_value(0.0) {}
|
||||||
|
|
||||||
|
~VariableData() = default;
|
||||||
|
|
||||||
|
std::string m_name;
|
||||||
|
std::unique_ptr<Context> m_context;
|
||||||
|
double m_value;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VariableData(const VariableData &other);
|
||||||
|
|
||||||
|
VariableData &operator=(const VariableData &other);
|
||||||
|
};
|
||||||
|
|
||||||
SharedDataPtr<VariableData> m_data;
|
SharedDataPtr<VariableData> m_data;
|
||||||
|
|
||||||
friend bool operator<(const Variable &lhs, const Variable &rhs)
|
friend bool operator<(const Variable &lhs, const Variable &rhs)
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
#include <kiwi/kiwi.h>
|
|
||||||
2
luakiwi.def
Normal file
2
luakiwi.def
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
EXPORTS
|
||||||
|
luaopen_ckiwi
|
||||||
88
luakiwi/.clang-format
Normal file
88
luakiwi/.clang-format
Normal 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
|
||||||
@@ -1,29 +1,33 @@
|
|||||||
#ifndef LJKIWI_LUACOMPAT_H_
|
#ifndef LKIWI_LUACOMPAT_H_
|
||||||
#define LJKIWI_LUACOMPAT_H_
|
#define LKIWI_LUACOMPAT_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
#include <lauxlib.h>
|
#include <lauxlib.h>
|
||||||
#include <lua.h>
|
#include <lua.h>
|
||||||
#include <lualib.h>
|
#include <lualib.h>
|
||||||
|
#ifdef __cplusplus
|
||||||
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501 && defined(__GNUC__)
|
}
|
||||||
#define LJKIWI_LJ_COMPAT_ATTR __attribute__((weak, visibility("default")))
|
#endif // __cplusplus
|
||||||
#else
|
|
||||||
#define LJKIWI_LJ_COMPAT_ATTR static
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(LUA_VERSION_NUM) || LUA_VERSION_NUM == 501
|
#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) {
|
static int lua_absindex(lua_State* L, int i) {
|
||||||
if (i < 0 && i > LUA_REGISTRYINDEX)
|
if (i < 0 && i > LUA_REGISTRYINDEX)
|
||||||
i += lua_gettop(L) + 1;
|
i += lua_gettop(L) + 1;
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
|
|
||||||
LJKIWI_LJ_COMPAT_ATTR lua_Number lua_tonumberx(lua_State* L, int i, int* isnum) {
|
static lua_Number lua_tonumberx(lua_State* L, int i, int* isnum) {
|
||||||
lua_Number n = lua_tonumber(L, i);
|
lua_Number n = lua_tonumber(L, i);
|
||||||
if (isnum != NULL) {
|
if (isnum != NULL) {
|
||||||
*isnum = (n != 0 || lua_isnumber(L, i));
|
*isnum = (n != 0 || lua_isnumber(L, i));
|
||||||
@@ -31,7 +35,7 @@ LJKIWI_LJ_COMPAT_ATTR lua_Number lua_tonumberx(lua_State* L, int i, int* isnum)
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
LJKIWI_LJ_COMPAT_ATTR lua_Integer lua_tointegerx(lua_State* L, int i, int* isnum) {
|
static lua_Integer lua_tointegerx(lua_State* L, int i, int* isnum) {
|
||||||
int ok = 0;
|
int ok = 0;
|
||||||
lua_Number n = lua_tonumberx(L, i, &ok);
|
lua_Number n = lua_tonumberx(L, i, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
@@ -140,8 +144,4 @@ static int luaL_typeerror(lua_State* L, int arg, const char* tname) {
|
|||||||
#define luaL_checkversion(L) ((void)0)
|
#define luaL_checkversion(L) ((void)0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#endif // LKIWI_LUACOMPAT_H_
|
||||||
}
|
|
||||||
#endif // __cplusplus
|
|
||||||
|
|
||||||
#endif // LJKIWI_LUACOMPAT_H_
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
#include "luacompat.h"
|
#include "luacompat.h"
|
||||||
|
|
||||||
#if defined(__GNUC__) && !defined(LJKIWI_NO_BUILTIN)
|
#if defined(__GNUC__) && !defined(LKIWI_NO_BUILTIN)
|
||||||
#define lk_likely(x) (__builtin_expect(((x) != 0), 1))
|
#define lk_likely(x) (__builtin_expect(((x) != 0), 1))
|
||||||
#define lk_unlikely(x) (__builtin_expect(((x) != 0), 0))
|
#define lk_unlikely(x) (__builtin_expect(((x) != 0), 0))
|
||||||
#else
|
#else
|
||||||
@@ -23,9 +23,8 @@ using namespace kiwi;
|
|||||||
// Lua 5.1 compatibility for missing lua_arith.
|
// Lua 5.1 compatibility for missing lua_arith.
|
||||||
inline void compat_arith_unm(lua_State* L) {
|
inline void compat_arith_unm(lua_State* L) {
|
||||||
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
|
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
|
||||||
int isnum;
|
lua_Number n = lua_tonumber(L, -1);
|
||||||
lua_Number n = lua_tonumberx(L, -1, &isnum);
|
if (n != 0 || lua_isnumber(L, -1)) {
|
||||||
if (isnum) {
|
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1);
|
||||||
lua_pushnumber(L, -n);
|
lua_pushnumber(L, -n);
|
||||||
} else {
|
} else {
|
||||||
@@ -59,7 +58,7 @@ constexpr int array_count(T (&)[N]) {
|
|||||||
return static_cast<int>(N);
|
return static_cast<int>(N);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void newlib(lua_State* L, const luaL_Reg* l) {
|
void newlib(lua_State* L, const luaL_Reg* l) {
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
setfuncs(L, l, 0);
|
setfuncs(L, l, 0);
|
||||||
}
|
}
|
||||||
@@ -79,28 +78,26 @@ enum KiwiErrKind {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct KiwiTerm {
|
struct KiwiTerm {
|
||||||
VariableData* var;
|
Variable* var;
|
||||||
double coefficient;
|
double coefficient;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct KiwiExpression {
|
struct KiwiExpression {
|
||||||
double constant;
|
double constant;
|
||||||
int term_count;
|
int term_count;
|
||||||
ConstraintData* owner;
|
Constraint* owner;
|
||||||
|
|
||||||
#if !defined(_MSC_VER) || _MSC_VER >= 1900
|
#if !defined(_MSC_VER) || _MSC_VER >= 1900
|
||||||
KiwiTerm terms[];
|
KiwiTerm terms[];
|
||||||
|
|
||||||
static constexpr std::size_t sz(int count) {
|
static constexpr std::size_t sz(int count) {
|
||||||
return sizeof(KiwiExpression)
|
return sizeof(KiwiExpression) + sizeof(KiwiTerm) * (count > 0 ? count : 0);
|
||||||
+ sizeof(KiwiTerm) * static_cast<std::size_t>(count > 0 ? count : 0);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
KiwiTerm terms[1];
|
KiwiTerm terms[1];
|
||||||
|
|
||||||
static constexpr std::size_t sz(int count) {
|
static constexpr std::size_t sz(int count) {
|
||||||
return sizeof(KiwiExpression)
|
return sizeof(KiwiExpression) + sizeof(KiwiTerm) * (count > 1 ? count - 1 : 0);
|
||||||
+ sizeof(KiwiTerm) * static_cast<std::size_t>(count > 0 ? count : 0);
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -141,57 +138,49 @@ template<typename F>
|
|||||||
inline const KiwiErr* wrap_err(F&& f) {
|
inline const KiwiErr* wrap_err(F&& f) {
|
||||||
static const constexpr KiwiErr kKiwiErrUnhandledCxxException {
|
static const constexpr KiwiErr kKiwiErrUnhandledCxxException {
|
||||||
KiwiErrUnknown,
|
KiwiErrUnknown,
|
||||||
"An unhandled C++ exception occurred."
|
"An unhandled C++ exception occurred."};
|
||||||
};
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
f();
|
f();
|
||||||
} catch (const UnsatisfiableConstraint&) {
|
} catch (const UnsatisfiableConstraint&) {
|
||||||
static const constexpr KiwiErr err {
|
static const constexpr KiwiErr err {
|
||||||
KiwiErrUnsatisfiableConstraint,
|
KiwiErrUnsatisfiableConstraint,
|
||||||
"The constraint cannot be satisfied."
|
"The constraint cannot be satisfied."};
|
||||||
};
|
|
||||||
return &err;
|
return &err;
|
||||||
} catch (const UnknownConstraint&) {
|
} catch (const UnknownConstraint&) {
|
||||||
static const constexpr KiwiErr err {
|
static const constexpr KiwiErr err {
|
||||||
KiwiErrUnknownConstraint,
|
KiwiErrUnknownConstraint,
|
||||||
"The constraint has not been added to the solver."
|
"The constraint has not been added to the solver."};
|
||||||
};
|
|
||||||
return &err;
|
return &err;
|
||||||
|
|
||||||
} catch (const DuplicateConstraint&) {
|
} catch (const DuplicateConstraint&) {
|
||||||
static const constexpr KiwiErr err {
|
static const constexpr KiwiErr err {
|
||||||
KiwiErrDuplicateConstraint,
|
KiwiErrDuplicateConstraint,
|
||||||
"The constraint has already been added to the solver."
|
"The constraint has already been added to the solver."};
|
||||||
};
|
|
||||||
return &err;
|
return &err;
|
||||||
|
|
||||||
} catch (const UnknownEditVariable&) {
|
} catch (const UnknownEditVariable&) {
|
||||||
static const constexpr KiwiErr err {
|
static const constexpr KiwiErr err {
|
||||||
KiwiErrUnknownEditVariable,
|
KiwiErrUnknownEditVariable,
|
||||||
"The edit variable has not been added to the solver."
|
"The edit variable has not been added to the solver."};
|
||||||
};
|
|
||||||
return &err;
|
return &err;
|
||||||
|
|
||||||
} catch (const DuplicateEditVariable&) {
|
} catch (const DuplicateEditVariable&) {
|
||||||
static const constexpr KiwiErr err {
|
static const constexpr KiwiErr err {
|
||||||
KiwiErrDuplicateEditVariable,
|
KiwiErrDuplicateEditVariable,
|
||||||
"The edit variable has already been added to the solver."
|
"The edit variable has already been added to the solver."};
|
||||||
};
|
|
||||||
return &err;
|
return &err;
|
||||||
|
|
||||||
} catch (const BadRequiredStrength&) {
|
} catch (const BadRequiredStrength&) {
|
||||||
static const constexpr KiwiErr err {
|
static const constexpr KiwiErr err {
|
||||||
KiwiErrBadRequiredStrength,
|
KiwiErrBadRequiredStrength,
|
||||||
"A required strength cannot be used in this context."
|
"A required strength cannot be used in this context."};
|
||||||
};
|
|
||||||
return &err;
|
return &err;
|
||||||
|
|
||||||
} catch (const InternalSolverError& ex) {
|
} catch (const InternalSolverError& ex) {
|
||||||
static const constexpr KiwiErr base {
|
static const constexpr KiwiErr base {
|
||||||
KiwiErrInternalSolverError,
|
KiwiErrInternalSolverError,
|
||||||
"An internal solver error occurred."
|
"An internal solver error occurred."};
|
||||||
};
|
|
||||||
return new_error(&base, ex);
|
return new_error(&base, ex);
|
||||||
} catch (std::bad_alloc&) {
|
} catch (std::bad_alloc&) {
|
||||||
static const constexpr KiwiErr err {KiwiErrAlloc, "A memory allocation failed."};
|
static const constexpr KiwiErr err {KiwiErrAlloc, "A memory allocation failed."};
|
||||||
@@ -205,108 +194,81 @@ inline const KiwiErr* wrap_err(F&& f) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename P, typename R, typename F>
|
template<typename P, typename R, typename F>
|
||||||
inline const KiwiErr* wrap_err(P&& s, F&& f) {
|
inline const KiwiErr* wrap_err(P& s, F&& f) {
|
||||||
return wrap_err([&]() { f(s); });
|
return wrap_err([&]() { f(s); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename P, typename R, typename F>
|
template<typename P, typename R, typename F>
|
||||||
inline const KiwiErr* wrap_err(P&& s, R&& ref, F&& f) {
|
inline const KiwiErr* wrap_err(P& s, R& ref, F&& f) {
|
||||||
return wrap_err([&]() { f(s, ref); });
|
return wrap_err([&]() { f(s, ref); });
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename... Args>
|
inline Variable* kiwi_var_retain(Variable* var) {
|
||||||
inline T* make_unmanaged(Args... args) {
|
alignas(Variable) unsigned char buf[sizeof(Variable)];
|
||||||
auto* p = new (std::nothrow) T(std::forward<Args>(args)...);
|
new (buf) Variable(*var);
|
||||||
if (lk_unlikely(!p))
|
return var;
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
p->m_refcount = 1;
|
|
||||||
return p;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
inline Constraint* kiwi_constraint_retain(Constraint* c) {
|
||||||
inline void release_unmanaged(T* p) {
|
alignas(Constraint) unsigned char buf[sizeof(Constraint)];
|
||||||
if (lk_likely(p)) {
|
new (buf) Constraint(*c);
|
||||||
if (--p->m_refcount == 0)
|
return c;
|
||||||
delete p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
inline Constraint* kiwi_constraint_new(
|
||||||
inline T* retain_unmanaged(T* p) {
|
|
||||||
if (lk_likely(p))
|
|
||||||
p->m_refcount++;
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ConstraintData* kiwi_constraint_new(
|
|
||||||
const KiwiExpression* lhs,
|
const KiwiExpression* lhs,
|
||||||
const KiwiExpression* rhs,
|
const KiwiExpression* rhs,
|
||||||
RelationalOperator op,
|
RelationalOperator op,
|
||||||
double strength
|
double strength,
|
||||||
|
void* mem
|
||||||
) {
|
) {
|
||||||
if (strength < 0.0) {
|
if (strength < 0.0) {
|
||||||
strength = kiwi::strength::required;
|
strength = kiwi::strength::required;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
std::vector<Term> terms;
|
||||||
std::vector<Term> terms;
|
terms.reserve((lhs ? lhs->term_count : 0) + (rhs ? rhs->term_count : 0));
|
||||||
|
|
||||||
terms.reserve(static_cast<decltype(terms)::size_type>(
|
if (lhs) {
|
||||||
(lhs && lhs->term_count > 0 ? lhs->term_count : 0)
|
for (auto* t = lhs->terms; t != lhs->terms + lhs->term_count; ++t) {
|
||||||
+ (rhs && rhs->term_count > 0 ? rhs->term_count : 0)
|
terms.emplace_back(*t->var, t->coefficient);
|
||||||
));
|
|
||||||
|
|
||||||
if (lhs) {
|
|
||||||
for (int i = 0; i < lhs->term_count; ++i) {
|
|
||||||
const auto& t = lhs->terms[i];
|
|
||||||
terms.emplace_back(Variable(t.var), t.coefficient);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (rhs) {
|
|
||||||
for (int i = 0; i < rhs->term_count; ++i) {
|
|
||||||
const auto& t = rhs->terms[i];
|
|
||||||
terms.emplace_back(Variable(t.var), -t.coefficient);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return make_unmanaged<ConstraintData>(
|
|
||||||
Expression(std::move(terms), (lhs ? lhs->constant : 0.0) - (rhs ? rhs->constant : 0.0)),
|
|
||||||
static_cast<RelationalOperator>(op),
|
|
||||||
strength
|
|
||||||
);
|
|
||||||
|
|
||||||
} catch (...) {
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
if (rhs) {
|
||||||
|
for (auto* t = rhs->terms; t != rhs->terms + rhs->term_count; ++t) {
|
||||||
|
terms.emplace_back(*t->var, -t->coefficient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new (mem) Constraint(
|
||||||
|
Expression(std::move(terms), (lhs ? lhs->constant : 0.0) - (rhs ? rhs->constant : 0.0)),
|
||||||
|
static_cast<RelationalOperator>(op),
|
||||||
|
strength
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const KiwiErr* kiwi_solver_add_constraint(Solver& s, ConstraintData* constraint) {
|
inline const KiwiErr* kiwi_solver_add_constraint(Solver& s, const Constraint& constraint) {
|
||||||
return wrap_err(s, constraint, [](auto&& solver, auto&& c) {
|
return wrap_err(s, constraint, [](auto& solver, const auto& c) { solver.addConstraint(c); });
|
||||||
solver.addConstraint(Constraint(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_remove_constraint(Solver& s, ConstraintData* constraint) {
|
inline const KiwiErr* kiwi_solver_add_edit_var(Solver& s, const Variable& var, double strength) {
|
||||||
return wrap_err(s, constraint, [](auto&& solver, auto&& c) {
|
return wrap_err(s, var, [strength](auto& solver, const auto& v) {
|
||||||
solver.removeConstraint(Constraint(c));
|
solver.addEditVariable(v, strength);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const KiwiErr* kiwi_solver_add_edit_var(Solver& s, VariableData* var, double strength) {
|
inline const KiwiErr* kiwi_solver_remove_edit_var(Solver& s, const Variable& var) {
|
||||||
return wrap_err(s, var, [strength](auto&& solver, auto&& v) {
|
return wrap_err(s, var, [](auto& solver, const auto& v) { solver.removeEditVariable(v); });
|
||||||
solver.addEditVariable(Variable(v), strength);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline const KiwiErr* kiwi_solver_remove_edit_var(Solver& s, VariableData* var) {
|
inline const KiwiErr* kiwi_solver_suggest_value(Solver& s, const Variable& var, double value) {
|
||||||
return wrap_err(s, var, [](auto&& solver, auto&& v) {
|
return wrap_err(s, var, [value](auto& solver, const auto& v) {
|
||||||
solver.removeEditVariable(Variable(v));
|
solver.suggestValue(v, value);
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const KiwiErr* kiwi_solver_suggest_value(Solver& s, VariableData* var, double value) {
|
|
||||||
return wrap_err(s, var, [value](auto&& solver, auto&& v) {
|
|
||||||
solver.suggestValue(Variable(v), value);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "luacompat.h"
|
||||||
#include "luakiwi-int.h"
|
#include "luakiwi-int.h"
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -11,7 +12,9 @@ namespace {
|
|||||||
|
|
||||||
enum TypeId { NOTYPE, VAR = 1, TERM, EXPR, CONSTRAINT, SOLVER, ERROR, NUMBER };
|
enum TypeId { NOTYPE, VAR = 1, TERM, EXPR, CONSTRAINT, SOLVER, ERROR, NUMBER };
|
||||||
|
|
||||||
enum { ERR_KIND_TAB = NUMBER + 1, VAR_SUB_FN, MEM_ERR_MSG, CONTEXT_TAB_MAX };
|
const int ERR_KIND_TAB = NUMBER + 1;
|
||||||
|
const int VAR_SUB_FN = ERR_KIND_TAB + 1;
|
||||||
|
const int CONTEXT_TAB_MAX = VAR_SUB_FN + 1;
|
||||||
|
|
||||||
constexpr const char* const lkiwi_error_kinds[] = {
|
constexpr const char* const lkiwi_error_kinds[] = {
|
||||||
"KiwiErrNone",
|
"KiwiErrNone",
|
||||||
@@ -142,8 +145,8 @@ inline void* try_type(lua_State* L, int idx, TypeId type_id) {
|
|||||||
return lua_rawequal(L, -1, -2) ? p : 0;
|
return lua_rawequal(L, -1, -2) ? p : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VariableData* try_var(lua_State* L, int idx) {
|
inline Variable* try_var(lua_State* L, int idx) {
|
||||||
return *static_cast<VariableData**>(try_type(L, idx, VAR));
|
return static_cast<Variable*>(try_type(L, idx, VAR));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline KiwiTerm* try_term(lua_State* L, int idx) {
|
inline KiwiTerm* try_term(lua_State* L, int idx) {
|
||||||
@@ -187,8 +190,8 @@ inline void* try_arg(lua_State* L, int idx, TypeId* type_id, double* num) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VariableData* get_var(lua_State* L, int idx) {
|
inline Variable* get_var(lua_State* L, int idx) {
|
||||||
return *static_cast<VariableData**>(check_arg(L, idx, VAR));
|
return static_cast<Variable*>(check_arg(L, idx, VAR));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline KiwiTerm* get_term(lua_State* L, int idx) {
|
inline KiwiTerm* get_term(lua_State* L, int idx) {
|
||||||
@@ -206,30 +209,24 @@ inline KiwiExpression* get_expr_opt(lua_State* L, int idx) {
|
|||||||
return static_cast<KiwiExpression*>(check_arg(L, idx, EXPR));
|
return static_cast<KiwiExpression*>(check_arg(L, idx, EXPR));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ConstraintData* get_constraint(lua_State* L, int idx) {
|
inline Constraint* get_constraint(lua_State* L, int idx) {
|
||||||
return *static_cast<ConstraintData**>(check_arg(L, idx, CONSTRAINT));
|
return static_cast<Constraint*>(check_arg(L, idx, CONSTRAINT));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline KiwiSolver* get_solver(lua_State* L, int idx) {
|
inline KiwiSolver* get_solver(lua_State* L, int idx) {
|
||||||
return static_cast<KiwiSolver*>(check_arg(L, idx, SOLVER));
|
return static_cast<KiwiSolver*>(check_arg(L, idx, SOLVER));
|
||||||
}
|
}
|
||||||
|
|
||||||
VariableData** var_new(lua_State* L) {
|
// note this expects the 2nd upvalue to have the variable weak table
|
||||||
auto** varp = static_cast<VariableData**>(lua_newuserdata(L, sizeof(VariableData*)));
|
template<typename... Args>
|
||||||
|
inline Variable* var_new(lua_State* L, Args&&... args) {
|
||||||
|
auto* var = new (lua_newuserdata(L, sizeof(Variable))) Variable(std::forward<Args>(args)...);
|
||||||
push_type(L, VAR);
|
push_type(L, VAR);
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
return varp;
|
|
||||||
}
|
|
||||||
|
|
||||||
// note this expects the 2nd upvalue to have the variable weak table
|
|
||||||
VariableData* var_register(lua_State* L, VariableData* var) {
|
|
||||||
if (lk_unlikely(!var)) {
|
|
||||||
lua_rawgeti(L, lua_upvalueindex(1), MEM_ERR_MSG);
|
|
||||||
lua_error(L);
|
|
||||||
}
|
|
||||||
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
|
#if defined(LUA_VERSION_NUM) && LUA_VERSION_NUM == 501
|
||||||
// a true compatibility shim has performance implications here
|
// a true compatibility shim has performance implications here
|
||||||
lua_pushlightuserdata(L, var);
|
lua_pushlightuserdata(L, p);
|
||||||
lua_pushvalue(L, -2);
|
lua_pushvalue(L, -2);
|
||||||
lua_rawset(L, lua_upvalueindex(2));
|
lua_rawset(L, lua_upvalueindex(2));
|
||||||
#else
|
#else
|
||||||
@@ -239,7 +236,7 @@ VariableData* var_register(lua_State* L, VariableData* var) {
|
|||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
KiwiTerm* term_new(lua_State* L) {
|
inline KiwiTerm* term_new(lua_State* L) {
|
||||||
auto* term = static_cast<KiwiTerm*>(lua_newuserdata(L, sizeof(KiwiTerm)));
|
auto* term = static_cast<KiwiTerm*>(lua_newuserdata(L, sizeof(KiwiTerm)));
|
||||||
push_type(L, TERM);
|
push_type(L, TERM);
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
@@ -254,22 +251,18 @@ inline KiwiExpression* expr_new(lua_State* L, int nterms) {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline ConstraintData* constraint_new(
|
inline Constraint* constraint_new(
|
||||||
lua_State* L,
|
lua_State* L,
|
||||||
const KiwiExpression* lhs,
|
const KiwiExpression* lhs,
|
||||||
const KiwiExpression* rhs,
|
const KiwiExpression* rhs,
|
||||||
kiwi::RelationalOperator op,
|
kiwi::RelationalOperator op,
|
||||||
double strength
|
double strength
|
||||||
) {
|
) {
|
||||||
auto** c = static_cast<ConstraintData**>(lua_newuserdata(L, sizeof(ConstraintData*)));
|
auto* c = kiwi_constraint_new(lhs, rhs, op, strength, lua_newuserdata(L, sizeof(Constraint)));
|
||||||
|
|
||||||
push_type(L, CONSTRAINT);
|
push_type(L, CONSTRAINT);
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
|
return c;
|
||||||
if (lk_unlikely(!(*c = kiwi_constraint_new(lhs, rhs, op, strength)))) {
|
|
||||||
lua_rawgeti(L, lua_upvalueindex(1), MEM_ERR_MSG);
|
|
||||||
lua_error(L);
|
|
||||||
}
|
|
||||||
return *c;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// stack disposition: dirty
|
// stack disposition: dirty
|
||||||
@@ -294,7 +287,7 @@ KiwiExpression* toexpr(lua_State* L, int idx, KiwiExpression* temp) {
|
|||||||
temp->term_count = 1;
|
temp->term_count = 1;
|
||||||
push_type(L, VAR);
|
push_type(L, VAR);
|
||||||
if (lua_rawequal(L, -1, -3)) {
|
if (lua_rawequal(L, -1, -3)) {
|
||||||
temp->terms[0].var = *static_cast<VariableData**>(ud);
|
temp->terms[0].var = static_cast<Variable*>(ud);
|
||||||
temp->terms[0].coefficient = 1.0;
|
temp->terms[0].coefficient = 1.0;
|
||||||
return temp;
|
return temp;
|
||||||
}
|
}
|
||||||
@@ -338,7 +331,7 @@ inline int push_expr_one(lua_State* L, double constant, const KiwiTerm* term) {
|
|||||||
expr->constant = constant;
|
expr->constant = constant;
|
||||||
expr->term_count = 1;
|
expr->term_count = 1;
|
||||||
expr->terms[0].coefficient = term->coefficient;
|
expr->terms[0].coefficient = term->coefficient;
|
||||||
expr->terms[0].var = retain_unmanaged(term->var);
|
expr->terms[0].var = kiwi_var_retain(term->var);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,21 +340,20 @@ inline int push_expr_pair(lua_State* L, double constant, const KiwiTerm* ta, con
|
|||||||
e->constant = constant;
|
e->constant = constant;
|
||||||
e->term_count = 2;
|
e->term_count = 2;
|
||||||
e->terms[0].coefficient = ta->coefficient;
|
e->terms[0].coefficient = ta->coefficient;
|
||||||
e->terms[0].var = retain_unmanaged(ta->var);
|
e->terms[0].var = kiwi_var_retain(ta->var);
|
||||||
e->terms[1].coefficient = tb->coefficient;
|
e->terms[1].coefficient = tb->coefficient;
|
||||||
e->terms[1].var = retain_unmanaged(tb->var);
|
e->terms[1].var = kiwi_var_retain(tb->var);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int
|
inline int push_expr_var_term(lua_State* L, double constant, Variable* var, const KiwiTerm* t) {
|
||||||
push_expr_var_term(lua_State* L, double constant, VariableData* var, const KiwiTerm* t) {
|
|
||||||
auto* e = expr_new(L, 2);
|
auto* e = expr_new(L, 2);
|
||||||
e->constant = constant;
|
e->constant = constant;
|
||||||
e->term_count = 2;
|
e->term_count = 2;
|
||||||
e->terms[0].coefficient = 1.0;
|
e->terms[0].coefficient = 1.0;
|
||||||
e->terms[0].var = retain_unmanaged(var);
|
e->terms[0].var = kiwi_var_retain(var);
|
||||||
e->terms[1].coefficient = t->coefficient;
|
e->terms[1].coefficient = t->coefficient;
|
||||||
e->terms[1].var = retain_unmanaged(t->var);
|
e->terms[1].var = kiwi_var_retain(t->var);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -372,23 +364,23 @@ int push_add_expr_term(lua_State* L, const KiwiExpression* expr, const KiwiTerm*
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
for (; i < expr->term_count; ++i) {
|
for (; i < expr->term_count; ++i) {
|
||||||
e->terms[i].coefficient = expr->terms[i].coefficient;
|
e->terms[i].coefficient = expr->terms[i].coefficient;
|
||||||
e->terms[i].var = retain_unmanaged(expr->terms[i].var);
|
e->terms[i].var = kiwi_var_retain(expr->terms[i].var);
|
||||||
}
|
}
|
||||||
e->terms[i].coefficient = t->coefficient;
|
e->terms[i].coefficient = t->coefficient;
|
||||||
e->terms[i].var = retain_unmanaged(t->var);
|
e->terms[i].var = kiwi_var_retain(t->var);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_var_m_add(lua_State* L) {
|
int lkiwi_var_m_add(lua_State* L) {
|
||||||
TypeId type_id_b;
|
TypeId type_id_b;
|
||||||
double num = 0.0;
|
double num;
|
||||||
void* arg_b = try_arg(L, 2, &type_id_b, &num);
|
void* arg_b = try_arg(L, 2, &type_id_b, &num);
|
||||||
|
|
||||||
if (type_id_b == VAR) {
|
if (type_id_b == VAR) {
|
||||||
int isnum_a;
|
int isnum_a;
|
||||||
num = lua_tonumberx(L, 1, &isnum_a);
|
num = lua_tonumberx(L, 1, &isnum_a);
|
||||||
if (isnum_a) {
|
if (isnum_a) {
|
||||||
const KiwiTerm t {*static_cast<VariableData**>(arg_b), 1.0};
|
const KiwiTerm t {static_cast<Variable*>(arg_b), 1.0};
|
||||||
return push_expr_one(L, num, &t);
|
return push_expr_one(L, num, &t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,7 +389,7 @@ int lkiwi_var_m_add(lua_State* L) {
|
|||||||
if (var_a) {
|
if (var_a) {
|
||||||
switch (type_id_b) {
|
switch (type_id_b) {
|
||||||
case VAR: {
|
case VAR: {
|
||||||
const KiwiTerm ta {var_a, 1.0}, tb {*static_cast<VariableData**>(arg_b), 1.0};
|
const KiwiTerm ta {var_a, 1.0}, tb {static_cast<Variable*>(arg_b), 1.0};
|
||||||
return push_expr_pair(L, 0.0, &ta, &tb);
|
return push_expr_pair(L, 0.0, &ta, &tb);
|
||||||
}
|
}
|
||||||
case TERM:
|
case TERM:
|
||||||
@@ -443,7 +435,7 @@ int lkiwi_var_m_mul(lua_State* L) {
|
|||||||
auto* var = try_var(L, varidx);
|
auto* var = try_var(L, varidx);
|
||||||
if (var) {
|
if (var) {
|
||||||
auto* term = term_new(L);
|
auto* term = term_new(L);
|
||||||
term->var = retain_unmanaged(var);
|
term->var = kiwi_var_retain(var);
|
||||||
term->coefficient = num;
|
term->coefficient = num;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -459,20 +451,20 @@ int lkiwi_var_m_div(lua_State* L) {
|
|||||||
return op_error(L, "/", 1, 2);
|
return op_error(L, "/", 1, 2);
|
||||||
}
|
}
|
||||||
auto* term = term_new(L);
|
auto* term = term_new(L);
|
||||||
term->var = retain_unmanaged(var);
|
term->var = kiwi_var_retain(var);
|
||||||
term->coefficient = 1.0 / num;
|
term->coefficient = 1.0 / num;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_var_m_unm(lua_State* L) {
|
int lkiwi_var_m_unm(lua_State* L) {
|
||||||
auto* term = term_new(L);
|
auto* term = term_new(L);
|
||||||
term->var = retain_unmanaged(get_var(L, 1));
|
term->var = kiwi_var_retain(get_var(L, 1));
|
||||||
term->coefficient = -1.0;
|
term->coefficient = -1.0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_var_m_eq(lua_State* L) {
|
int lkiwi_var_m_eq(lua_State* L) {
|
||||||
lua_pushboolean(L, get_var(L, 1) == get_var(L, 2));
|
lua_pushboolean(L, get_var(L, 1)->equals(*get_var(L, 2)));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -483,7 +475,7 @@ int lkiwi_var_m_tostring(lua_State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_var_m_gc(lua_State* L) {
|
int lkiwi_var_m_gc(lua_State* L) {
|
||||||
release_unmanaged(get_var(L, 1));
|
get_var(L, 1)->~Variable();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,7 +508,7 @@ int lkiwi_var_toterm(lua_State* L) {
|
|||||||
double coefficient = luaL_optnumber(L, 2, 1.0);
|
double coefficient = luaL_optnumber(L, 2, 1.0);
|
||||||
auto* term = term_new(L);
|
auto* term = term_new(L);
|
||||||
|
|
||||||
term->var = retain_unmanaged(var);
|
term->var = kiwi_var_retain(var);
|
||||||
term->coefficient = coefficient;
|
term->coefficient = coefficient;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -545,21 +537,59 @@ constexpr const struct luaL_Reg kiwi_var_m[] = {
|
|||||||
{"eq", lkiwi_eq},
|
{"eq", lkiwi_eq},
|
||||||
{"le", lkiwi_le},
|
{"le", lkiwi_le},
|
||||||
{"ge", lkiwi_ge},
|
{"ge", lkiwi_ge},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
int lkiwi_var_new(lua_State* L) {
|
int lkiwi_var_new(lua_State* L) {
|
||||||
const char* name = luaL_optstring(L, 1, "");
|
const char* name = luaL_optstring(L, 1, "");
|
||||||
|
var_new(L, name);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
auto* varp = var_new(L);
|
int lkiwi_term_m_mul(lua_State* L) {
|
||||||
var_register(L, *varp = make_unmanaged<VariableData>(name));
|
int isnum, termidx = 2;
|
||||||
|
double num = lua_tonumberx(L, 1, &isnum);
|
||||||
|
|
||||||
|
if (!isnum) {
|
||||||
|
termidx = 1;
|
||||||
|
num = lua_tonumberx(L, 2, &isnum);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isnum) {
|
||||||
|
const auto* term = try_term(L, termidx);
|
||||||
|
if (term) {
|
||||||
|
auto* ret = term_new(L);
|
||||||
|
ret->var = kiwi_var_retain(term->var);
|
||||||
|
ret->coefficient = term->coefficient * num;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return op_error(L, "*", 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lkiwi_term_m_div(lua_State* L) {
|
||||||
|
const KiwiTerm* term = try_term(L, 1);
|
||||||
|
int isnum;
|
||||||
|
double num = lua_tonumberx(L, 2, &isnum);
|
||||||
|
if (!term || !isnum) {
|
||||||
|
return op_error(L, "/", 1, 2);
|
||||||
|
}
|
||||||
|
auto* ret = term_new(L);
|
||||||
|
ret->var = kiwi_var_retain(term->var);
|
||||||
|
ret->coefficient = term->coefficient / num;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int lkiwi_term_m_unm(lua_State* L) {
|
||||||
|
const auto* term = get_term(L, 1);
|
||||||
|
auto* ret = term_new(L);
|
||||||
|
ret->var = kiwi_var_retain(term->var);
|
||||||
|
ret->coefficient = -term->coefficient;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_term_m_add(lua_State* L) {
|
int lkiwi_term_m_add(lua_State* L) {
|
||||||
TypeId type_id_b;
|
TypeId type_id_b;
|
||||||
double num = 0.0;
|
double num;
|
||||||
void* arg_b = try_arg(L, 2, &type_id_b, &num);
|
void* arg_b = try_arg(L, 2, &type_id_b, &num);
|
||||||
|
|
||||||
if (type_id_b == TERM) {
|
if (type_id_b == TERM) {
|
||||||
@@ -576,7 +606,7 @@ int lkiwi_term_m_add(lua_State* L) {
|
|||||||
case TERM:
|
case TERM:
|
||||||
return push_expr_pair(L, 0.0, term_a, static_cast<KiwiTerm*>(arg_b));
|
return push_expr_pair(L, 0.0, term_a, static_cast<KiwiTerm*>(arg_b));
|
||||||
case VAR: {
|
case VAR: {
|
||||||
const KiwiTerm term_b {*static_cast<VariableData**>(arg_b), 1.0};
|
const KiwiTerm term_b {static_cast<Variable*>(arg_b), 1.0};
|
||||||
return push_expr_pair(L, 0.0, term_a, &term_b);
|
return push_expr_pair(L, 0.0, term_a, &term_b);
|
||||||
}
|
}
|
||||||
case EXPR:
|
case EXPR:
|
||||||
@@ -597,48 +627,6 @@ int lkiwi_term_m_sub(lua_State* L) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_term_m_mul(lua_State* L) {
|
|
||||||
int isnum, termidx = 2;
|
|
||||||
double num = lua_tonumberx(L, 1, &isnum);
|
|
||||||
|
|
||||||
if (!isnum) {
|
|
||||||
termidx = 1;
|
|
||||||
num = lua_tonumberx(L, 2, &isnum);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isnum) {
|
|
||||||
const auto* term = try_term(L, termidx);
|
|
||||||
if (term) {
|
|
||||||
auto* ret = term_new(L);
|
|
||||||
ret->var = retain_unmanaged(term->var);
|
|
||||||
ret->coefficient = term->coefficient * num;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return op_error(L, "*", 1, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int lkiwi_term_m_div(lua_State* L) {
|
|
||||||
const KiwiTerm* term = try_term(L, 1);
|
|
||||||
int isnum;
|
|
||||||
double num = lua_tonumberx(L, 2, &isnum);
|
|
||||||
if (!term || !isnum) {
|
|
||||||
return op_error(L, "/", 1, 2);
|
|
||||||
}
|
|
||||||
auto* ret = term_new(L);
|
|
||||||
ret->var = retain_unmanaged(term->var);
|
|
||||||
ret->coefficient = term->coefficient / num;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lkiwi_term_m_unm(lua_State* L) {
|
|
||||||
const auto* term = get_term(L, 1);
|
|
||||||
auto* ret = term_new(L);
|
|
||||||
ret->var = retain_unmanaged(term->var);
|
|
||||||
ret->coefficient = -term->coefficient;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lkiwi_term_toexpr(lua_State* L) {
|
int lkiwi_term_toexpr(lua_State* L) {
|
||||||
return push_expr_one(L, 0.0, get_term(L, 1));
|
return push_expr_one(L, 0.0, get_term(L, 1));
|
||||||
}
|
}
|
||||||
@@ -656,7 +644,7 @@ int lkiwi_term_m_tostring(lua_State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_term_m_gc(lua_State* L) {
|
int lkiwi_term_m_gc(lua_State* L) {
|
||||||
release_unmanaged(get_term(L, 1)->var);
|
get_term(L, 1)->var->~Variable();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -671,10 +659,8 @@ int lkiwi_term_m_index(lua_State* L) {
|
|||||||
#else
|
#else
|
||||||
lua_rawgetp(L, lua_upvalueindex(2), term->var);
|
lua_rawgetp(L, lua_upvalueindex(2), term->var);
|
||||||
#endif
|
#endif
|
||||||
if (lua_isnil(L, -1)) {
|
if (lua_isnil(L, -1))
|
||||||
auto* varp = var_new(L);
|
var_new(L, *term->var);
|
||||||
var_register(L, *varp = retain_unmanaged(term->var));
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
} else if (len == 11 && memcmp("coefficient", k, len) == 0) {
|
} else if (len == 11 && memcmp("coefficient", k, len) == 0) {
|
||||||
lua_pushnumber(L, term->coefficient);
|
lua_pushnumber(L, term->coefficient);
|
||||||
@@ -703,14 +689,13 @@ constexpr const struct luaL_Reg kiwi_term_m[] = {
|
|||||||
{"eq", lkiwi_eq},
|
{"eq", lkiwi_eq},
|
||||||
{"le", lkiwi_le},
|
{"le", lkiwi_le},
|
||||||
{"ge", lkiwi_ge},
|
{"ge", lkiwi_ge},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
int lkiwi_term_new(lua_State* L) {
|
int lkiwi_term_new(lua_State* L) {
|
||||||
auto* var = get_var(L, 1);
|
auto* var = get_var(L, 1);
|
||||||
double coefficient = luaL_optnumber(L, 2, 1.0);
|
double coefficient = luaL_optnumber(L, 2, 1.0);
|
||||||
auto* term = term_new(L);
|
auto* term = term_new(L);
|
||||||
term->var = retain_unmanaged(var);
|
term->var = kiwi_var_retain(var);
|
||||||
term->coefficient = coefficient;
|
term->coefficient = coefficient;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -718,7 +703,7 @@ int lkiwi_term_new(lua_State* L) {
|
|||||||
int push_expr_constant(lua_State* L, const KiwiExpression* expr, double constant) {
|
int push_expr_constant(lua_State* L, const KiwiExpression* expr, double constant) {
|
||||||
auto* ne = expr_new(L, expr->term_count);
|
auto* ne = expr_new(L, expr->term_count);
|
||||||
for (int i = 0; i < expr->term_count; i++) {
|
for (int i = 0; i < expr->term_count; i++) {
|
||||||
ne->terms[i].var = retain_unmanaged(expr->terms[i].var);
|
ne->terms[i].var = kiwi_var_retain(expr->terms[i].var);
|
||||||
ne->terms[i].coefficient = expr->terms[i].coefficient;
|
ne->terms[i].coefficient = expr->terms[i].coefficient;
|
||||||
}
|
}
|
||||||
ne->constant = constant;
|
ne->constant = constant;
|
||||||
@@ -731,7 +716,7 @@ int push_mul_expr_coeff(lua_State* L, const KiwiExpression* expr, double coeff)
|
|||||||
ne->constant = expr->constant * coeff;
|
ne->constant = expr->constant * coeff;
|
||||||
ne->term_count = expr->term_count;
|
ne->term_count = expr->term_count;
|
||||||
for (int i = 0; i < expr->term_count; i++) {
|
for (int i = 0; i < expr->term_count; i++) {
|
||||||
ne->terms[i].var = retain_unmanaged(expr->terms[i].var);
|
ne->terms[i].var = kiwi_var_retain(expr->terms[i].var);
|
||||||
ne->terms[i].coefficient = expr->terms[i].coefficient * coeff;
|
ne->terms[i].coefficient = expr->terms[i].coefficient * coeff;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -745,57 +730,16 @@ int push_add_expr_expr(lua_State* L, const KiwiExpression* a, const KiwiExpressi
|
|||||||
ne->term_count = na + nb;
|
ne->term_count = na + nb;
|
||||||
|
|
||||||
for (int i = 0; i < na; i++) {
|
for (int i = 0; i < na; i++) {
|
||||||
ne->terms[i].var = retain_unmanaged(a->terms[i].var);
|
ne->terms[i].var = kiwi_var_retain(a->terms[i].var);
|
||||||
ne->terms[i].coefficient = a->terms[i].coefficient;
|
ne->terms[i].coefficient = a->terms[i].coefficient;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < nb; i++) {
|
for (int i = 0; i < nb; i++) {
|
||||||
ne->terms[i + na].var = retain_unmanaged(b->terms[i].var);
|
ne->terms[i + na].var = kiwi_var_retain(b->terms[i].var);
|
||||||
ne->terms[i + na].coefficient = b->terms[i].coefficient;
|
ne->terms[i + na].coefficient = b->terms[i].coefficient;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_expr_m_add(lua_State* L) {
|
|
||||||
TypeId type_id_b;
|
|
||||||
double num = 0.0;
|
|
||||||
void* arg_b = try_arg(L, 2, &type_id_b, &num);
|
|
||||||
|
|
||||||
if (type_id_b == EXPR) {
|
|
||||||
int isnum_a;
|
|
||||||
num = lua_tonumberx(L, 1, &isnum_a);
|
|
||||||
if (isnum_a) {
|
|
||||||
auto* expr_b = static_cast<const KiwiExpression*>(arg_b);
|
|
||||||
return push_expr_constant(L, expr_b, num + expr_b->constant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto* expr_a = try_expr(L, 1);
|
|
||||||
if (expr_a) {
|
|
||||||
switch (type_id_b) {
|
|
||||||
case EXPR:
|
|
||||||
return push_add_expr_expr(L, expr_a, static_cast<KiwiExpression*>(arg_b));
|
|
||||||
case TERM:
|
|
||||||
return push_add_expr_term(L, expr_a, static_cast<KiwiTerm*>(arg_b));
|
|
||||||
case VAR: {
|
|
||||||
const KiwiTerm term_b {*static_cast<VariableData**>(arg_b), 1.0};
|
|
||||||
return push_add_expr_term(L, expr_a, &term_b);
|
|
||||||
}
|
|
||||||
case NUMBER:
|
|
||||||
return push_expr_constant(L, expr_a, num + expr_a->constant);
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return op_error(L, "+", 1, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
int lkiwi_expr_m_sub(lua_State* L) {
|
|
||||||
lua_settop(L, 2);
|
|
||||||
compat_arith_unm(L);
|
|
||||||
lkiwi_expr_m_add(L);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int lkiwi_expr_m_mul(lua_State* L) {
|
int lkiwi_expr_m_mul(lua_State* L) {
|
||||||
int isnum, expridx = 2;
|
int isnum, expridx = 2;
|
||||||
double num = lua_tonumberx(L, 1, &isnum);
|
double num = lua_tonumberx(L, 1, &isnum);
|
||||||
@@ -828,6 +772,47 @@ int lkiwi_expr_m_unm(lua_State* L) {
|
|||||||
return push_mul_expr_coeff(L, expr, -1.0);
|
return push_mul_expr_coeff(L, expr, -1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int lkiwi_expr_m_add(lua_State* L) {
|
||||||
|
TypeId type_id_b;
|
||||||
|
double num;
|
||||||
|
void* arg_b = try_arg(L, 2, &type_id_b, &num);
|
||||||
|
|
||||||
|
if (type_id_b == EXPR) {
|
||||||
|
int isnum_a;
|
||||||
|
num = lua_tonumberx(L, 1, &isnum_a);
|
||||||
|
if (isnum_a) {
|
||||||
|
auto* expr_b = static_cast<const KiwiExpression*>(arg_b);
|
||||||
|
return push_expr_constant(L, expr_b, num + expr_b->constant);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* expr_a = try_expr(L, 1);
|
||||||
|
if (expr_a) {
|
||||||
|
switch (type_id_b) {
|
||||||
|
case EXPR:
|
||||||
|
return push_add_expr_expr(L, expr_a, static_cast<KiwiExpression*>(arg_b));
|
||||||
|
case TERM:
|
||||||
|
return push_add_expr_term(L, expr_a, static_cast<KiwiTerm*>(arg_b));
|
||||||
|
case VAR: {
|
||||||
|
const KiwiTerm term_b {static_cast<Variable*>(arg_b), 1.0};
|
||||||
|
return push_add_expr_term(L, expr_a, &term_b);
|
||||||
|
}
|
||||||
|
case NUMBER:
|
||||||
|
return push_expr_constant(L, expr_a, num + expr_a->constant);
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return op_error(L, "+", 1, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lkiwi_expr_m_sub(lua_State* L) {
|
||||||
|
lua_settop(L, 2);
|
||||||
|
compat_arith_unm(L);
|
||||||
|
lkiwi_expr_m_add(L);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
int lkiwi_expr_value(lua_State* L) {
|
int lkiwi_expr_value(lua_State* L) {
|
||||||
const auto* expr = get_expr(L, 1);
|
const auto* expr = get_expr(L, 1);
|
||||||
double sum = expr->constant;
|
double sum = expr->constant;
|
||||||
@@ -845,7 +830,7 @@ int lkiwi_expr_terms(lua_State* L) {
|
|||||||
for (int i = 0; i < expr->term_count; i++) {
|
for (int i = 0; i < expr->term_count; i++) {
|
||||||
const auto* t = &expr->terms[i];
|
const auto* t = &expr->terms[i];
|
||||||
auto* new_term = term_new(L);
|
auto* new_term = term_new(L);
|
||||||
new_term->var = retain_unmanaged(t->var);
|
new_term->var = kiwi_var_retain(t->var);
|
||||||
new_term->coefficient = t->coefficient;
|
new_term->coefficient = t->coefficient;
|
||||||
lua_rawseti(L, -2, i + 1);
|
lua_rawseti(L, -2, i + 1);
|
||||||
}
|
}
|
||||||
@@ -879,10 +864,10 @@ int lkiwi_expr_m_tostring(lua_State* L) {
|
|||||||
int lkiwi_expr_m_gc(lua_State* L) {
|
int lkiwi_expr_m_gc(lua_State* L) {
|
||||||
const auto* expr = get_expr(L, 1);
|
const auto* expr = get_expr(L, 1);
|
||||||
if (expr->owner) {
|
if (expr->owner) {
|
||||||
release_unmanaged(expr->owner);
|
expr->owner->~Constraint();
|
||||||
} else {
|
} else {
|
||||||
for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) {
|
for (auto* t = expr->terms; t != expr->terms + expr->term_count; ++t) {
|
||||||
release_unmanaged(t->var);
|
t->var->~Variable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -920,8 +905,7 @@ constexpr const struct luaL_Reg kiwi_expr_m[] = {
|
|||||||
{"eq", lkiwi_eq},
|
{"eq", lkiwi_eq},
|
||||||
{"le", lkiwi_le},
|
{"le", lkiwi_le},
|
||||||
{"ge", lkiwi_ge},
|
{"ge", lkiwi_ge},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
int lkiwi_expr_new(lua_State* L) {
|
int lkiwi_expr_new(lua_State* L) {
|
||||||
int nterms = lua_gettop(L) - 1;
|
int nterms = lua_gettop(L) - 1;
|
||||||
@@ -933,7 +917,7 @@ int lkiwi_expr_new(lua_State* L) {
|
|||||||
|
|
||||||
for (int i = 0; i < nterms; i++) {
|
for (int i = 0; i < nterms; i++) {
|
||||||
const auto* term = get_term(L, i + 2);
|
const auto* term = get_term(L, i + 2);
|
||||||
expr->terms[i].var = retain_unmanaged(term->var);
|
expr->terms[i].var = kiwi_var_retain(term->var);
|
||||||
expr->terms[i].coefficient = term->coefficient;
|
expr->terms[i].coefficient = term->coefficient;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
@@ -971,17 +955,16 @@ int lkiwi_constraint_expression(lua_State* L) {
|
|||||||
auto* c = get_constraint(L, 1);
|
auto* c = get_constraint(L, 1);
|
||||||
const auto& expr = c->expression();
|
const auto& expr = c->expression();
|
||||||
const auto& terms = expr.terms();
|
const auto& terms = expr.terms();
|
||||||
const auto term_count = static_cast<int>(terms.size() > INT_MAX ? INT_MAX : terms.size());
|
const int term_count = terms.size();
|
||||||
|
|
||||||
auto* ne = expr_new(L, term_count);
|
auto* ne = expr_new(L, term_count);
|
||||||
ne->owner = retain_unmanaged(c);
|
ne->owner = kiwi_constraint_retain(c);
|
||||||
ne->constant = expr.constant();
|
ne->constant = expr.constant();
|
||||||
ne->term_count = term_count;
|
ne->term_count = term_count;
|
||||||
|
|
||||||
for (int i = 0; i < term_count; ++i) {
|
for (int i = 0; i < term_count; ++i) {
|
||||||
const auto& t = terms[static_cast<std::size_t>(i)];
|
ne->terms[i].var = const_cast<Variable*>(&terms[i].variable());
|
||||||
ne->terms[i].var = const_cast<Variable&>(t.variable()).ptr();
|
ne->terms[i].coefficient = terms[i].coefficient();
|
||||||
ne->terms[i].coefficient = t.coefficient();
|
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1041,7 +1024,7 @@ int lkiwi_constraint_m_tostring(lua_State* L) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_constraint_m_gc(lua_State* L) {
|
int lkiwi_constraint_m_gc(lua_State* L) {
|
||||||
release_unmanaged(get_constraint(L, 1));
|
get_constraint(L, 1)->~Constraint();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,8 +1056,7 @@ constexpr const struct luaL_Reg kiwi_constraint_m[] = {
|
|||||||
{"expression", lkiwi_constraint_expression},
|
{"expression", lkiwi_constraint_expression},
|
||||||
{"add_to", lkiwi_constraint_add_to},
|
{"add_to", lkiwi_constraint_add_to},
|
||||||
{"remove_from", lkiwi_constraint_remove_from},
|
{"remove_from", lkiwi_constraint_remove_from},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
int lkiwi_constraint_new(lua_State* L) {
|
int lkiwi_constraint_new(lua_State* L) {
|
||||||
const auto* lhs = get_expr_opt(L, 1);
|
const auto* lhs = get_expr_opt(L, 1);
|
||||||
@@ -1088,9 +1070,9 @@ int lkiwi_constraint_new(lua_State* L) {
|
|||||||
|
|
||||||
int push_pair_constraint(
|
int push_pair_constraint(
|
||||||
lua_State* L,
|
lua_State* L,
|
||||||
VariableData* left,
|
Variable* left,
|
||||||
double coeff,
|
double coeff,
|
||||||
VariableData* right,
|
Variable* right,
|
||||||
double constant,
|
double constant,
|
||||||
kiwi::RelationalOperator op,
|
kiwi::RelationalOperator op,
|
||||||
double strength
|
double strength
|
||||||
@@ -1147,8 +1129,7 @@ constexpr const struct luaL_Reg lkiwi_constraints[] = {
|
|||||||
{"pair_ratio", lkiwi_constraints_pair_ratio},
|
{"pair_ratio", lkiwi_constraints_pair_ratio},
|
||||||
{"pair", lkiwi_constraints_pair},
|
{"pair", lkiwi_constraints_pair},
|
||||||
{"single", lkiwi_constraints_single},
|
{"single", lkiwi_constraints_single},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
void lkiwi_mod_constraints_new(lua_State* L, int ctx_i) {
|
void lkiwi_mod_constraints_new(lua_State* L, int ctx_i) {
|
||||||
luaL_newlibtable(L, lkiwi_constraints);
|
luaL_newlibtable(L, lkiwi_constraints);
|
||||||
@@ -1199,7 +1180,10 @@ int lkiwi_error_m_tostring(lua_State* L) {
|
|||||||
luaL_tolstring(L, -1, 0);
|
luaL_tolstring(L, -1, 0);
|
||||||
lua_remove(L, -2); // remove item
|
lua_remove(L, -2); // remove item
|
||||||
luaL_addvalue(&buf);
|
luaL_addvalue(&buf);
|
||||||
luaL_addstring(&buf, ")");
|
luaL_addstring(&buf, ")\n");
|
||||||
|
|
||||||
|
luaL_traceback(L, L, nullptr, 2);
|
||||||
|
luaL_addvalue(&buf);
|
||||||
luaL_pushresult(&buf);
|
luaL_pushresult(&buf);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@@ -1207,8 +1191,7 @@ int lkiwi_error_m_tostring(lua_State* L) {
|
|||||||
|
|
||||||
constexpr const struct luaL_Reg lkiwi_error_m[] = {
|
constexpr const struct luaL_Reg lkiwi_error_m[] = {
|
||||||
{"__tostring", lkiwi_error_m_tostring},
|
{"__tostring", lkiwi_error_m_tostring},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
int lkiwi_error_mask(lua_State* L) {
|
int lkiwi_error_mask(lua_State* L) {
|
||||||
int invert = lua_toboolean(L, 2);
|
int invert = lua_toboolean(L, 2);
|
||||||
@@ -1254,21 +1237,21 @@ int lkiwi_solver_handle_err(lua_State* L, const KiwiErr* err, const KiwiSolver*
|
|||||||
|
|
||||||
int lkiwi_solver_add_constraint(lua_State* L) {
|
int lkiwi_solver_add_constraint(lua_State* L) {
|
||||||
auto* self = get_solver(L, 1);
|
auto* self = get_solver(L, 1);
|
||||||
auto* c = get_constraint(L, 2);
|
const auto& c = *get_constraint(L, 2);
|
||||||
auto* err = kiwi_solver_add_constraint(self->solver, c);
|
auto* err = kiwi_solver_add_constraint(self->solver, c);
|
||||||
return lkiwi_solver_handle_err(L, err, self);
|
return lkiwi_solver_handle_err(L, err, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_solver_remove_constraint(lua_State* L) {
|
int lkiwi_solver_remove_constraint(lua_State* L) {
|
||||||
auto* self = get_solver(L, 1);
|
auto* self = get_solver(L, 1);
|
||||||
auto* c = get_constraint(L, 2);
|
const auto& c = *get_constraint(L, 2);
|
||||||
auto* err = kiwi_solver_remove_constraint(self->solver, c);
|
auto* err = kiwi_solver_remove_constraint(self->solver, c);
|
||||||
return lkiwi_solver_handle_err(L, err, self);
|
return lkiwi_solver_handle_err(L, err, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_solver_add_edit_var(lua_State* L) {
|
int lkiwi_solver_add_edit_var(lua_State* L) {
|
||||||
auto* self = get_solver(L, 1);
|
auto* self = get_solver(L, 1);
|
||||||
auto* var = get_var(L, 2);
|
const auto& var = *get_var(L, 2);
|
||||||
double strength = luaL_checknumber(L, 3);
|
double strength = luaL_checknumber(L, 3);
|
||||||
auto* err = kiwi_solver_add_edit_var(self->solver, var, strength);
|
auto* err = kiwi_solver_add_edit_var(self->solver, var, strength);
|
||||||
return lkiwi_solver_handle_err(L, err, self);
|
return lkiwi_solver_handle_err(L, err, self);
|
||||||
@@ -1276,14 +1259,14 @@ int lkiwi_solver_add_edit_var(lua_State* L) {
|
|||||||
|
|
||||||
int lkiwi_solver_remove_edit_var(lua_State* L) {
|
int lkiwi_solver_remove_edit_var(lua_State* L) {
|
||||||
auto* self = get_solver(L, 1);
|
auto* self = get_solver(L, 1);
|
||||||
auto* var = get_var(L, 2);
|
const auto& var = *get_var(L, 2);
|
||||||
auto* err = kiwi_solver_remove_edit_var(self->solver, var);
|
auto* err = kiwi_solver_remove_edit_var(self->solver, var);
|
||||||
return lkiwi_solver_handle_err(L, err, self);
|
return lkiwi_solver_handle_err(L, err, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_solver_suggest_value(lua_State* L) {
|
int lkiwi_solver_suggest_value(lua_State* L) {
|
||||||
auto* self = get_solver(L, 1);
|
auto* self = get_solver(L, 1);
|
||||||
auto* var = get_var(L, 2);
|
const auto& var = *get_var(L, 2);
|
||||||
double value = luaL_checknumber(L, 3);
|
double value = luaL_checknumber(L, 3);
|
||||||
auto* err = kiwi_solver_suggest_value(self->solver, var, value);
|
auto* err = kiwi_solver_suggest_value(self->solver, var, value);
|
||||||
return lkiwi_solver_handle_err(L, err, self);
|
return lkiwi_solver_handle_err(L, err, self);
|
||||||
@@ -1301,15 +1284,15 @@ int lkiwi_solver_reset(lua_State* L) {
|
|||||||
|
|
||||||
int lkiwi_solver_has_constraint(lua_State* L) {
|
int lkiwi_solver_has_constraint(lua_State* L) {
|
||||||
auto* s = get_solver(L, 1);
|
auto* s = get_solver(L, 1);
|
||||||
auto* c = get_constraint(L, 2);
|
const auto& c = *get_constraint(L, 2);
|
||||||
lua_pushboolean(L, s->solver.hasConstraint(Constraint(c)));
|
lua_pushboolean(L, s->solver.hasConstraint(c));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_solver_has_edit_var(lua_State* L) {
|
int lkiwi_solver_has_edit_var(lua_State* L) {
|
||||||
auto* s = get_solver(L, 1);
|
auto* s = get_solver(L, 1);
|
||||||
auto* var = get_var(L, 2);
|
const auto& var = *get_var(L, 2);
|
||||||
lua_pushboolean(L, s->solver.hasEditVariable(Variable(var)));
|
lua_pushboolean(L, s->solver.hasEditVariable(var));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1354,26 +1337,26 @@ int lkiwi_add_remove_tab(lua_State* L, F&& fn) {
|
|||||||
|
|
||||||
int lkiwi_solver_add_constraints(lua_State* L) {
|
int lkiwi_solver_add_constraints(lua_State* L) {
|
||||||
return lkiwi_add_remove_tab(L, [](lua_State* L, KiwiSolver* s) {
|
return lkiwi_add_remove_tab(L, [](lua_State* L, KiwiSolver* s) {
|
||||||
return kiwi_solver_add_constraint(s->solver, get_constraint(L, -1));
|
return kiwi_solver_add_constraint(s->solver, *get_constraint(L, -1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_solver_remove_constraints(lua_State* L) {
|
int lkiwi_solver_remove_constraints(lua_State* L) {
|
||||||
return lkiwi_add_remove_tab(L, [](lua_State* L, KiwiSolver* s) {
|
return lkiwi_add_remove_tab(L, [](lua_State* L, KiwiSolver* s) {
|
||||||
return kiwi_solver_add_constraint(s->solver, get_constraint(L, -1));
|
return kiwi_solver_add_constraint(s->solver, *get_constraint(L, -1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_solver_add_edit_vars(lua_State* L) {
|
int lkiwi_solver_add_edit_vars(lua_State* L) {
|
||||||
double strength = luaL_checknumber(L, 3);
|
double strength = luaL_checknumber(L, 3);
|
||||||
return lkiwi_add_remove_tab(L, [strength](lua_State* L, KiwiSolver* s) {
|
return lkiwi_add_remove_tab(L, [strength](lua_State* L, KiwiSolver* s) {
|
||||||
return kiwi_solver_add_edit_var(s->solver, get_var(L, -1), strength);
|
return kiwi_solver_add_edit_var(s->solver, *get_var(L, -1), strength);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
int lkiwi_solver_remove_edit_vars(lua_State* L) {
|
int lkiwi_solver_remove_edit_vars(lua_State* L) {
|
||||||
return lkiwi_add_remove_tab(L, [](lua_State* L, KiwiSolver* s) {
|
return lkiwi_add_remove_tab(L, [](lua_State* L, KiwiSolver* s) {
|
||||||
return kiwi_solver_remove_edit_var(s->solver, get_var(L, -1));
|
return kiwi_solver_remove_edit_var(s->solver, *get_var(L, -1));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1381,10 +1364,11 @@ int lkiwi_solver_suggest_values(lua_State* L) {
|
|||||||
auto* self = get_solver(L, 1);
|
auto* self = get_solver(L, 1);
|
||||||
int narg = lua_gettop(L);
|
int narg = lua_gettop(L);
|
||||||
|
|
||||||
// catch this obnoxious case which is always a bug
|
// block this particularly obnoxious case which is always a bug
|
||||||
if (lua_type(L, 2) == LUA_TSTRING) {
|
if (lua_type(L, 2) == LUA_TSTRING) {
|
||||||
luaL_typeerror(L, 2, "indexable");
|
luaL_typeerror(L, 2, "indexable");
|
||||||
}
|
}
|
||||||
|
// block this particularly obnoxious case which is always a bug
|
||||||
if (lua_type(L, 3) == LUA_TSTRING) {
|
if (lua_type(L, 3) == LUA_TSTRING) {
|
||||||
luaL_typeerror(L, 3, "indexable");
|
luaL_typeerror(L, 3, "indexable");
|
||||||
}
|
}
|
||||||
@@ -1395,7 +1379,7 @@ int lkiwi_solver_suggest_values(lua_State* L) {
|
|||||||
lua_geti(L, 3, i);
|
lua_geti(L, 3, i);
|
||||||
double value = luaL_checknumber(L, -1);
|
double value = luaL_checknumber(L, -1);
|
||||||
|
|
||||||
const KiwiErr* err = kiwi_solver_suggest_value(self->solver, var, value);
|
const KiwiErr* err = kiwi_solver_suggest_value(self->solver, *var, value);
|
||||||
if (err) {
|
if (err) {
|
||||||
error_new(L, err, 1, narg + 1 /* item_absi */);
|
error_new(L, err, 1, narg + 1 /* item_absi */);
|
||||||
unsigned error_mask = self->error_mask;
|
unsigned error_mask = self->error_mask;
|
||||||
@@ -1460,8 +1444,7 @@ constexpr const struct luaL_Reg kiwi_solver_m[] = {
|
|||||||
{"set_error_mask", lkiwi_solver_set_error_mask},
|
{"set_error_mask", lkiwi_solver_set_error_mask},
|
||||||
{"__tostring", lkiwi_solver_m_tostring},
|
{"__tostring", lkiwi_solver_m_tostring},
|
||||||
{"__gc", lkiwi_solver_m_gc},
|
{"__gc", lkiwi_solver_m_gc},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
int lkiwi_solver_new(lua_State* L) {
|
int lkiwi_solver_new(lua_State* L) {
|
||||||
lua_Integer error_mask;
|
lua_Integer error_mask;
|
||||||
@@ -1558,8 +1541,7 @@ constexpr const struct luaL_Reg lkiwi[] = {
|
|||||||
{"eq", lkiwi_eq},
|
{"eq", lkiwi_eq},
|
||||||
{"le", lkiwi_le},
|
{"le", lkiwi_le},
|
||||||
{"ge", lkiwi_ge},
|
{"ge", lkiwi_ge},
|
||||||
{0, 0}
|
{0, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
int no_member_mt_index(lua_State* L) {
|
int no_member_mt_index(lua_State* L) {
|
||||||
luaL_error(L, "attempt to access non-existent member '%s'", lua_tostring(L, 2));
|
luaL_error(L, "attempt to access non-existent member '%s'", lua_tostring(L, 2));
|
||||||
@@ -1580,7 +1562,7 @@ void register_type_n(
|
|||||||
const luaL_Reg* m,
|
const luaL_Reg* m,
|
||||||
size_t mcnt
|
size_t mcnt
|
||||||
) {
|
) {
|
||||||
lua_createtable(L, 0, static_cast<int>(mcnt + 2));
|
lua_createtable(L, 0, mcnt + 2);
|
||||||
lua_pushvalue(L, -2); // no_member_mt
|
lua_pushvalue(L, -2); // no_member_mt
|
||||||
lua_setmetatable(L, -2);
|
lua_setmetatable(L, -2);
|
||||||
lua_pushstring(L, name);
|
lua_pushstring(L, name);
|
||||||
@@ -1623,13 +1605,7 @@ void compat_init(lua_State*, int) {}
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
#if defined __GNUC__ && (!defined _WIN32 || defined __CYGWIN__)
|
extern "C" int luaopen_ckiwi(lua_State* L) {
|
||||||
#define LJKIWI_EXPORT __attribute__((__visibility__("default")))
|
|
||||||
#elif defined _WIN32
|
|
||||||
#define LJKIWI_EXPORT __declspec(dllexport)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern "C" LJKIWI_EXPORT int luaopen_ljkiwi(lua_State* L) {
|
|
||||||
luaL_checkversion(L);
|
luaL_checkversion(L);
|
||||||
|
|
||||||
/* context table */
|
/* context table */
|
||||||
@@ -1637,8 +1613,6 @@ extern "C" LJKIWI_EXPORT int luaopen_ljkiwi(lua_State* L) {
|
|||||||
int ctx_i = lua_gettop(L);
|
int ctx_i = lua_gettop(L);
|
||||||
|
|
||||||
compat_init(L, ctx_i);
|
compat_init(L, ctx_i);
|
||||||
lua_pushliteral(L, "kiwi library memory allocation error");
|
|
||||||
lua_rawseti(L, ctx_i, MEM_ERR_MSG);
|
|
||||||
|
|
||||||
no_member_mt_new(L);
|
no_member_mt_new(L);
|
||||||
register_type(L, "kiwi.Var", ctx_i, VAR, kiwi_var_m);
|
register_type(L, "kiwi.Var", ctx_i, VAR, kiwi_var_m);
|
||||||
|
|||||||
@@ -1,40 +0,0 @@
|
|||||||
rockspec_format = "3.0"
|
|
||||||
package = "kiwi"
|
|
||||||
version = "0.1.0-1"
|
|
||||||
source = {
|
|
||||||
url = "git+https://github.com/jkl1337/ljkiwi",
|
|
||||||
tag = "v0.1.0",
|
|
||||||
}
|
|
||||||
description = {
|
|
||||||
summary = "LuaJIT FFI and Lua binding for the Kiwi constraint solver.",
|
|
||||||
detailed = [[
|
|
||||||
kiwi is a LuaJIT FFI and Lua binding for the Kiwi constraint solver. Kiwi is a fast
|
|
||||||
implementation of the Cassowary constraint solving algorithm. kiwi provides
|
|
||||||
reasonably efficient bindings using the LuaJIT FFI and convential Lua C bindings.]],
|
|
||||||
license = "MIT",
|
|
||||||
issues_url = "https://github.com/jkl1337/ljkiwi/issues",
|
|
||||||
maintainer = "John Luebs",
|
|
||||||
}
|
|
||||||
dependencies = {
|
|
||||||
"lua >= 5.1",
|
|
||||||
}
|
|
||||||
|
|
||||||
build = {
|
|
||||||
type = "make",
|
|
||||||
build_variables = {
|
|
||||||
LUAROCKS = "1",
|
|
||||||
LUA = "$(LUA)",
|
|
||||||
CFLAGS = "$(CFLAGS)",
|
|
||||||
LUA_INCDIR = "$(LUA_INCDIR)",
|
|
||||||
LUA_LIBDIR = "$(LUA_LIBDIR)",
|
|
||||||
LUALIB = "$(LUALIB)",
|
|
||||||
LIBFLAG = "$(LIBFLAG)",
|
|
||||||
LIB_EXT = "$(LIB_EXTENSION)",
|
|
||||||
OBJ_EXT = "$(OBJ_EXTENSION)",
|
|
||||||
},
|
|
||||||
install_variables = {
|
|
||||||
INST_LIBDIR = "$(LIBDIR)",
|
|
||||||
INST_LUADIR = "$(LUADIR)",
|
|
||||||
LIB_EXT = "$(LIB_EXTENSION)",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
32
t.lua
Normal file
32
t.lua
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
|
||||||
|
local c
|
||||||
|
--debug.getupvalue
|
||||||
|
do
|
||||||
|
local v1 = kiwi.Var("v1")
|
||||||
|
local v2 = kiwi.Var("v2")
|
||||||
|
local v3 = kiwi.Var("v3")
|
||||||
|
local v4 = kiwi.Var("v4")
|
||||||
|
local v5 = kiwi.Var("v5")
|
||||||
|
local c1 = (3 * v1 + 4 * v2 + 6 * v3):eq(0)
|
||||||
|
local c2 = (6 * v4 + 4 * v5 + 2 * v1 + 1.4 * v1 / 0.3):le(1000)
|
||||||
|
|
||||||
|
local e = c1:expression()
|
||||||
|
local s = kiwi.Solver()
|
||||||
|
|
||||||
|
s:add_constraints({ c1, c2, c1 })
|
||||||
|
print(s:dumps())
|
||||||
|
end
|
||||||
|
|
||||||
|
-- c = (3 * v1 + 4 * v2 + 6 * v3):eq(0)
|
||||||
|
|
||||||
|
-- local t = c:expression():terms()
|
||||||
|
-- print(t[2].var)
|
||||||
|
|
||||||
|
-- for k, v in ipairs(t) do
|
||||||
|
-- print(k, v.var, v.coefficient)
|
||||||
|
-- end
|
||||||
|
|
||||||
|
-- for k, v in pairs(kiwi.ErrKind) do
|
||||||
|
-- print(k, v)
|
||||||
|
-- end
|
||||||
204
tmp/enaml.lua
Normal file
204
tmp/enaml.lua
Normal file
@@ -0,0 +1,204 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
|
||||||
|
local Var = kiwi.Var
|
||||||
|
|
||||||
|
---@param solver kiwi.Solver
|
||||||
|
local function build_solver(solver)
|
||||||
|
-- create custom strength
|
||||||
|
--
|
||||||
|
local width = Var("width")
|
||||||
|
local height = Var("height")
|
||||||
|
|
||||||
|
local mmedium = kiwi.strength.create(0.0, 1.0, 0.0, 1.25)
|
||||||
|
local smedium = kiwi.strength.create(0.0, 100, 0.0)
|
||||||
|
local left = Var("left")
|
||||||
|
local top = Var("top")
|
||||||
|
local contents_top = Var("contents_top")
|
||||||
|
local contents_bottom = Var("contents_bottom")
|
||||||
|
local contents_left = Var("contents_left")
|
||||||
|
local contents_right = Var("contents_right")
|
||||||
|
local midline = Var("midline")
|
||||||
|
local ctleft = Var("ctleft")
|
||||||
|
local ctheight = Var("ctheight")
|
||||||
|
local cttop = Var("cttop")
|
||||||
|
local ctwidth = Var("ctwidth")
|
||||||
|
local lb1left = Var("lb1left")
|
||||||
|
local lb1height = Var("lb1height")
|
||||||
|
local lb1top = Var("lb1top")
|
||||||
|
local lb1width = Var("lb1width")
|
||||||
|
local lb2left = Var("lb2left")
|
||||||
|
local lb2height = Var("lb2height")
|
||||||
|
local lb2top = Var("lb2top")
|
||||||
|
local lb2width = Var("lb2width")
|
||||||
|
local lb3left = Var("lb3left")
|
||||||
|
local lb3height = Var("lb3height")
|
||||||
|
local lb3top = Var("lb3top")
|
||||||
|
local lb3width = Var("lb3width")
|
||||||
|
local fl1left = Var("fl1left")
|
||||||
|
local fl1height = Var("fl1height")
|
||||||
|
local fl1top = Var("fl1top")
|
||||||
|
local fl1width = Var("fl1width")
|
||||||
|
local fl2left = Var("fl2left")
|
||||||
|
local fl2height = Var("fl2height")
|
||||||
|
local fl2top = Var("fl2top")
|
||||||
|
local fl2width = Var("fl2width")
|
||||||
|
local fl3left = Var("fl3left")
|
||||||
|
local fl3height = Var("fl3height")
|
||||||
|
local fl3top = Var("fl3top")
|
||||||
|
local fl3width = Var("fl3width")
|
||||||
|
|
||||||
|
solver:add_edit_var(width, kiwi.strength.STRONG)
|
||||||
|
solver:add_edit_var(height, kiwi.strength.STRONG)
|
||||||
|
|
||||||
|
local strong, medium, weak = kiwi.strength.STRONG, kiwi.strength.MEDIUM, kiwi.strength.WEAK
|
||||||
|
local constraints = {
|
||||||
|
(left + -0):ge(0),
|
||||||
|
(height + 0):eq(0, medium),
|
||||||
|
(top + -0):ge(0),
|
||||||
|
(width + -0):ge(0),
|
||||||
|
(height + -0):ge(0),
|
||||||
|
(-top + contents_top + -10):eq(0),
|
||||||
|
(lb3height + -16):eq(0, strong),
|
||||||
|
(lb3height + -16):ge(0, strong),
|
||||||
|
(ctleft + -0):ge(0),
|
||||||
|
(cttop + -0):ge(0),
|
||||||
|
(ctwidth + -0):ge(0),
|
||||||
|
(ctheight + -0):ge(0),
|
||||||
|
(fl3left + -0):ge(0),
|
||||||
|
(ctheight + -24):ge(0, smedium),
|
||||||
|
(ctwidth + -1.67772e+07):le(0, smedium),
|
||||||
|
(ctheight + -24):le(0, smedium),
|
||||||
|
(fl3top + -0):ge(0),
|
||||||
|
(fl3width + -0):ge(0),
|
||||||
|
(fl3height + -0):ge(0),
|
||||||
|
(lb1width + -67):eq(0, weak),
|
||||||
|
(lb2width + -0):ge(0),
|
||||||
|
(lb2height + -0):ge(0),
|
||||||
|
(fl2height + -0):ge(0),
|
||||||
|
(lb3left + -0):ge(0),
|
||||||
|
(fl2width + -125):ge(0, strong),
|
||||||
|
(fl2height + -21):eq(0, strong),
|
||||||
|
(fl2height + -21):ge(0, strong),
|
||||||
|
(lb3top + -0):ge(0),
|
||||||
|
(lb3width + -0):ge(0),
|
||||||
|
(fl1left + -0):ge(0),
|
||||||
|
(fl1width + -0):ge(0),
|
||||||
|
(lb1width + -67):ge(0, strong),
|
||||||
|
(fl2left + -0):ge(0),
|
||||||
|
(lb2width + -66):eq(0, weak),
|
||||||
|
(lb2width + -66):ge(0, strong),
|
||||||
|
(lb2height + -16):eq(0, strong),
|
||||||
|
(fl1height + -0):ge(0),
|
||||||
|
(fl1top + -0):ge(0),
|
||||||
|
(lb2top + -0):ge(0),
|
||||||
|
(-lb2top + lb3top + -lb2height + -10):eq(0, mmedium),
|
||||||
|
(-lb3top + -lb3height + fl3top + -10):ge(0),
|
||||||
|
(-lb3top + -lb3height + fl3top + -10):eq(0, mmedium),
|
||||||
|
(contents_bottom + -fl3height + -fl3top + -0):eq(0, mmedium),
|
||||||
|
(fl1top + -contents_top + 0):ge(0),
|
||||||
|
(fl1top + -contents_top + 0):eq(0, mmedium),
|
||||||
|
(contents_bottom + -fl3height + -fl3top + -0):ge(0),
|
||||||
|
(-left + -width + contents_right + 10):eq(0),
|
||||||
|
(-top + -height + contents_bottom + 10):eq(0),
|
||||||
|
(-left + contents_left + -10):eq(0),
|
||||||
|
(lb3left + -contents_left + 0):eq(0, mmedium),
|
||||||
|
(fl1left + -midline + 0):eq(0, strong),
|
||||||
|
(fl2left + -midline + 0):eq(0, strong),
|
||||||
|
(ctleft + -midline + 0):eq(0, strong),
|
||||||
|
(fl1top + 0.5 * fl1height + -lb1top + -0.5 * lb1height + 0):eq(0, strong),
|
||||||
|
(lb1left + -contents_left + 0):ge(0),
|
||||||
|
(lb1left + -contents_left + 0):eq(0, mmedium),
|
||||||
|
(-lb1left + fl1left + -lb1width + -10):ge(0),
|
||||||
|
(-lb1left + fl1left + -lb1width + -10):eq(0, mmedium),
|
||||||
|
(-fl1left + contents_right + -fl1width + -0):ge(0),
|
||||||
|
(width + 0):eq(0, medium),
|
||||||
|
(-fl1top + fl2top + -fl1height + -10):ge(0),
|
||||||
|
(-fl1top + fl2top + -fl1height + -10):eq(0, mmedium),
|
||||||
|
(cttop + -fl2top + -fl2height + -10):ge(0),
|
||||||
|
(-ctheight + -cttop + fl3top + -10):ge(0),
|
||||||
|
(contents_bottom + -fl3height + -fl3top + -0):ge(0),
|
||||||
|
(cttop + -fl2top + -fl2height + -10):eq(0, mmedium),
|
||||||
|
(-fl1left + contents_right + -fl1width + -0):eq(0, mmedium),
|
||||||
|
(-lb2top + -0.5 * lb2height + fl2top + 0.5 * fl2height + 0):eq(0, strong),
|
||||||
|
(-contents_left + lb2left + 0):ge(0),
|
||||||
|
(-contents_left + lb2left + 0):eq(0, mmedium),
|
||||||
|
(fl2left + -lb2width + -lb2left + -10):ge(0),
|
||||||
|
(-ctheight + -cttop + fl3top + -10):eq(0, mmedium),
|
||||||
|
(contents_bottom + -fl3height + -fl3top + -0):eq(0, mmedium),
|
||||||
|
(lb1top + -0):ge(0),
|
||||||
|
(lb1width + -0):ge(0),
|
||||||
|
(lb1height + -0):ge(0),
|
||||||
|
(fl2left + -lb2width + -lb2left + -10):eq(0, mmedium),
|
||||||
|
(-fl2left + -fl2width + contents_right + -0):eq(0, mmedium),
|
||||||
|
(-fl2left + -fl2width + contents_right + -0):ge(0),
|
||||||
|
(lb3left + -contents_left + 0):ge(0),
|
||||||
|
(lb1left + -0):ge(0),
|
||||||
|
(0.5 * ctheight + cttop + -lb3top + -0.5 * lb3height + 0):eq(0, strong),
|
||||||
|
(ctleft + -lb3left + -lb3width + -10):ge(0),
|
||||||
|
(-ctwidth + -ctleft + contents_right + -0):ge(0),
|
||||||
|
(ctleft + -lb3left + -lb3width + -10):eq(0, mmedium),
|
||||||
|
(fl3left + -contents_left + 0):ge(0),
|
||||||
|
(fl3left + -contents_left + 0):eq(0, mmedium),
|
||||||
|
(-ctwidth + -ctleft + contents_right + -0):eq(0, mmedium),
|
||||||
|
(-fl3left + contents_right + -fl3width + -0):eq(0, mmedium),
|
||||||
|
(-contents_top + lb1top + 0):ge(0),
|
||||||
|
(-contents_top + lb1top + 0):eq(0, mmedium),
|
||||||
|
(-fl3left + contents_right + -fl3width + -0):ge(0),
|
||||||
|
(lb2top + -lb1top + -lb1height + -10):ge(0),
|
||||||
|
(-lb2top + lb3top + -lb2height + -10):ge(0),
|
||||||
|
(lb2top + -lb1top + -lb1height + -10):eq(0, mmedium),
|
||||||
|
(fl1height + -21):eq(0, strong),
|
||||||
|
(fl1height + -21):ge(0, strong),
|
||||||
|
(lb2left + -0):ge(0),
|
||||||
|
(lb2height + -16):ge(0, strong),
|
||||||
|
(fl2top + -0):ge(0),
|
||||||
|
(fl2width + -0):ge(0),
|
||||||
|
(lb1height + -16):ge(0, strong),
|
||||||
|
(lb1height + -16):eq(0, strong),
|
||||||
|
(fl3width + -125):ge(0, strong),
|
||||||
|
(fl3height + -21):eq(0, strong),
|
||||||
|
(fl3height + -21):ge(0, strong),
|
||||||
|
(lb3height + -0):ge(0),
|
||||||
|
(ctwidth + -119):ge(0, smedium),
|
||||||
|
(lb3width + -24):eq(0, weak),
|
||||||
|
(lb3width + -24):ge(0, strong),
|
||||||
|
(fl1width + -125):ge(0, strong),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, c in ipairs(constraints) do
|
||||||
|
print(c)
|
||||||
|
solver:add_constraint(c)
|
||||||
|
end
|
||||||
|
|
||||||
|
return width, height
|
||||||
|
end
|
||||||
|
|
||||||
|
local function main()
|
||||||
|
local sizes = {
|
||||||
|
{ w = 400, h = 600 },
|
||||||
|
{ w = 600, h = 400 },
|
||||||
|
{ w = 800, h = 1200 },
|
||||||
|
{ w = 1200, h = 800 },
|
||||||
|
{ w = 400, h = 800 },
|
||||||
|
{ w = 800, h = 400 },
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 1, 1 do
|
||||||
|
local solver = kiwi.Solver()
|
||||||
|
|
||||||
|
local width, height = build_solver(solver)
|
||||||
|
|
||||||
|
for _, size in ipairs(sizes) do
|
||||||
|
solver:suggest_value(width, size.w)
|
||||||
|
solver:suggest_value(height, size.h)
|
||||||
|
solver:update_vars()
|
||||||
|
print(width:value(), height:value())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
main()
|
||||||
|
collectgarbage("collect")
|
||||||
|
collectgarbage("collect")
|
||||||
|
collectgarbage("collect")
|
||||||
|
collectgarbage("collect")
|
||||||
90
tmp/ex.lua
Normal file
90
tmp/ex.lua
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
local Var = kiwi.Var
|
||||||
|
|
||||||
|
local Button = setmetatable({}, {
|
||||||
|
__call = function(_, identifier)
|
||||||
|
return setmetatable({
|
||||||
|
left = Var(identifier .. " left"),
|
||||||
|
width = Var(identifier .. " width"),
|
||||||
|
}, {
|
||||||
|
__tostring = function(self)
|
||||||
|
return "Button(" .. self.left:value() .. ", " .. self.width:value() .. ")"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
|
||||||
|
local b1 = Button("b1")
|
||||||
|
local b2 = Button("b2")
|
||||||
|
|
||||||
|
local left_edge = Var("left")
|
||||||
|
local right_edge = Var("width")
|
||||||
|
|
||||||
|
local STRONG = kiwi.Strength.STRONG
|
||||||
|
|
||||||
|
local constraints
|
||||||
|
|
||||||
|
for i = 1, 200 do
|
||||||
|
q = kiwi.Term(left_edge, 2.0)
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, 50, 1 do
|
||||||
|
-- stylua: ignore start
|
||||||
|
constraints = {
|
||||||
|
left_edge :eq(0.0),
|
||||||
|
-- two buttons are the same width
|
||||||
|
b1.width :eq(b2.width),
|
||||||
|
-- button1 starts 50 for the left margin
|
||||||
|
(1.00 * b1.left) :eq(left_edge + 50),
|
||||||
|
-- button2 ends 50 from the right margin
|
||||||
|
right_edge :eq(b2.left + b2.width + 50),
|
||||||
|
-- button2 starts at least 100 from the end of button1. This is the "elastic" constraint
|
||||||
|
b2.left :ge(b1.left + b1.width + 100),
|
||||||
|
-- button1 has a minimum width of 87
|
||||||
|
b1.width :ge(87),
|
||||||
|
-- button1 has a preferred width of 87
|
||||||
|
b1.width :eq(87, STRONG),
|
||||||
|
-- button2 has minimum width of 113
|
||||||
|
b2.width :ge(113),
|
||||||
|
-- button2 has a preferred width of 113
|
||||||
|
b2.width :eq(113, STRONG),
|
||||||
|
}
|
||||||
|
-- stylua: ignore end
|
||||||
|
--
|
||||||
|
k = kiwi.Strength.create(0.0, 1.0, 0.0, 1.25)
|
||||||
|
end
|
||||||
|
local solver = kiwi.Solver()
|
||||||
|
|
||||||
|
for _, c in ipairs(constraints) do
|
||||||
|
print(c)
|
||||||
|
solver:add_constraint(c)
|
||||||
|
end
|
||||||
|
|
||||||
|
solver:update_vars()
|
||||||
|
|
||||||
|
print(b1) -- Button(50, 113)
|
||||||
|
print(b2) -- Button(263, 113)
|
||||||
|
print(left_edge:value()) -- 0
|
||||||
|
print(right_edge:value()) -- 426
|
||||||
|
|
||||||
|
solver:add_edit_var(right_edge, STRONG)
|
||||||
|
solver:suggest_value(right_edge, 500)
|
||||||
|
solver:update_vars()
|
||||||
|
-- solver:dump()
|
||||||
|
-- print(b1) -- Button(50, 113)
|
||||||
|
-- print(b2) -- Button(337, 113)
|
||||||
|
-- print(right_edge:value()) -- 500
|
||||||
|
|
||||||
|
-- print(solver:dumps())
|
||||||
|
|
||||||
|
-- solver = kiwi.Solver()
|
||||||
|
|
||||||
|
-- local trailing = Var("trailing")
|
||||||
|
-- local leading = Var("leading")
|
||||||
|
|
||||||
|
-- solver:add_constraint(kiwi.new_single_constraint(trailing, 86))
|
||||||
|
-- solver:add_constraint(kiwi.new_pair_constraint(trailing, leading, 8.0))
|
||||||
|
-- print(solver:dumps())
|
||||||
|
-- solver:update_vars()
|
||||||
|
-- print(trailing:value()) -- 86
|
||||||
|
-- print(leading:value()) -- 76
|
||||||
28
tmp/ex2.lua
Normal file
28
tmp/ex2.lua
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
|
||||||
|
local Var = kiwi.Var
|
||||||
|
|
||||||
|
local function doit(v, i)
|
||||||
|
v:set(i)
|
||||||
|
end
|
||||||
|
|
||||||
|
local v = Var("fuckit")
|
||||||
|
|
||||||
|
local s = kiwi.Solver()
|
||||||
|
|
||||||
|
local e
|
||||||
|
for i = 1, 1000 do
|
||||||
|
e = kiwi.Expression(5.0, kiwi.Term(v, 3.0), kiwi.Term(v, 2.0))
|
||||||
|
end
|
||||||
|
--local e = (v + 1)
|
||||||
|
|
||||||
|
s:add_constraint(e:eq(100))
|
||||||
|
|
||||||
|
print(v:value())
|
||||||
|
|
||||||
|
s:update_vars()
|
||||||
|
|
||||||
|
v:set_name("fuck")
|
||||||
|
print(v:value())
|
||||||
|
|
||||||
|
s:dump()
|
||||||
49
tmp/ex3.lua
Normal file
49
tmp/ex3.lua
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
local ffi = require("ffi")
|
||||||
|
|
||||||
|
local t
|
||||||
|
local e
|
||||||
|
local strformat = string.format
|
||||||
|
local Strength = kiwi.Strength
|
||||||
|
|
||||||
|
--local bad_str = "-1 v8 + -1 v4 + -1 v2 + -4 v9 + -2 v3 + -1 v6 + -1 v5 + -1 v1 + -2 v7 + -5"
|
||||||
|
-- local b = ""
|
||||||
|
|
||||||
|
function s(self)
|
||||||
|
local ops = {
|
||||||
|
[0] = "<=",
|
||||||
|
">=",
|
||||||
|
"==",
|
||||||
|
}
|
||||||
|
local strengths = {
|
||||||
|
[Strength.REQUIRED] = "required",
|
||||||
|
[Strength.STRONG] = "strong",
|
||||||
|
[Strength.MEDIUM] = "medium",
|
||||||
|
[Strength.WEAK] = "weak",
|
||||||
|
}
|
||||||
|
local strength = self:strength()
|
||||||
|
--local e = self:expression()
|
||||||
|
local s = strformat("%s %s %s", "aaa", tostring(self:expression()), tonumber(self:op()))
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, 2000 do
|
||||||
|
local v1 = kiwi.Var("v1")
|
||||||
|
local v2 = kiwi.Var("v2")
|
||||||
|
local v3 = kiwi.Var("v3")
|
||||||
|
local v4 = kiwi.Var("v4")
|
||||||
|
|
||||||
|
local v5 = kiwi.Var("v5")
|
||||||
|
local v6 = kiwi.Var("v6")
|
||||||
|
local v7 = kiwi.Var("v7")
|
||||||
|
local v8 = kiwi.Var("v8")
|
||||||
|
local v9 = kiwi.Var("v9")
|
||||||
|
local v10 = kiwi.Var("v9")
|
||||||
|
|
||||||
|
do
|
||||||
|
--
|
||||||
|
local c = ((-(v1 + v2 + 2 * v3 + v4 + 3)):eq(v5 + v6 + 2 * v7 + v8 + 4 * v9 + 3))
|
||||||
|
s(c)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print(t)
|
||||||
37
tmp/ex4.lua
Normal file
37
tmp/ex4.lua
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
local ffi = require("ffi")
|
||||||
|
|
||||||
|
local Var = kiwi.Var
|
||||||
|
|
||||||
|
local v1 = Var("v1")
|
||||||
|
local v2 = Var("v2")
|
||||||
|
local v3 = Var("v3")
|
||||||
|
local v4 = Var("v4")
|
||||||
|
local v5 = Var("v5")
|
||||||
|
local v6 = Var("v6")
|
||||||
|
|
||||||
|
local f1 = kiwi.f1
|
||||||
|
local f2 = kiwi.f2
|
||||||
|
|
||||||
|
local single = kiwi.constraints.single
|
||||||
|
|
||||||
|
local function execute_times(f, times)
|
||||||
|
local begin = os.clock()
|
||||||
|
for _ = 1, times do
|
||||||
|
f()
|
||||||
|
end
|
||||||
|
local finish = os.clock()
|
||||||
|
return finish - begin
|
||||||
|
end
|
||||||
|
|
||||||
|
local t = execute_times(function()
|
||||||
|
return kiwi.constraints.pair_ratio(v1, 2.0, v2, 3.0)
|
||||||
|
end, 6000000)
|
||||||
|
|
||||||
|
print(t)
|
||||||
|
|
||||||
|
-- local t = execute_times(function()
|
||||||
|
-- return pair_ratio2(v1, 2.0, v2, 3.0)
|
||||||
|
-- end, 2000000)
|
||||||
|
|
||||||
|
-- print(t)
|
||||||
41
tmp/ex5.lua
Normal file
41
tmp/ex5.lua
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
|
||||||
|
local Var = kiwi.Var
|
||||||
|
|
||||||
|
x1 = Var("x1")
|
||||||
|
x2 = Var("x2")
|
||||||
|
xm = Var("xm")
|
||||||
|
|
||||||
|
local constraints = { x1:ge(0), x2:le(100), x2:ge(x1 + 10), xm:eq((x1 + x2) / 2) }
|
||||||
|
|
||||||
|
local solver = kiwi.Solver()
|
||||||
|
|
||||||
|
for _, c in ipairs(constraints) do
|
||||||
|
solver:add_constraint(c)
|
||||||
|
end
|
||||||
|
|
||||||
|
local c = kiwi.constraints.single(x1, 40, "EQ", kiwi.Strength.WEAK)
|
||||||
|
solver:add_constraint(c)
|
||||||
|
|
||||||
|
constraints[#constraints + 1] = c
|
||||||
|
|
||||||
|
solver:add_edit_var(xm, kiwi.Strength.STRONG)
|
||||||
|
|
||||||
|
solver:suggest_value(xm, 60)
|
||||||
|
|
||||||
|
solver:update_vars()
|
||||||
|
|
||||||
|
print(xm:value(), x1:value(), x2:value())
|
||||||
|
|
||||||
|
for _, c in ipairs(constraints) do
|
||||||
|
print(c, c:violated())
|
||||||
|
end
|
||||||
|
|
||||||
|
solver:suggest_value(xm, 90)
|
||||||
|
solver:update_vars()
|
||||||
|
|
||||||
|
print(xm:value(), x1:value(), x2:value())
|
||||||
|
|
||||||
|
for _, c in ipairs(constraints) do
|
||||||
|
print(c, c:violated())
|
||||||
|
end
|
||||||
26
tmp/t.lua
Normal file
26
tmp/t.lua
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
local k = require("kiwi")
|
||||||
|
|
||||||
|
s = k.Solver()
|
||||||
|
|
||||||
|
--s:set_error_mask({ "KiwiErrUnknownEditVariable" }, false)
|
||||||
|
|
||||||
|
local v1 = k.Var("v1")
|
||||||
|
local v2 = k.Var("v2")
|
||||||
|
local v3 = k.Var("v3")
|
||||||
|
local v4 = k.Var("v4")
|
||||||
|
|
||||||
|
print((2 * v1 - 5 * v2))
|
||||||
|
|
||||||
|
os.exit()
|
||||||
|
local c1 = k.constraints.pair_ratio(v1, -4, v2, 22, "GE", 1000)
|
||||||
|
local c2 = k.constraints.pair_ratio(v3, -6, v4, 29, "LE", 1000)
|
||||||
|
|
||||||
|
local vo = c1:expression():terms()[1].var
|
||||||
|
print(v1 == vo)
|
||||||
|
-- print(v1:name())
|
||||||
|
-- print(v1 * 5)
|
||||||
|
|
||||||
|
local e = k.Expression(6, k.Term(v1, 2), k.Term(v2, 3))
|
||||||
|
--print(e)
|
||||||
|
|
||||||
|
--print(k.strength.MEDIUM)
|
||||||
66
tmp/test.lua
Normal file
66
tmp/test.lua
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
local kiwi = require("kiwi")
|
||||||
|
|
||||||
|
local Var = kiwi.Var
|
||||||
|
local Strength = kiwi.Strength
|
||||||
|
|
||||||
|
local Button_mt = {}
|
||||||
|
|
||||||
|
---@class Button
|
||||||
|
---@field left kiwi.Var
|
||||||
|
---@field width kiwi.Var
|
||||||
|
---@overload fun(identifier: string): Button
|
||||||
|
local Button = setmetatable({}, Button_mt)
|
||||||
|
|
||||||
|
function Button_mt.__call(_, identifier)
|
||||||
|
return setmetatable({
|
||||||
|
left = Var("left" .. identifier),
|
||||||
|
width = Var("width" .. identifier),
|
||||||
|
}, {
|
||||||
|
__index = Button,
|
||||||
|
__tostring = function(self)
|
||||||
|
return "Button(" .. self.left:value() .. ", " .. self.width:value() .. ")"
|
||||||
|
end,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local b1 = Button("b1")
|
||||||
|
local b2 = Button("b2")
|
||||||
|
|
||||||
|
local left_limit = kiwi.Var("left")
|
||||||
|
local right_limit = kiwi.Var("width")
|
||||||
|
|
||||||
|
|
||||||
|
-- stylua: ignore start
|
||||||
|
local constraints = {
|
||||||
|
left_limit :eq( 0 ),
|
||||||
|
b1.width :eq( b2.width ),
|
||||||
|
b1.left :eq( left_limit + 50),
|
||||||
|
right_limit:eq( b2.left + b2.width + 50),
|
||||||
|
b2.left :ge( b1.left + b1.width + 100),
|
||||||
|
|
||||||
|
b1.width :ge( 87 ),
|
||||||
|
b1.width :eq( 87, Strength.STRONG),
|
||||||
|
|
||||||
|
b2.width :ge( 113 ),
|
||||||
|
b2.width :eq( 113, Strength.STRONG),
|
||||||
|
}
|
||||||
|
-- stylua: ignore end
|
||||||
|
|
||||||
|
local s = kiwi.Solver()
|
||||||
|
|
||||||
|
for _, c in ipairs(constraints) do
|
||||||
|
s:add_constraint(c)
|
||||||
|
end
|
||||||
|
|
||||||
|
print(constraints[4]:expression())
|
||||||
|
print(constraints[5]:expression())
|
||||||
|
|
||||||
|
kiwi.Constraint(b1.left + 1, "EQ")
|
||||||
|
|
||||||
|
s:update_vars()
|
||||||
|
|
||||||
|
print(b1)
|
||||||
|
print(b2)
|
||||||
|
print(left_limit:value())
|
||||||
|
print(right_limit:value())
|
||||||
|
print(s:dumps())
|
||||||
Reference in New Issue
Block a user