aboutsummaryrefslogtreecommitdiff
path: root/cpp/nissy.cpp
diff options
context:
space:
mode:
authorSebastiano Tronto <sebastiano@tronto.net>2025-04-14 14:00:44 +0200
committerSebastiano Tronto <sebastiano@tronto.net>2025-04-14 14:00:44 +0200
commit3ab1012ea8c55f82812b5998fd6b4fdf53dea70e (patch)
treed18552619a364fcb816d5e2d2331822edd7e2045 /cpp/nissy.cpp
parent7b8c1e4634784b57bb6223cd780d5c67f5381d43 (diff)
downloadnissy-core-3ab1012ea8c55f82812b5998fd6b4fdf53dea70e.tar.gz
nissy-core-3ab1012ea8c55f82812b5998fd6b4fdf53dea70e.zip
Improved C++ API and added info to README
Diffstat (limited to '')
-rw-r--r--cpp/nissy.cpp289
1 files changed, 157 insertions, 132 deletions
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)
6 6
7#include "./nissy.h" 7#include "./nissy.h"
8 8
9#include <fstream>
10
9extern "C" { 11extern "C" {
10 long long nissy_compose(const char *, const char *, char *); 12 long long nissy_compose(const char *, const char *, char *);
11 long long nissy_inverse(const char *, char *); 13 long long nissy_inverse(const char *, char *);
@@ -26,191 +28,214 @@ extern "C" {
26} 28}
27 29
28namespace nissy { 30namespace nissy {
29 namespace utils {
30 void fixstr(std::string& str)
31 {
32 size_t n = str.find('\0');
33 str.resize(n);
34 }
35
36 std::variant<cube_t, error_t>
37 cube_or_error(const char *r, long long e)
38 {
39 if (e < 0)
40 return error_t{e};
41 return cube_t{r};
42 }
43 31
44 std::variant<std::string, error_t> 32 /* Definition of constants with const qualifier */
45 string_or_error(const char *cstr, long long e) 33 const nissflag nissflag::NORMAL{1};
46 { 34 const nissflag nissflag::INVERSE{2};
47 if (e < 0) 35 const nissflag nissflag::MIXED{4};
48 return error_t{e}; 36 const nissflag nissflag::LINEAR{3};
37 const nissflag nissflag::ALL{7};
49 38
50 std::string str{cstr}; 39 const error error::OK{0};
51 fixstr(str); 40 const error error::UNSOLVABLE{-1};
52 return str; 41 const error error::INVALID_CUBE{-10};
53 } 42 const error error::UNSOLVABLE_CUBE{-11};
43 const error error::INVALID_MOVES{-20};
44 const error error::INVALID_TRANS{-30};
45 const error error::INVALID_FORMAT{-40};
46 const error error::INVALID_SOLVER{-50};
47 const error error::NULL_POINTER{-60};
48 const error error::BUFFER_SIZE{-61};
49 const error error::DATA{-70};
50 const error error::OPTIONS{-80};
51 const error error::UNKNOWN{-999};
54 52
55 std::function<void(const char *)> 53 namespace size {
56 char_str_fn(std::function<void(std::string&)> f) 54 constexpr size_t B32 = 22;
57 { 55 constexpr size_t H48 = 88;
58 return [&](const char *cc){ 56 constexpr size_t CUBE_MAX = H48;
59 std::string str{cc}; 57 constexpr size_t TRANSFORMATION = 12;
60 f(str); 58 constexpr size_t DATAID = 255;
61 };
62 }
63 } 59 }
64
65 std::variant<cube_t, error_t>
66 compose(const cube_t& cube, const cube_t& permutation)
67 {
68 char result[size::B32];
69 60
70 auto error = nissy_compose(cube.value.c_str(), 61 bool error::ok() const { return value >= 0; }
71 permutation.value.c_str(), result);
72 62
73 return utils::cube_or_error(result, error); 63 cube::cube() {}
74 }
75 64
76 std::variant<cube_t, error_t> 65 error cube::move(const std::string& moves)
77 inverse(const cube_t& cube)
78 { 66 {
79 char result[size::B32]; 67 char result[size::B32];
80 68 long long err = nissy_applymoves(
81 auto error = nissy_inverse(cube.value.c_str(), result); 69 m_b32.c_str(), moves.c_str(), result);
82 70 if (err < 0)
83 return utils::cube_or_error(result, error); 71 return error{err};
72 m_b32 = result;
73 return error::OK;
84 } 74 }
85 75
86 std::variant<cube_t, error_t> 76 error cube::transform(const std::string& trans)
87 applymoves(const cube_t& cube, const moves_t& moves)
88 { 77 {
89 char result[size::B32]; 78 char result[size::B32];
79 long long err = nissy_applytrans(
80 m_b32.c_str(), trans.c_str(), result);
81 if (err < 0)
82 return error{err};
83 m_b32 = result;
84 return error::OK;
85 }
90 86
91 auto error = nissy_applymoves(cube.value.c_str(), 87 void cube::invert()
92 moves.value.c_str(), result); 88 {
93 89 char result[size::B32];
94 return utils::cube_or_error(result, error); 90 nissy_inverse(m_b32.c_str(), result);
91 m_b32 = result;
95 } 92 }
96 93
97 std::variant<cube_t, error_t> 94 void cube::compose(const cube& other)
98 applytrans(const cube_t& cube, const trans_t& trans)
99 { 95 {
100 char result[size::B32]; 96 char result[size::B32];
97 nissy_compose(
98 m_b32.c_str(), other.to_string().c_str(), result);
99 m_b32 = result;
100 }
101 101
102 auto error = nissy_applytrans(cube.value.c_str(), 102 std::string cube::to_string() const { return m_b32; }
103 trans.value.c_str(), result);
104 103
105 return utils::cube_or_error(result, error); 104 std::variant<std::string, error>
105 cube::to_string(const std::string& format) const
106 {
107 char result[size::CUBE_MAX];
108 auto err = nissy_convert("B32", format.c_str(),
109 m_b32.c_str(), size::CUBE_MAX, result);
110 if (err < 0)
111 return error{err};
112 else
113 return result;
106 } 114 }
107 115
108 std::variant<std::string, error_t> 116 std::variant<cube, error>
109 convert(const cube_format_t& format_in, 117 cube::from_string(const std::string& str)
110 const cube_format_t& format_out, const std::string& cube_string)
111 { 118 {
112 char result[size::CUBE_MAX]; 119 return from_string(str, "B32");
120 }
113 121
114 auto error = nissy_convert(format_in.value.c_str(), 122 std::variant<cube, error>
115 format_out.value.c_str(), cube_string.c_str(), 123 cube::from_string(const std::string& str, const std::string& format)
116 size::CUBE_MAX, result); 124 {
125 char result[size::B32];
126 cube c;
127 auto err = nissy_convert(format.c_str(),
128 "B32", c.m_b32.c_str(), size::B32, result);
129 if (err < 0)
130 return error{err};
131 c.m_b32 = result;
132 return c;
133 }
117 134
118 return utils::string_or_error(result, error); 135 std::variant<cube, error>
136 cube::get(long long ep, long long eo, long long cp, long long co)
137 {
138 return get(ep, eo, cp, co, "fix");
119 } 139 }
120 140
121 std::variant<cube_t, error_t> 141 std::variant<cube, error>
122 getcube(long long ep, long long eo, long long cp, long long co, 142 cube::get(long long ep, long long eo, long long cp, long long co,
123 const std::string& options) 143 const std::string& options)
124 { 144 {
125 char result[size::B32]; 145 char result[size::B32];
126 146 cube c;
127 auto error = nissy_getcube(ep, eo, cp, co, options.c_str(), 147 auto err = nissy_getcube(
128 result); 148 ep, eo, cp, co, options.c_str(), result);
129 149 if (err < 0)
130 return utils::cube_or_error(result, error); 150 return error{err};
151 c.m_b32 = result;
152 return c;
131 } 153 }
132 154
133 std::variant<std::pair<size_t, std::string>, error_t> 155 error solver::generate_data()
134 solverinfo(const solver_t& solver)
135 { 156 {
136 char dataid[size::DATAID]; 157 data.resize(size);
137 158 auto err = nissy_gendata(name.c_str(),
138 auto error = nissy_solverinfo(solver.value.c_str(), dataid); 159 size, reinterpret_cast<char *>(data.data()));
139 if (error < 0) 160 return error{err};
140 return error_t{error};
141
142 return std::pair{error, dataid};
143 } 161 }
144 162
145 std::variant<solver_data_t, error_t> 163 void solver::read_data(std::ifstream& ifs)
146 gendata(const solver_t& solver)
147 { 164 {
148 char dataid[size::DATAID]; 165 data.resize(size);
149 166 ifs.read(reinterpret_cast<char *>(data.data()), size);
150 auto error = nissy_solverinfo(solver.value.c_str(), dataid);
151 if (error < 0)
152 return error_t{error};
153
154 size_t sz = error;
155 std::vector<std::byte> buffer(sz);
156 error = nissy_gendata(solver.value.c_str(), sz,
157 reinterpret_cast<char *>(buffer.data()));
158 if (error < 0)
159 return error_t{error};
160
161 return solver_data_t{buffer};
162 } 167 }
163 168
164 std::optional<error_t> 169 error solver::check_data() const
165 checkdata(const solver_data_t& data)
166 { 170 {
167 auto error = nissy_checkdata(data.value.size(), 171 auto err = nissy_checkdata(data.size(),
168 reinterpret_cast<const char *>(data.value.data())); 172 reinterpret_cast<const char *>(data.data()));
173 return error{err};
174 }
169 175
170 if (error < 0) 176 void solver::unload_data()
171 return error_t{error}; 177 {
172 return std::nullopt; 178 data.resize(0);
173 } 179 }
174 180
175 std::variant<solve_result_t, error_t> 181 solver::solve_result
176 solve(const cube_t& cube, const solver_t& solver, 182 solver::solve(const cube& cube, nissflag niss, unsigned minmoves,
177 nissflag_t niss, unsigned minmoves, unsigned maxmoves, 183 unsigned maxmoves, unsigned maxsols, int optimal, int threads)
178 unsigned maxsolutions, int optimal, int threads,
179 const solver_data_t& data)
180 { 184 {
181 const size_t len = 3 * (maxmoves+1) * maxsolutions; 185 const size_t len = 3 * (maxmoves+1) * maxsols;
182 char csols[len]; 186 std::vector<char> csols(len);
183 long long cstats[size::SOLVE_STATS]; 187 solver::solve_result result;
184 188
185 auto error = nissy_solve(cube.value.c_str(), 189 auto err = nissy_solve(cube.to_string().c_str(),
186 solver.value.c_str(), niss.value, minmoves, maxmoves, 190 name.c_str(), niss.value, minmoves, maxmoves, maxsols,
187 maxsolutions, optimal, threads, data.value.size(), 191 optimal, threads, data.size(),
188 reinterpret_cast<const char *>(data.value.data()), 192 reinterpret_cast<const char *>(data.data()), len,
189 len, csols, cstats); 193 csols.data(), result.stats.data());
194 result.err = error{err};
190 195
191 if (error < 0) 196 if (err < 0)
192 return error_t{error}; 197 return result;
198
199 // TODO: is this special case actually needed? Remove if not
200 if (err == 0) {
201 result.solutions = {};
202 return result;
203 }
193 204
194 std::vector<std::string> sols; 205 std::string_view strsols(csols.data());
195 std::string_view strsols(csols);
196 for (auto r : strsols | std::views::split('\n')) 206 for (auto r : strsols | std::views::split('\n'))
197 sols.push_back(std::string{r.begin(), r.end()}); 207 if (r.begin() != r.end())
208 result.solutions.push_back(
209 std::string{r.begin(), r.end()});
198 210
199 return solve_result_t{sols, std::to_array(cstats)}; 211 return result;
200 } 212 }
201 213
202 std::variant<unsigned, error_t> 214 std::variant<solver, error> solver::get(const std::string& name)
203 countmoves(const moves_t& moves) 215 {
216 char dataid[size::DATAID];
217 auto err = nissy_solverinfo(name.c_str(), dataid);
218 if (err < 0)
219 return error{err};
220 solver s(name);
221 s.size = (unsigned)err;
222 s.id = std::string{dataid};
223 return s;
224 }
225
226 solver::solver(const std::string& str) : name{str} {}
227
228 std::variant<unsigned, error>
229 count_moves(const std::string& moves)
204 { 230 {
205 auto error = nissy_countmoves(moves.value.c_str()); 231 auto err = nissy_countmoves(moves.c_str());
206 if (error < 0) 232 if (err < 0)
207 return error_t{error}; 233 return error{err};
208 return (unsigned)error; 234 return (unsigned)err;
209 } 235 }
210 236
211 void setlogger(std::function<void(std::string&)> log) 237 void set_logger(const std::function<void(const char *)>& log)
212 { 238 {
213 nissy_setlogger( 239 nissy_setlogger(log.target<void(const char *)>());
214 utils::char_str_fn(log).target<void(const char *)>());
215 } 240 }
216} 241}

Generated with cgit - Back to sebastiano.tronto.net