1 #ifndef GAP_HELPER_PNFRE
2 #define GAP_HELPER_PNFRE
3 
4 #include <stdexcept>
5 #include <string>
6 #include <exception>
7 #include <vector>
8 #include <deque>
9 #include <list>
10 
11 // We have to include this to get around problems with the 'extern C' wrapping of src/compiled.h,
12 // which includes gmp, which in C++ mode has some C++ templates.
13 #include "include_gap_headers.hpp"
14 #include "gap_exception.hpp"
15 #include "gap_function.hpp"
16 
17 #include "library/timing.hpp"
18 #include "library/vec1.hpp"
19 #include "library/optional.hpp"
20 
21 
22 namespace GAPdetail
23 {
24 template<typename T>
25 struct GAP_getter
26 { };
27 
28 // Yes, this is useful. It lets someone turn a GAP vector into a
29 // vec1<Obj>, without having to worry about GAP vector functions
30 // any more.
31 template<>
32 struct GAP_getter<Obj>
33 {
isaGAPdetail::GAP_getter34     bool isa(Obj) const
35     { return true; }
36 
operator ()GAPdetail::GAP_getter37     Obj operator()(Obj recval) const
38     { return recval; }
39 };
40 
41 template<>
42 struct GAP_getter<char*>
43 {
isaGAPdetail::GAP_getter44     bool isa(Obj recval) const
45     { return IS_STRING(recval) && IS_STRING_REP(recval); }
46 
operator ()GAPdetail::GAP_getter47     char* operator()(Obj recval) const
48     {
49         if(!isa(recval))
50             throw GAPException("Invalid attempt to read string");
51         return (char*)CHARS_STRING(recval);
52     }
53 };
54 
55 template<>
56 struct GAP_getter<std::string>
57 {
isaGAPdetail::GAP_getter58     bool isa(Obj recval) const
59     { return IS_STRING(recval) && IS_STRING_REP(recval); }
60 
operator ()GAPdetail::GAP_getter61     std::string operator()(Obj recval) const
62     {
63         if(!isa(recval))
64             throw GAPException("Invalid attempt to read string");
65         return std::string((char*)CHARS_STRING(recval));
66     }
67 };
68 
69 
70 template<>
71 struct GAP_getter<bool>
72 {
isaGAPdetail::GAP_getter73     bool isa(Obj recval) const
74     { return (recval == True) || (recval == False); }
75 
operator ()GAPdetail::GAP_getter76     bool operator()(Obj recval) const
77     {
78         if(recval == True)
79             return true;
80         if(recval == False)
81             return false;
82         if(recval == Fail)
83             throw GAPException("Got 'fail' as a Boolean");
84         throw GAPException("Not a bool!");
85     }
86 };
87 
88 
89 template<>
90 struct GAP_getter<int>
91 {
isaGAPdetail::GAP_getter92     bool isa(Obj recval) const
93     { return IS_INTOBJ(recval); }
94 
operator ()GAPdetail::GAP_getter95     int operator()(Obj recval) const
96     {
97         if(!isa(recval))
98             throw GAPException("Invalid attempt to read int");
99         return INT_INTOBJ(recval);
100     }
101 };
102 
103 template<>
104 struct GAP_getter<long>
105 {
isaGAPdetail::GAP_getter106     bool isa(Obj recval) const
107     { return IS_INTOBJ(recval); }
108 
operator ()GAPdetail::GAP_getter109     long operator()(Obj recval) const
110     {
111         if(!isa(recval))
112             throw GAPException("Invalid attempt to read int");
113         return INT_INTOBJ(recval);
114     }
115 };
116 
117 
118 template<typename Con>
fill_container(Obj rec)119 Con fill_container(Obj rec)
120 {
121     if(!(IS_SMALL_LIST(rec)))
122         throw GAPException("Invalid attempt to read list");
123     int len = LEN_LIST(rec);
124 
125     Con v;
126     typedef typename Con::value_type T;
127     GAP_getter<T> getter;
128     for(int i = 1; i <= len; ++i)
129     {
130         v.push_back(getter(ELM_LIST(rec, i)));
131     }
132     return v;
133 }
134 
135 // This case, and next one, handle arrays with and without holes
136 template<typename T>
137 struct GAP_getter<vec1<T> >
138 {
isaGAPdetail::GAP_getter139     bool isa(Obj recval) const
140     { return IS_SMALL_LIST(recval); }
141 
operator ()GAPdetail::GAP_getter142     vec1<T> operator()(Obj rec) const
143     { return fill_container<vec1<T> >(rec); }
144 };
145 
146 template<typename T>
147 struct GAP_getter<std::vector<T> >
148 {
isaGAPdetail::GAP_getter149     bool isa(Obj recval) const
150     { return IS_SMALL_LIST(recval); }
151 
operator ()GAPdetail::GAP_getter152     std::vector<T> operator()(Obj rec) const
153     { return fill_container<std::vector<T> >(rec); }
154 };
155 
156 template<typename T>
157 struct GAP_getter<std::deque<T> >
158 {
isaGAPdetail::GAP_getter159     bool isa(Obj recval) const
160     { return IS_SMALL_LIST(recval); }
161 
operator ()GAPdetail::GAP_getter162     std::deque<T> operator()(Obj rec) const
163     { return fill_container<std::deque<T> >(rec); }
164 };
165 
166 template<typename T>
167 struct GAP_getter<std::list<T> >
168 {
isaGAPdetail::GAP_getter169     bool isa(Obj recval) const
170     { return IS_SMALL_LIST(recval); }
171 
operator ()GAPdetail::GAP_getter172     std::list<T> operator()(Obj rec) const
173     { return fill_container<std::list<T> >(rec); }
174 };
175 
176 
177 template<typename Con, typename T>
178 Con fill_optional_container(Obj rec)
179 {
180   if(!(IS_SMALL_LIST(rec)))
181       throw GAPException("Invalid attempt to read list");
182   int len = LEN_LIST(rec);
183 
184   Con v;
185   GAP_getter<T> getter;
186   for(int i = 1; i <= len; ++i)
187   {
188       if(ISB_LIST(rec, i))
189       { v.push_back(getter(ELM_LIST(rec, i))); }
190       else
191       { v.push_back(optional<T>()); }
192   }
193   return v;
194 }
195 
196 template<typename T, typename U>
197 struct GAP_getter<std::pair<T, U> >
198 {
isaGAPdetail::GAP_getter199     bool isa(Obj recval) const
200     { return IS_SMALL_LIST(recval) && LEN_LIST(recval) == 2; }
201 
operator ()GAPdetail::GAP_getter202     std::pair<T,U> operator()(Obj rec) const
203     {
204       if(!isa(rec))
205         throw GAPException("Invalid attempt to read pair");
206       GAP_getter<T> get_T;
207       GAP_getter<U> get_U;
208       std::pair<T,U> p(get_T(ELM_LIST(rec, 1)), get_U(ELM_LIST(rec, 2)));
209       return p;
210     }
211 };
212 
213 template<typename T>
214 struct GAP_getter<vec1<optional<T> > >
215 {
isaGAPdetail::GAP_getter216     bool isa(Obj recval) const
217     { return IS_SMALL_LIST(recval); }
218 
operator ()GAPdetail::GAP_getter219     vec1<optional<T> > operator()(Obj rec) const
220     { return fill_optional_container<vec1<optional<T> >, T>(rec); }
221 };
222 
223 template<typename T>
224 struct GAP_getter<std::vector<optional<T> > >
225 {
isaGAPdetail::GAP_getter226     bool isa(Obj recval) const
227     { return IS_SMALL_LIST(recval); }
228 
operator ()GAPdetail::GAP_getter229     std::vector<optional<T> > operator()(Obj rec) const
230     { return fill_optional_container<std::vector<optional<T> >, T>(rec); }
231 };
232 
233 template<typename T>
234 struct GAP_getter<std::deque<optional<T> > >
235 {
isaGAPdetail::GAP_getter236     bool isa(Obj recval) const
237     { return IS_SMALL_LIST(recval); }
238 
operator ()GAPdetail::GAP_getter239     std::deque<optional<T> > operator()(Obj rec) const
240     { return fill_optional_container<std::deque<optional<T> >, T>(rec); }
241 };
242 
243 template<typename T>
244 struct GAP_getter<std::list<optional<T> > >
245 {
isaGAPdetail::GAP_getter246     bool isa(Obj recval) const
247     { return IS_SMALL_LIST(recval); }
248 
operator ()GAPdetail::GAP_getter249     std::list<optional<T> > operator()(Obj rec) const
250     { return fill_optional_container<std::list<optional<T> >, T>(rec); }
251 };
252 
253 
254 }
255 
256 template<typename T>
GAP_get(Obj rec)257 T GAP_get(Obj rec)
258 {
259     GAPdetail::GAP_getter<T> getter;
260     return getter(rec);
261 }
262 
263 template<typename T>
GAP_isa(Obj rec)264 bool GAP_isa(Obj rec)
265 {
266   GAPdetail::GAP_getter<T> getter;
267   return getter.isa(rec);
268 }
269 
GAP_has_rec(Obj rec,UInt n)270 bool GAP_has_rec(Obj rec, UInt n)
271 {
272     if(!IS_REC(rec))
273         throw GAPException("Invalid attempt to read record");
274     return ISB_REC(rec, n);
275 }
276 
GAP_get_rec(Obj rec,UInt n)277 Obj GAP_get_rec(Obj rec, UInt n)
278 {
279     if(!IS_REC(rec))
280         throw GAPException("Invalid attempt to read record");
281     if(!ISB_REC(rec, n))
282         throw GAPException(std::string("Unable to read value from rec"));
283     return ELM_REC(rec, n);
284 }
285 
286 // This is a special method. It gets a boolean from a record, and assumes
287 // it is 'false' if not present
GAP_get_maybe_bool_rec(Obj rec,UInt n)288 bool GAP_get_maybe_bool_rec(Obj rec, UInt n)
289 {
290     if(!IS_REC(rec))
291         throw GAPException("Invalid attempt to read record");
292     if(!ISB_REC(rec, n))
293         return false;
294     Obj b = ELM_REC(rec, n);
295     if(b == True)
296         return true;
297     if(b == False)
298         return false;
299     throw GAPException("Record element is not a boolean");
300 }
301 
302 namespace GAPdetail
303 {
304 template<typename T>
305 struct GAP_maker
306 { };
307 
308 template<>
309 struct GAP_maker<int>
310 {
operator ()GAPdetail::GAP_maker311     Obj operator()(int32_t i)
312     { return INTOBJ_INT(i); }
313 };
314 
315 template<>
316 struct GAP_maker<long>
317 {
operator ()GAPdetail::GAP_maker318     Obj operator()(long i)
319     { return INTOBJ_INT(i); }
320 };
321 
322 template<>
323 struct GAP_maker<bool>
324 {
operator ()GAPdetail::GAP_maker325     Obj operator()(bool b) const
326     {
327         if(b)
328             return True;
329         else
330             return False;
331     }
332 };
333 
334 template<typename T>
335 struct GAP_maker<vec1<T> >
336 {
operator ()GAPdetail::GAP_maker337     Obj operator()(const vec1<T>& v) const
338     {
339         size_t s = v.size();
340         if(s == 0)
341         {
342           Obj l = NEW_PLIST(T_PLIST_EMPTY, 0);
343           SET_LEN_PLIST(l, 0);
344           CHANGED_BAG(l);
345           return l;
346         }
347         Obj list = NEW_PLIST(T_PLIST_DENSE, s);
348         SET_LEN_PLIST(list, s);
349         CHANGED_BAG(list);
350         GAP_maker<T> m;
351         for(int i = 1; i <= v.size(); ++i)
352         {
353             SET_ELM_PLIST(list, i, m(v[i]));
354             CHANGED_BAG(list);
355         }
356 
357         return list;
358     }
359 };
360 
361 template<typename T, typename U>
362 struct GAP_maker<std::pair<T,U> >
363 {
operator ()GAPdetail::GAP_maker364     Obj operator()(const std::pair<T,U>& v) const
365     {
366         Obj list = NEW_PLIST(T_PLIST_DENSE, 2);
367         SET_LEN_PLIST(list, 2);
368 
369         GAP_maker<T> m_t;
370         SET_ELM_PLIST(list, 1, m_t(v.first));
371         CHANGED_BAG(list);
372 
373         GAP_maker<U> m_u;
374         SET_ELM_PLIST(list, 2, m_u(v.second));
375         CHANGED_BAG(list);
376 
377         return list;
378     }
379 };
380 
381 template<typename U>
382 struct GAP_maker<std::map<std::string,U> >
383 {
operator ()GAPdetail::GAP_maker384     Obj operator()(const std::map<std::string,U>& m) const
385     {
386         Obj rec = NEW_PREC(0);
387         for(auto& p : m)
388         {
389             GAP_maker<U> m_u;
390             Obj result = m_u(p.second);
391             AssPRec(rec, RNamName(p.first.c_str()), result);
392             CHANGED_BAG(rec);
393         }
394         return rec;
395     }
396 };
397 
398 }
399 
400 template<typename T>
GAP_make(const T & t)401 Obj GAP_make(const T& t)
402 {
403     GAPdetail::GAP_maker<T> m;
404     return m(t);
405 }
406 
GAP_getGlobal(const char * name)407 Obj GAP_getGlobal(const char* name)
408 {
409     UInt i = GVarName(name);
410     Obj o =  VAL_GVAR(i);
411     if(!o)
412         throw GAPException("Missing global : " + std::string(name));
413     return o;
414 }
415 
416 // We would use CALL_0ARGS and friends here, but in C++
417 // we have to be more explicit with the types of our functions.
GAP_callFunction(GAPFunction fun)418 Obj GAP_callFunction(GAPFunction fun)
419 {
420     timing_start(fun.getName());
421     typedef Obj(*F)(Obj);
422     Obj funobj = fun.getObj();
423     ObjFunc hdlrfunc = HDLR_FUNC(funobj,0);
424     Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj);
425     timing_end(fun.getName());
426     return ret;
427 }
428 
GAP_callFunction(GAPFunction fun,Obj arg1)429 Obj GAP_callFunction(GAPFunction fun, Obj arg1)
430 {
431     timing_start(fun.getName());
432     typedef Obj(*F)(Obj,Obj);
433     Obj funobj = fun.getObj();
434     ObjFunc hdlrfunc = HDLR_FUNC(funobj,1);
435     Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj, arg1);
436     timing_end(fun.getName());
437     return ret;
438 }
439 
GAP_callFunction(GAPFunction fun,Obj arg1,Obj arg2)440 Obj GAP_callFunction(GAPFunction fun, Obj arg1, Obj arg2)
441 {
442     typedef Obj(*F)(Obj,Obj, Obj);
443     timing_start(fun.getName());
444     Obj funobj = fun.getObj();
445     ObjFunc hdlrfunc = HDLR_FUNC(funobj,2);
446     Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj, arg1, arg2);
447     timing_end(fun.getName());
448     return ret;
449 }
450 
GAP_callFunction(GAPFunction fun,Obj arg1,Obj arg2,Obj arg3)451 Obj GAP_callFunction(GAPFunction fun, Obj arg1, Obj arg2, Obj arg3)
452 {
453     typedef Obj(*F)(Obj,Obj, Obj, Obj);
454     timing_start(fun.getName());
455     Obj funobj = fun.getObj();
456     ObjFunc hdlrfunc = HDLR_FUNC(funobj,3);
457     Obj ret = reinterpret_cast<F>(hdlrfunc)(funobj, arg1, arg2, arg3);
458     timing_start(fun.getName());
459     return ret;
460 }
461 
462 struct GAP_convertor
463 {
464     Obj o;
465 
GAP_convertorGAP_convertor466     GAP_convertor(Obj _o) : o(_o) { }
467 
468     template<typename T>
operator TGAP_convertor469     operator T()
470     {
471         if(!GAP_isa<T>(o))
472             throw GAPException("Failed to map GAP object to C++");
473         return GAP_get<T>(o);
474     }
475 };
476 
477 // Register and deregister objects so they do not get garbage collected
478 
479 
GAP_addRef(Obj o)480 void GAP_addRef(Obj o)
481 {
482     static GAPFunction addRef("_YAPB_addRef");
483     GAP_callFunction(addRef, o);
484 }
485 
GAP_checkRef(Obj o)486 bool GAP_checkRef(Obj o)
487 {
488     static GAPFunction checkRef("_YAPB_checkRef");
489     return GAP_get<bool>(GAP_callFunction(checkRef, o));
490 }
491 
GAP_clearRefs()492 void GAP_clearRefs()
493 {
494     static GAPFunction clearRefs("_YAPB_clearRefs");
495     GAP_callFunction(clearRefs);
496 }
497 
GAP_print(const std::string & s)498 void GAP_print(const std::string& s)
499 { Pr(s.c_str(), 0, 0); }
500 
501 #endif
502