From f7d6bec5a3b79425dab88043a10efad80e26fcb4 Mon Sep 17 00:00:00 2001 From: Sebastiano Tronto Date: Wed, 9 Apr 2025 16:49:51 +0200 Subject: Add an opinionated C++20 adapter --- cpp/nissy.cpp | 216 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ cpp/nissy.h | 133 ++++++++++++++++++++++++++++++++++++ 2 files changed, 349 insertions(+) create mode 100644 cpp/nissy.cpp create mode 100644 cpp/nissy.h (limited to 'cpp') diff --git a/cpp/nissy.cpp b/cpp/nissy.cpp new file mode 100644 index 0000000..7987f6c --- /dev/null +++ b/cpp/nissy.cpp @@ -0,0 +1,216 @@ +/* +C++20 interface for nissy. + +TODO: add more documentation (here and in README.md) +*/ + +#include "./nissy.h" + +extern "C" { + long long nissy_compose(const char *, const char *, char *); + long long nissy_inverse(const char *, char *); + long long nissy_applymoves(const char *, const char *, char *); + long long nissy_applytrans(const char *, const char *, char *); + long long nissy_convert(const char *, const char *, const char *, + unsigned, char *); + long long nissy_getcube(long long, long long, long long, long long, + const char *, char *); + long long nissy_solverinfo(const char *, char *); + long long nissy_gendata(const char *, unsigned long long, char *); + long long nissy_checkdata(unsigned long long, const char *); + long long nissy_solve(const char *, const char *, unsigned, unsigned, + unsigned, unsigned, int, int, unsigned long long, const char *, + unsigned, char *, long long *); + long long nissy_countmoves(const char *); + long long nissy_setlogger(void (*)(const char *)); +} + +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}; + } + + std::variant + string_or_error(const char *cstr, long long e) + { + if (e < 0) + return error_t{e}; + + std::string str{cstr}; + fixstr(str); + return str; + } + + 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) + { + char result[size::B32]; + + auto error = nissy_compose(cube.value.c_str(), + permutation.value.c_str(), result); + + return utils::cube_or_error(result, error); + } + + std::variant + inverse(const cube_t& cube) + { + char result[size::B32]; + + auto error = nissy_inverse(cube.value.c_str(), result); + + return utils::cube_or_error(result, error); + } + + std::variant + applymoves(const cube_t& cube, const moves_t& moves) + { + char result[size::B32]; + + auto error = nissy_applymoves(cube.value.c_str(), + moves.value.c_str(), result); + + return utils::cube_or_error(result, error); + } + + std::variant + applytrans(const cube_t& cube, const trans_t& trans) + { + char result[size::B32]; + + auto error = nissy_applytrans(cube.value.c_str(), + trans.value.c_str(), result); + + return utils::cube_or_error(result, error); + } + + std::variant + convert(const cube_format_t& format_in, + const cube_format_t& format_out, const std::string& cube_string) + { + char result[size::CUBE_MAX]; + + auto error = nissy_convert(format_in.value.c_str(), + format_out.value.c_str(), cube_string.c_str(), + size::CUBE_MAX, result); + + return utils::string_or_error(result, error); + } + + std::variant + getcube(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); + } + + std::variant, error_t> + solverinfo(const solver_t& solver) + { + 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}; + } + + std::variant + gendata(const solver_t& solver) + { + 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}; + } + + std::optional + checkdata(const solver_data_t& data) + { + auto error = nissy_checkdata(data.value.size(), + reinterpret_cast(data.value.data())); + + if (error < 0) + return error_t{error}; + return std::nullopt; + } + + 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) + { + 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); + + if (error < 0) + return error_t{error}; + + std::vector sols; + std::string_view strsols(csols); + for (auto r : strsols | std::views::split('\n')) + sols.push_back(std::string{r.begin(), r.end()}); + + return solve_result_t{sols, std::to_array(cstats)}; + } + + std::variant + countmoves(const moves_t& moves) + { + auto error = nissy_countmoves(moves.value.c_str()); + if (error < 0) + return error_t{error}; + return (unsigned)error; + } + + void setlogger(std::function log) + { + nissy_setlogger( + utils::char_str_fn(log).target()); + } +} diff --git a/cpp/nissy.h b/cpp/nissy.h new file mode 100644 index 0000000..e336c7a --- /dev/null +++ b/cpp/nissy.h @@ -0,0 +1,133 @@ +/* +C++20 header file for nissy. +*/ + +#ifndef NISSY_H +#define NISSY_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace nissy { + /* Some constants for size for I/O buffers */ + 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 SOLVE_STATS = 10; + constexpr size_t DATAID = 255; + } + + /* Some structs definitions for better type safety */ + struct nissflag_t { unsigned value; }; + struct error_t { long long value; }; + struct cube_t { std::string value; }; + struct moves_t { std::string value; }; + struct trans_t { std::string value; }; + struct cube_format_t { std::string value; }; + struct solver_t { std::string value; }; + struct solver_data_t { std::vector value; }; + struct solve_result_t { + std::vector solutions; + std::array stats; + }; + + /* Flags for NISS options */ + namespace nissflag { + constexpr nissflag_t NORMAL{1}; + constexpr nissflag_t INVERSE{2}; + constexpr nissflag_t MIXED{4}; + constexpr nissflag_t LINEAR{NORMAL.value | INVERSE.value}; + constexpr nissflag_t ALL{LINEAR.value | MIXED.value}; + } + + /* Error codes */ + namespace error { + constexpr error_t UNSOLVABLE{-1}; + constexpr error_t INVALID_CUBE{-10}; + constexpr error_t UNSOLVABLE_CUBE{-11}; + constexpr error_t INVALID_MOVES{-20}; + constexpr error_t INVALID_TRANS{-30}; + constexpr error_t INVALID_FORMAT{-40}; + constexpr error_t INVALID_SOLVER{-50}; + constexpr error_t NULL_POINTER{-60}; + constexpr error_t BUFFER_SIZE{-61}; + constexpr error_t DATA{-70}; + constexpr error_t OPTIONS{-80}; + constexpr error_t UNKNOWN{-999}; + } + + /* Cube constants */ + namespace cube { + const cube_t SOLVED{"ABCDEFGH=ABCDEFGHIJKL"}; + } + + std::variant inverse( + const cube_t& cube + ); + + std::variant applymoves( + const cube_t& cube, + const moves_t& moves + ); + + std::variant applytrans( + const cube_t& cube, + const trans_t& trans + ); + + std::variant convert( + const cube_format_t& format_in, + const cube_format_t& format_out, + const std::string& cube_string + ); + + std::variant getcube( + long long ep, + long long eo, + long long cp, + long long co, + const std::string& options + ); + + std::variant, error_t> solverinfo( + const solver_t& solver + ); + + std::variant gendata( + const solver_t& solver + ); + + std::optional checkdata( + const solver_data_t& data + ); + + 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 + ); + + std::variant countmoves( + const moves_t& moves + ); + + void setlogger( + std::function log + ); +} + +#endif -- cgit v1.3