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