From 3ab1012ea8c55f82812b5998fd6b4fdf53dea70e Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Mon, 14 Apr 2025 14:00:44 +0200 Subject: Improved C++ API and added info to README --- cpp/nissy.cpp | 293 +++++++++++++++++++++++++++++++--------------------------- 1 file changed, 159 insertions(+), 134 deletions(-) (limited to 'cpp/nissy.cpp') diff --git a/cpp/nissy.cpp b/cpp/nissy.cpp index 7987f6c..ad0eb7c 100644 --- a/cpp/nissy.cpp +++ b/cpp/nissy.cpp @@ -6,6 +6,8 @@ TODO: add more documentation (here and in README.md) #include "./nissy.h" +#include + extern "C" { long long nissy_compose(const char *, const char *, char *); long long nissy_inverse(const char *, char *); @@ -26,191 +28,214 @@ extern "C" { } namespace nissy { - namespace utils { - void fixstr(std::string& str) - { - size_t n = str.find('\0'); - str.resize(n); - } - std::variant - cube_or_error(const char *r, long long e) - { - if (e < 0) - return error_t{e}; - return cube_t{r}; - } + /* Definition of constants with const qualifier */ + const nissflag nissflag::NORMAL{1}; + const nissflag nissflag::INVERSE{2}; + const nissflag nissflag::MIXED{4}; + const nissflag nissflag::LINEAR{3}; + const nissflag nissflag::ALL{7}; + + const error error::OK{0}; + const error error::UNSOLVABLE{-1}; + const error error::INVALID_CUBE{-10}; + const error error::UNSOLVABLE_CUBE{-11}; + const error error::INVALID_MOVES{-20}; + const error error::INVALID_TRANS{-30}; + const error error::INVALID_FORMAT{-40}; + const error error::INVALID_SOLVER{-50}; + const error error::NULL_POINTER{-60}; + const error error::BUFFER_SIZE{-61}; + const error error::DATA{-70}; + const error error::OPTIONS{-80}; + const error error::UNKNOWN{-999}; + + namespace size { + constexpr size_t B32 = 22; + constexpr size_t H48 = 88; + constexpr size_t CUBE_MAX = H48; + constexpr size_t TRANSFORMATION = 12; + constexpr size_t DATAID = 255; + } - std::variant - string_or_error(const char *cstr, long long e) - { - if (e < 0) - return error_t{e}; + bool error::ok() const { return value >= 0; } - std::string str{cstr}; - fixstr(str); - return str; - } + cube::cube() {} - std::function - char_str_fn(std::function f) - { - return [&](const char *cc){ - std::string str{cc}; - f(str); - }; - } - } - - std::variant - compose(const cube_t& cube, const cube_t& permutation) + error cube::move(const std::string& moves) { char result[size::B32]; - - auto error = nissy_compose(cube.value.c_str(), - permutation.value.c_str(), result); - - return utils::cube_or_error(result, error); + long long err = nissy_applymoves( + m_b32.c_str(), moves.c_str(), result); + if (err < 0) + return error{err}; + m_b32 = result; + return error::OK; } - std::variant - inverse(const cube_t& cube) + error cube::transform(const std::string& trans) { char result[size::B32]; - - auto error = nissy_inverse(cube.value.c_str(), result); - - return utils::cube_or_error(result, error); + long long err = nissy_applytrans( + m_b32.c_str(), trans.c_str(), result); + if (err < 0) + return error{err}; + m_b32 = result; + return error::OK; } - std::variant - applymoves(const cube_t& cube, const moves_t& moves) + void cube::invert() { char result[size::B32]; - - auto error = nissy_applymoves(cube.value.c_str(), - moves.value.c_str(), result); - - return utils::cube_or_error(result, error); + nissy_inverse(m_b32.c_str(), result); + m_b32 = result; } - std::variant - applytrans(const cube_t& cube, const trans_t& trans) + void cube::compose(const cube& other) { char result[size::B32]; + nissy_compose( + m_b32.c_str(), other.to_string().c_str(), result); + m_b32 = result; + } - auto error = nissy_applytrans(cube.value.c_str(), - trans.value.c_str(), result); + std::string cube::to_string() const { return m_b32; } - return utils::cube_or_error(result, error); + std::variant + cube::to_string(const std::string& format) const + { + char result[size::CUBE_MAX]; + auto err = nissy_convert("B32", format.c_str(), + m_b32.c_str(), size::CUBE_MAX, result); + if (err < 0) + return error{err}; + else + return result; } - std::variant - convert(const cube_format_t& format_in, - const cube_format_t& format_out, const std::string& cube_string) + std::variant + cube::from_string(const std::string& str) { - char result[size::CUBE_MAX]; + return from_string(str, "B32"); + } - auto error = nissy_convert(format_in.value.c_str(), - format_out.value.c_str(), cube_string.c_str(), - size::CUBE_MAX, result); + std::variant + cube::from_string(const std::string& str, const std::string& format) + { + char result[size::B32]; + cube c; + auto err = nissy_convert(format.c_str(), + "B32", c.m_b32.c_str(), size::B32, result); + if (err < 0) + return error{err}; + c.m_b32 = result; + return c; + } - return utils::string_or_error(result, error); + std::variant + cube::get(long long ep, long long eo, long long cp, long long co) + { + return get(ep, eo, cp, co, "fix"); } - std::variant - getcube(long long ep, long long eo, long long cp, long long co, + std::variant + cube::get(long long ep, long long eo, long long cp, long long co, const std::string& options) { char result[size::B32]; - - auto error = nissy_getcube(ep, eo, cp, co, options.c_str(), - result); - - return utils::cube_or_error(result, error); + cube c; + auto err = nissy_getcube( + ep, eo, cp, co, options.c_str(), result); + if (err < 0) + return error{err}; + c.m_b32 = result; + return c; } - std::variant, error_t> - solverinfo(const solver_t& solver) + error solver::generate_data() { - char dataid[size::DATAID]; - - auto error = nissy_solverinfo(solver.value.c_str(), dataid); - if (error < 0) - return error_t{error}; - - return std::pair{error, dataid}; + data.resize(size); + auto err = nissy_gendata(name.c_str(), + size, reinterpret_cast(data.data())); + return error{err}; } - std::variant - gendata(const solver_t& solver) + void solver::read_data(std::ifstream& ifs) { - char dataid[size::DATAID]; - - auto error = nissy_solverinfo(solver.value.c_str(), dataid); - if (error < 0) - return error_t{error}; - - size_t sz = error; - std::vector buffer(sz); - error = nissy_gendata(solver.value.c_str(), sz, - reinterpret_cast(buffer.data())); - if (error < 0) - return error_t{error}; - - return solver_data_t{buffer}; + data.resize(size); + ifs.read(reinterpret_cast(data.data()), size); } - std::optional - checkdata(const solver_data_t& data) + error solver::check_data() const { - auto error = nissy_checkdata(data.value.size(), - reinterpret_cast(data.value.data())); - - if (error < 0) - return error_t{error}; - return std::nullopt; + auto err = nissy_checkdata(data.size(), + reinterpret_cast(data.data())); + return error{err}; } - std::variant - solve(const cube_t& cube, const solver_t& solver, - nissflag_t niss, unsigned minmoves, unsigned maxmoves, - unsigned maxsolutions, int optimal, int threads, - const solver_data_t& data) + void solver::unload_data() { - const size_t len = 3 * (maxmoves+1) * maxsolutions; - char csols[len]; - long long cstats[size::SOLVE_STATS]; - - auto error = nissy_solve(cube.value.c_str(), - solver.value.c_str(), niss.value, minmoves, maxmoves, - maxsolutions, optimal, threads, data.value.size(), - reinterpret_cast(data.value.data()), - len, csols, cstats); + data.resize(0); + } - if (error < 0) - return error_t{error}; + solver::solve_result + solver::solve(const cube& cube, nissflag niss, unsigned minmoves, + unsigned maxmoves, unsigned maxsols, int optimal, int threads) + { + const size_t len = 3 * (maxmoves+1) * maxsols; + std::vector csols(len); + solver::solve_result result; + + auto err = nissy_solve(cube.to_string().c_str(), + name.c_str(), niss.value, minmoves, maxmoves, maxsols, + optimal, threads, data.size(), + reinterpret_cast(data.data()), len, + csols.data(), result.stats.data()); + result.err = error{err}; + + if (err < 0) + return result; + + // TODO: is this special case actually needed? Remove if not + if (err == 0) { + result.solutions = {}; + return result; + } - std::vector sols; - std::string_view strsols(csols); + std::string_view strsols(csols.data()); for (auto r : strsols | std::views::split('\n')) - sols.push_back(std::string{r.begin(), r.end()}); + if (r.begin() != r.end()) + result.solutions.push_back( + std::string{r.begin(), r.end()}); - return solve_result_t{sols, std::to_array(cstats)}; + return result; } - std::variant - countmoves(const moves_t& moves) + std::variant solver::get(const std::string& name) + { + char dataid[size::DATAID]; + auto err = nissy_solverinfo(name.c_str(), dataid); + if (err < 0) + return error{err}; + solver s(name); + s.size = (unsigned)err; + s.id = std::string{dataid}; + return s; + } + + solver::solver(const std::string& str) : name{str} {} + + std::variant + count_moves(const std::string& moves) { - auto error = nissy_countmoves(moves.value.c_str()); - if (error < 0) - return error_t{error}; - return (unsigned)error; + auto err = nissy_countmoves(moves.c_str()); + if (err < 0) + return error{err}; + return (unsigned)err; } - void setlogger(std::function log) + void set_logger(const std::function& log) { - nissy_setlogger( - utils::char_str_fn(log).target()); + nissy_setlogger(log.target()); } } -- cgit v1.3