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