1 // Please refer to the COPYRIGHT file of the profiling package for details.
2 // SPDX-License-Identifier: MIT
3 #ifndef GAP_HELPER_PNFRE
4 #define GAP_HELPER_PNFRE
5
6 #include <stdexcept>
7 #include <string>
8 #include <exception>
9 #include <vector>
10 #include <deque>
11 #include <list>
12 #include <utility>
13 #include <set>
14
15 #include "src/compiled.h" // GAP headers
16
17 #include "gap_prototypes.hpp"
18 #include "gap_exception.hpp"
19 #include "gap_function.hpp"
20 #include "gap_wrapping.hpp"
21
22 #include "vec1.hpp"
23 #include "optional.hpp"
24
25
26 namespace GAPdetail
27 {
28 template<typename T>
29 struct GAP_getter
30 { };
31
32 // Yes, this is useful. It lets someone turn a GAP vector into a
33 // vec1<Obj>, without having to worry about GAP vector functions
34 // any more.
35 template<>
36 struct GAP_getter<Obj>
37 {
isaGAPdetail::GAP_getter38 bool isa(Obj) const
39 { return true; }
40
operator ()GAPdetail::GAP_getter41 Obj operator()(Obj recval) const
42 { return recval; }
43 };
44
45 template<>
46 struct GAP_getter<char*>
47 {
isaGAPdetail::GAP_getter48 bool isa(Obj recval) const
49 { return IS_STRING(recval) && IS_STRING_REP(recval); }
50
operator ()GAPdetail::GAP_getter51 char* operator()(Obj recval) const
52 {
53 if(!isa(recval))
54 throw GAPException("Invalid attempt to read string");
55 return (char*)CHARS_STRING(recval);
56 }
57 };
58
59 template<>
60 struct GAP_getter<std::string>
61 {
isaGAPdetail::GAP_getter62 bool isa(Obj recval) const
63 { return IS_STRING(recval) && IS_STRING_REP(recval); }
64
operator ()GAPdetail::GAP_getter65 std::string operator()(Obj recval) const
66 {
67 if(!isa(recval))
68 throw GAPException("Invalid attempt to read string");
69 return std::string((char*)CHARS_STRING(recval));
70 }
71 };
72
73
74 template<>
75 struct GAP_getter<bool>
76 {
isaGAPdetail::GAP_getter77 bool isa(Obj recval) const
78 { return (recval == True) || (recval == False); }
79
operator ()GAPdetail::GAP_getter80 bool operator()(Obj recval) const
81 {
82 if(recval == True)
83 return true;
84 if(recval == False)
85 return false;
86 if(recval == Fail)
87 throw GAPException("Got 'fail' as a Boolean");
88 throw GAPException("Not a bool!");
89 }
90 };
91
92
93 template<>
94 struct GAP_getter<Int>
95 {
isaGAPdetail::GAP_getter96 bool isa(Obj recval) const
97 { return IS_INTOBJ(recval); }
98
operator ()GAPdetail::GAP_getter99 Int operator()(Obj recval) const
100 {
101 if(!isa(recval))
102 throw GAPException("Invalid attempt to read Int");
103 return INT_INTOBJ(recval);
104 }
105 };
106
107 template<typename Con>
fill_container(Obj rec)108 Con fill_container(Obj rec)
109 {
110 if(!(IS_SMALL_LIST(rec)))
111 throw GAPException("Invalid attempt to read list");
112 int len = LEN_LIST(rec);
113
114 Con v;
115 typedef typename Con::value_type T;
116 GAP_getter<T> getter;
117 for(int i = 1; i <= len; ++i)
118 {
119 v.push_back(getter(ELM_LIST(rec, i)));
120 }
121 return v;
122 }
123
124 template<typename T, typename U>
125 struct GAP_getter<std::pair<T, U> >
126 {
isaGAPdetail::GAP_getter127 bool isa(Obj recval) const
128 { return IS_SMALL_LIST(recval) && LEN_LIST(recval) == 2; }
129
operator ()GAPdetail::GAP_getter130 std::pair<T,U> operator()(Obj rec) const
131 {
132 if(!isa(rec))
133 throw GAPException("Invalid attempt to read pair");
134 GAP_getter<T> get_T;
135 GAP_getter<U> get_U;
136 std::pair<T,U> p(get_T(ELM_LIST(rec, 1)), get_U(ELM_LIST(rec, 2)));
137 return p;
138 }
139 };
140
141 // This case, and next one, handle arrays with and without holes
142 template<typename T>
143 struct GAP_getter<vec1<T> >
144 {
isaGAPdetail::GAP_getter145 bool isa(Obj recval) const
146 { return IS_SMALL_LIST(recval); }
147
operator ()GAPdetail::GAP_getter148 vec1<T> operator()(Obj rec) const
149 { return fill_container<vec1<T> >(rec); }
150 };
151
152 template<typename T>
153 struct GAP_getter<std::vector<T> >
154 {
isaGAPdetail::GAP_getter155 bool isa(Obj recval) const
156 { return IS_SMALL_LIST(recval); }
157
operator ()GAPdetail::GAP_getter158 std::vector<T> operator()(Obj rec) const
159 { return fill_container<std::vector<T> >(rec); }
160 };
161
162
163 template<typename T>
164 struct GAP_getter<std::deque<T> >
165 {
isaGAPdetail::GAP_getter166 bool isa(Obj recval) const
167 { return IS_SMALL_LIST(recval); }
168
operator ()GAPdetail::GAP_getter169 std::deque<T> operator()(Obj rec) const
170 { return fill_container<std::deque<T> >(rec); }
171 };
172
173 template<typename T>
174 struct GAP_getter<std::list<T> >
175 {
isaGAPdetail::GAP_getter176 bool isa(Obj recval) const
177 { return IS_SMALL_LIST(recval); }
178
operator ()GAPdetail::GAP_getter179 std::list<T> operator()(Obj rec) const
180 { return fill_container<std::list<T> >(rec); }
181 };
182
183
184 template<typename Con, typename T>
185 Con fill_optional_container(Obj rec)
186 {
187 if(!(IS_SMALL_LIST(rec)))
188 throw GAPException("Invalid attempt to read list");
189 int len = LEN_LIST(rec);
190
191 Con v;
192 GAP_getter<T> getter;
193 for(int i = 1; i <= len; ++i)
194 {
195 if(ISB_LIST(rec, i))
196 { v.push_back(getter(ELM_LIST(rec, i))); }
197 else
198 { v.push_back(optional<T>()); }
199 }
200 return v;
201 }
202
203 template<typename T>
204 struct GAP_getter<vec1<optional<T> > >
205 {
isaGAPdetail::GAP_getter206 bool isa(Obj recval) const
207 { return IS_SMALL_LIST(recval); }
208
operator ()GAPdetail::GAP_getter209 vec1<optional<T> > operator()(Obj rec) const
210 { return fill_optional_container<vec1<optional<T> >, T>(rec); }
211 };
212
213 template<typename T>
214 struct GAP_getter<std::vector<optional<T> > >
215 {
isaGAPdetail::GAP_getter216 bool isa(Obj recval) const
217 { return IS_SMALL_LIST(recval); }
218
operator ()GAPdetail::GAP_getter219 std::vector<optional<T> > operator()(Obj rec) const
220 { return fill_optional_container<std::vector<optional<T> >, T>(rec); }
221 };
222
223 template<typename T>
224 struct GAP_getter<std::deque<optional<T> > >
225 {
isaGAPdetail::GAP_getter226 bool isa(Obj recval) const
227 { return IS_SMALL_LIST(recval); }
228
operator ()GAPdetail::GAP_getter229 std::deque<optional<T> > operator()(Obj rec) const
230 { return fill_optional_container<std::deque<optional<T> >, T>(rec); }
231 };
232
233 template<typename T>
234 struct GAP_getter<std::list<optional<T> > >
235 {
isaGAPdetail::GAP_getter236 bool isa(Obj recval) const
237 { return IS_SMALL_LIST(recval); }
238
operator ()GAPdetail::GAP_getter239 std::list<optional<T> > operator()(Obj rec) const
240 { return fill_optional_container<std::list<optional<T> >, T>(rec); }
241 };
242
243
244 template<>
245 struct GAP_getter<GAPRecord>
246 {
isaGAPdetail::GAP_getter247 bool isa(Obj recval) const
248 { return IS_REC(recval); }
249
operator ()GAPdetail::GAP_getter250 GAPRecord operator()(Obj rec) const
251 {
252 if(!isa(rec))
253 throw GAPException("Not a record");
254
255 return GAPRecord(rec);
256 }
257 };
258
259 }
260
261 template<typename T>
GAP_get(Obj rec)262 T GAP_get(Obj rec)
263 {
264 GAPdetail::GAP_getter<T> getter;
265 return getter(rec);
266 }
267
268 template<typename T>
GAP_isa(Obj rec)269 bool GAP_isa(Obj rec)
270 {
271 GAPdetail::GAP_getter<T> getter;
272 return getter.isa(rec);
273 }
274
GAP_get_rec(Obj rec,UInt n)275 Obj GAP_get_rec(Obj rec, UInt n)
276 {
277 if(!IS_REC(rec))
278 throw GAPException("Invalid attempt to read record");
279 if(!ISB_REC(rec, n))
280 throw GAPException(std::string("Unable to read value from rec"));
281 return ELM_REC(rec, n);
282 }
283
284 // This is a special method. It gets a boolean from a record, and assumes
285 // it is 'false' if not present
GAP_get_maybe_bool_rec(Obj rec,UInt n)286 bool GAP_get_maybe_bool_rec(Obj rec, UInt n)
287 {
288 if(!IS_REC(rec))
289 throw GAPException("Invalid attempt to read record");
290 if(!ISB_REC(rec, n))
291 return false;
292 Obj b = ELM_REC(rec, n);
293 if(b == True)
294 return true;
295 if(b == False)
296 return false;
297 throw GAPException("Record element is not a boolean");
298 }
299
300 namespace GAPdetail
301 {
302 template<typename T>
303 struct GAP_maker
304 { };
305
306 template<>
307 struct GAP_maker<Int>
308 {
operator ()GAPdetail::GAP_maker309 Obj operator()(Int i)
310 { return INTOBJ_INT(i); }
311 };
312
313 template<>
314 struct GAP_maker<bool>
315 {
operator ()GAPdetail::GAP_maker316 Obj operator()(bool b) const
317 {
318 if(b)
319 return True;
320 else
321 return False;
322 }
323 };
324
325 template<typename T>
CopyContainerToGap(const T & v)326 Obj CopyContainerToGap(const T& v)
327 {
328 size_t s = v.size();
329 if(s == 0)
330 {
331 Obj l = NEW_PLIST(T_PLIST_EMPTY, 0);
332 SET_LEN_PLIST(l, 0);
333 CHANGED_BAG(l);
334 return l;
335 }
336 Obj list = NEW_PLIST(T_PLIST_DENSE, s);
337 SET_LEN_PLIST(list, s);
338 CHANGED_BAG(list);
339 GAP_maker<typename T::value_type> m;
340 int pos = 1;
341 for(typename T::const_iterator it = v.begin(); it != v.end(); ++it, ++pos)
342 {
343 SET_ELM_PLIST(list, pos, m(*it));
344 CHANGED_BAG(list);
345 }
346
347 return list;
348 }
349
350 template<typename T>
351 struct GAP_maker<vec1<T> >
352 {
operator ()GAPdetail::GAP_maker353 Obj operator()(const vec1<T>& v) const
354 {
355 return CopyContainerToGap(v);
356 }
357 };
358
359 template<typename T>
360 struct GAP_maker<std::vector<T> >
361 {
operator ()GAPdetail::GAP_maker362 Obj operator()(const std::vector<T>& v) const
363 {
364 return CopyContainerToGap(v);
365 }
366 };
367
368 template<typename T>
369 struct GAP_maker<std::set<T> >
370 {
operator ()GAPdetail::GAP_maker371 Obj operator()(const std::set<T>& v) const
372 {
373 return CopyContainerToGap(v);
374 }
375 };
376
377 template<>
378 struct GAP_maker<std::string>
379 {
operator ()GAPdetail::GAP_maker380 Obj operator()(const std::string& s) const
381 {
382 Obj o;
383 size_t len = s.length();
384 o = NEW_STRING(len);
385 memcpy(CHARS_STRING(o), s.c_str(), len);
386 return o;
387 }
388 };
389
390 template<typename T, typename U>
391 struct GAP_maker<std::pair<T,U> >
392 {
operator ()GAPdetail::GAP_maker393 Obj operator()(const std::pair<T,U>& v) const
394 {
395 Obj list = NEW_PLIST(T_PLIST_DENSE, 2);
396 SET_LEN_PLIST(list, 2);
397
398 GAP_maker<T> m_t;
399 SET_ELM_PLIST(list, 1, m_t(v.first));
400 CHANGED_BAG(list);
401
402 GAP_maker<U> m_u;
403 SET_ELM_PLIST(list, 2, m_u(v.second));
404 CHANGED_BAG(list);
405
406 return list;
407 }
408 };
409
410 template<>
411 struct GAP_maker<GAPRecord>
412 {
operator ()GAPdetail::GAP_maker413 Obj operator()(GAPRecord r) const
414 { return r.raw_obj(); }
415 };
416
417 }
418
419 template<typename T>
GAP_make(const T & t)420 Obj GAP_make(const T& t)
421 {
422 GAPdetail::GAP_maker<T> m;
423 return m(t);
424 }
425
GAP_getGlobal(const char * name)426 Obj GAP_getGlobal(const char* name)
427 {
428 UInt i = GVarName(name);
429 Obj o = VAL_GVAR(i);
430 if(!o)
431 throw GAPException("Missing global : " + std::string(name));
432 return o;
433 }
434
435 // We would use CALL_0ARGS and friends here, but in C++
436 // we have to be more explicit with the types of our functions.
GAP_callFunction(GAPFunction fun)437 Obj GAP_callFunction(GAPFunction fun)
438 {
439 typedef Obj(*F)(Obj);
440 Obj funobj = fun.getObj();
441 ObjFunc hdlrfunc = HDLR_FUNC(funobj,0);
442 Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj);
443 return ret;
444 }
445
GAP_callFunction(GAPFunction fun,Obj arg1)446 Obj GAP_callFunction(GAPFunction fun, Obj arg1)
447 {
448 typedef Obj(*F)(Obj,Obj);
449 Obj funobj = fun.getObj();
450 ObjFunc hdlrfunc = HDLR_FUNC(funobj,1);
451 Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj, arg1);
452 return ret;
453 }
454
GAP_callFunction(GAPFunction fun,Obj arg1,Obj arg2)455 Obj GAP_callFunction(GAPFunction fun, Obj arg1, Obj arg2)
456 {
457 typedef Obj(*F)(Obj,Obj, Obj);
458 Obj funobj = fun.getObj();
459 ObjFunc hdlrfunc = HDLR_FUNC(funobj,2);
460 Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj, arg1, arg2);
461 return ret;
462 }
463
GAP_callFunction(GAPFunction fun,Obj arg1,Obj arg2,Obj arg3)464 Obj GAP_callFunction(GAPFunction fun, Obj arg1, Obj arg2, Obj arg3)
465 {
466 typedef Obj(*F)(Obj,Obj, Obj, Obj);
467 Obj funobj = fun.getObj();
468 ObjFunc hdlrfunc = HDLR_FUNC(funobj,3);
469 Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj, arg1, arg2, arg3);
470 return ret;
471 }
472
473 struct GAP_convertor
474 {
475 Obj o;
476
GAP_convertorGAP_convertor477 GAP_convertor(Obj _o) : o(_o) { }
478
479 template<typename T>
operator TGAP_convertor480 operator T()
481 {
482 if(!GAP_isa<T>(o))
483 throw GAPException("Failed to map GAP object to C++");
484 return GAP_get<T>(o);
485 }
486 };
487
488 // Register and deregister objects so they do not get garbage collected
489
490
GAP_addRef(Obj o)491 void GAP_addRef(Obj o)
492 {
493 static GAPFunction addRef("_YAPB_addRef");
494 GAP_callFunction(addRef, o);
495 }
496
GAP_checkRef(Obj o)497 bool GAP_checkRef(Obj o)
498 {
499 static GAPFunction checkRef("_YAPB_checkRef");
500 return GAP_get<bool>(GAP_callFunction(checkRef, o));
501 }
502
GAP_clearRefs()503 void GAP_clearRefs()
504 {
505 static GAPFunction clearRefs("_YAPB_clearRefs");
506 GAP_callFunction(clearRefs);
507 }
508
GAP_print(const std::string & s)509 void GAP_print(const std::string& s)
510 { Pr(s.c_str(), 0, 0); }
511
512 #endif
513