Initial actual commit, awaiting CI
This commit is contained in:
258
ckiwi/ckiwi.cpp
Normal file
258
ckiwi/ckiwi.cpp
Normal file
@@ -0,0 +1,258 @@
|
||||
#include "ckiwi.h"
|
||||
|
||||
#include <kiwi/kiwi.h>
|
||||
|
||||
#include <cstring>
|
||||
|
||||
using namespace kiwi;
|
||||
|
||||
namespace {
|
||||
template<class T, class CS>
|
||||
class alignas(T) SharedRef {
|
||||
private:
|
||||
CS ref_;
|
||||
|
||||
public:
|
||||
T* operator&() {
|
||||
return reinterpret_cast<T*>(&ref_);
|
||||
}
|
||||
|
||||
T* operator->() {
|
||||
return reinterpret_cast<T*>(&ref_);
|
||||
}
|
||||
|
||||
operator T&() {
|
||||
return *reinterpret_cast<T*>(&ref_);
|
||||
}
|
||||
|
||||
operator CS() const {
|
||||
return ref_;
|
||||
}
|
||||
|
||||
T& instance() {
|
||||
return *reinterpret_cast<T*>(&ref_);
|
||||
}
|
||||
|
||||
void destroy() {
|
||||
instance().~T();
|
||||
ref_ = {0};
|
||||
}
|
||||
|
||||
SharedRef<T, CS>(CS ref) : ref_(ref) {}
|
||||
|
||||
template<typename... Args>
|
||||
SharedRef<T, CS>(Args&&... args) {
|
||||
new (&ref_) T(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
static_assert(sizeof(CS) >= sizeof(T), "SharedRef cannot wrap T (size)");
|
||||
};
|
||||
|
||||
using ConstraintRef = SharedRef<Constraint, KiwiConstraintRef>;
|
||||
using VariableRef = SharedRef<Variable, KiwiVarRef>;
|
||||
|
||||
KiwiErr make_error(KiwiErrKind kind, const std::exception& ex) {
|
||||
constexpr auto max_n = sizeof(KiwiErr::message) - 1;
|
||||
const auto n = std::min(std::strlen(ex.what()), max_n);
|
||||
|
||||
KiwiErr err {kind};
|
||||
|
||||
std::memcpy(err.message, ex.what(), n);
|
||||
if (n == max_n)
|
||||
err.message[max_n] = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
KiwiErr make_error(KiwiErrKind kind) {
|
||||
return KiwiErr {kind, {0}};
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline KiwiErr wrap_err(F&& f) {
|
||||
try {
|
||||
f();
|
||||
} catch (const UnsatisfiableConstraint& err) {
|
||||
return make_error(KiwiErrUnsatisfiableConstraint, err);
|
||||
} catch (const UnknownConstraint& err) {
|
||||
return make_error(KiwiErrUnknownConstraint, err);
|
||||
} catch (const DuplicateConstraint& err) {
|
||||
return make_error(KiwiErrDuplicateConstraint, err);
|
||||
} catch (const UnknownEditVariable& err) {
|
||||
return make_error(KiwiErrUnknownEditVariable, err);
|
||||
} catch (const DuplicateEditVariable& err) {
|
||||
return make_error(KiwiErrDuplicateEditVariable, err);
|
||||
} catch (const BadRequiredStrength& err) {
|
||||
return make_error(KiwiErrBadRequiredStrength, err);
|
||||
} catch (const InternalSolverError& err) {
|
||||
return make_error(KiwiErrInternalSolverError, err);
|
||||
} catch (std::bad_alloc&) {
|
||||
return make_error(KiwiErrAlloc);
|
||||
} catch (const std::exception& err) {
|
||||
return make_error(KiwiErrUnknown, err);
|
||||
} catch (...) {
|
||||
return make_error(KiwiErrUnknown);
|
||||
}
|
||||
return make_error(KiwiErrNone);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
extern "C" {
|
||||
|
||||
KiwiVarRef kiwi_var_new(const char* name) {
|
||||
return VariableRef(name);
|
||||
}
|
||||
|
||||
void kiwi_var_del(KiwiVarRef var) {
|
||||
VariableRef(var).destroy();
|
||||
}
|
||||
|
||||
const char* kiwi_var_name(KiwiVarRef var) {
|
||||
return VariableRef(var)->name().c_str();
|
||||
}
|
||||
|
||||
void kiwi_var_set_name(KiwiVarRef var, const char* name) {
|
||||
VariableRef(var)->setName(name);
|
||||
}
|
||||
|
||||
double kiwi_var_value(KiwiVarRef var) {
|
||||
return VariableRef(var)->value();
|
||||
}
|
||||
|
||||
void kiwi_var_set_value(KiwiVarRef var, double value) {
|
||||
VariableRef(var)->setValue(value);
|
||||
}
|
||||
|
||||
int kiwi_var_eq(KiwiVarRef var, KiwiVarRef other) {
|
||||
return VariableRef(var)->equals(VariableRef(other));
|
||||
}
|
||||
|
||||
KiwiConstraintRef kiwi_constraint_new(
|
||||
const KiwiExpression* expression,
|
||||
enum KiwiRelOp op,
|
||||
double strength
|
||||
) {
|
||||
if (strength < 0.0) {
|
||||
strength = kiwi::strength::required;
|
||||
}
|
||||
std::vector<Term> terms;
|
||||
terms.reserve(expression->term_count);
|
||||
|
||||
for (auto* t = expression->terms; t != expression->terms + expression->term_count;
|
||||
++t) {
|
||||
terms.emplace_back(VariableRef(t->var), t->coefficient);
|
||||
}
|
||||
|
||||
return ConstraintRef(
|
||||
Expression(std::move(terms), expression->constant),
|
||||
static_cast<RelationalOperator>(op),
|
||||
strength
|
||||
);
|
||||
}
|
||||
|
||||
void kiwi_constraint_del(KiwiConstraintRef constraint) {
|
||||
ConstraintRef(constraint).destroy();
|
||||
}
|
||||
|
||||
double kiwi_constraint_strength(KiwiConstraintRef constraint) {
|
||||
return ConstraintRef(constraint)->strength();
|
||||
}
|
||||
|
||||
enum KiwiRelOp kiwi_constraint_op(KiwiConstraintRef constraint) {
|
||||
return static_cast<KiwiRelOp>(ConstraintRef(constraint)->op());
|
||||
}
|
||||
|
||||
int kiwi_constraint_violated(KiwiConstraintRef constraint) {
|
||||
return ConstraintRef(constraint)->violated();
|
||||
}
|
||||
|
||||
int kiwi_constraint_expression(
|
||||
KiwiConstraintRef constraint,
|
||||
KiwiExpression* out,
|
||||
int out_size
|
||||
) {
|
||||
const auto& expr = ConstraintRef(constraint).instance().expression();
|
||||
const auto& terms = expr.terms();
|
||||
const int n_terms = terms.size();
|
||||
if (!out || out_size < n_terms)
|
||||
return n_terms;
|
||||
|
||||
auto* p = out->terms;
|
||||
for (const auto& t : terms) {
|
||||
*p = KiwiTerm {VariableRef(t.variable()), t.coefficient()};
|
||||
++p;
|
||||
}
|
||||
out->term_count = p - out->terms;
|
||||
out->constant = expr.constant();
|
||||
|
||||
return n_terms;
|
||||
}
|
||||
|
||||
KiwiSolverRef kiwi_solver_new() {
|
||||
return KiwiSolverRef {new (std::nothrow) Solver()};
|
||||
}
|
||||
|
||||
void kiwi_solver_del(KiwiSolverRef s) {
|
||||
delete reinterpret_cast<Solver*>(s.impl_);
|
||||
}
|
||||
|
||||
KiwiErr kiwi_solver_add_constraint(KiwiSolverRef s, KiwiConstraintRef constraint) {
|
||||
return wrap_err([=]() {
|
||||
reinterpret_cast<Solver*>(s.impl_)->addConstraint(ConstraintRef(constraint));
|
||||
});
|
||||
}
|
||||
|
||||
KiwiErr kiwi_solver_remove_constraint(KiwiSolverRef s, KiwiConstraintRef constraint) {
|
||||
return wrap_err([=]() {
|
||||
reinterpret_cast<Solver*>(s.impl_)->removeConstraint(ConstraintRef(constraint));
|
||||
});
|
||||
}
|
||||
|
||||
int kiwi_solver_has_constraint(KiwiSolverRef s, KiwiConstraintRef constraint) {
|
||||
return reinterpret_cast<Solver*>(s.impl_)->hasConstraint(ConstraintRef(constraint));
|
||||
}
|
||||
|
||||
KiwiErr kiwi_solver_add_edit_var(KiwiSolverRef s, KiwiVarRef var, double strength) {
|
||||
return wrap_err([=]() {
|
||||
reinterpret_cast<Solver*>(s.impl_)->addEditVariable(VariableRef(var), strength);
|
||||
});
|
||||
}
|
||||
|
||||
KiwiErr kiwi_solver_remove_edit_var(KiwiSolverRef s, KiwiVarRef var) {
|
||||
return wrap_err([=]() {
|
||||
reinterpret_cast<Solver*>(s.impl_)->removeEditVariable(VariableRef(var));
|
||||
});
|
||||
}
|
||||
|
||||
int kiwi_solver_has_edit_var(KiwiSolverRef s, KiwiVarRef var) {
|
||||
return reinterpret_cast<Solver*>(s.impl_)->hasEditVariable(VariableRef(var));
|
||||
}
|
||||
|
||||
KiwiErr kiwi_solver_suggest_value(KiwiSolverRef s, KiwiVarRef var, double value) {
|
||||
return wrap_err([=]() {
|
||||
reinterpret_cast<Solver*>(s.impl_)->suggestValue(VariableRef(var), value);
|
||||
});
|
||||
}
|
||||
|
||||
void kiwi_solver_update_vars(KiwiSolverRef s) {
|
||||
reinterpret_cast<Solver*>(s.impl_)->updateVariables();
|
||||
}
|
||||
|
||||
void kiwi_solver_reset(KiwiSolverRef s) {
|
||||
reinterpret_cast<Solver*>(s.impl_)->reset();
|
||||
}
|
||||
|
||||
void kiwi_solver_dump(KiwiSolverRef s) {
|
||||
reinterpret_cast<Solver*>(s.impl_)->dump();
|
||||
}
|
||||
|
||||
char* kiwi_solver_dumps(KiwiSolverRef s, void* (*alloc)(size_t)) {
|
||||
const auto val = reinterpret_cast<Solver*>(s.impl_)->dumps();
|
||||
const auto buf_size = val.size() + 1;
|
||||
auto* buf = static_cast<char*>(alloc ? alloc(buf_size) : malloc(buf_size));
|
||||
if (!buf)
|
||||
return nullptr;
|
||||
std::memcpy(buf, val.c_str(), val.size() + 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
Reference in New Issue
Block a user