11/* ******************************************************************************
2- * SOMAR - Stratified Ocean Model with Adaptive Refinement
3- * Developed by Ed Santilli & Alberto Scotti
2+ * PyGlue
3+ * Developed by Alberto Scotti
44 * Copyright (C) 2018
5- * Jefferson (Philadelphia University + Thomas Jefferson University) and
65 * University of North Carolina at Chapel Hill
76 *
87 * This library is free software; you can redistribute it and/or
2120 * USA
2221 *
2322 * For up-to-date contact information, please visit the repository homepage,
24- * https://github.com/somarhub .
23+ * https://github.com/ululi1970/PyGlue .
2524 ******************************************************************************/
2625#ifndef ___PyGlue_H__INCLUDED___
2726#define ___PyGlue_H__INCLUDED___
3938// #include "AMRNSLevel.H"
4039#ifdef CHOMBO
4140#include " FArrayBox.H"
42- #endif
43- #define TYPEtoSTR (X ) \
44- { \
45- if (std::is_same<T, X>::value) \
46- { \
47- return #X; \
48- } \
41+ #endif
42+ // these macros are to be used on arithmetic and string types
43+ // note that the chicanery with the pointer is ok
44+ // since at the end of the day the whole expression
45+ // is evaluated only if X and T are the same type.
46+ #define IFTYPEU (X, Y ) \
47+ { \
48+ if (std::is_same<T, X>::value) \
49+ { \
50+ X s = this ->Y (a_pin); \
51+ void *p = static_cast <void *>(&s); \
52+ T *pr = reinterpret_cast <T *>(p); \
53+ t = *pr; \
54+ return ; \
55+ } \
4956 }
5057
51- // this macro is to be used on arithmetic types
52- #define IFTYPEU (X, Y ) \
53- { \
54- if (std::is_same<T, X>::value) \
55- { \
56- t = static_cast <X>(this ->Y (a_pin)); \
57- return ; \
58- } \
58+ #define IFTYPEP (X, Y ) \
59+ { \
60+ if (std::is_same<T, X>::value) \
61+ { \
62+ \
63+ void *pr = static_cast <void *>(const_cast <T *>(&t)); \
64+ X *p = reinterpret_cast <X *>(pr); \
65+ return this ->Y (*p); \
66+ } \
5967 }
60- #define IFTYPEP ( X, Y ) \
68+ #define TYPEtoSTR ( X ) \
6169 { \
6270 if (std::is_same<T, X>::value) \
6371 { \
64- T x = t; \
65- return this ->Y (static_cast <X>(x)); \
72+ return #X; \
6673 } \
6774 }
75+
6876#define SAME (X ) std::is_same<T, X>::value
6977// The purpose of this class is to be able to run functions on Python
7078// from within a C++ code. The use is
9199
92100#include < array>
93101
94- template <typename > struct PM_traits {
102+ // dark magic used to check if a class as a .size() function.
103+ template <typename ... Ts>
104+ struct make_void
105+ {
106+ typedef void type;
107+ };
108+ template <typename ... Ts>
109+ using void_t = typename make_void<Ts...>::type;
110+ // note the above is not needed if using c++14,
111+ template <typename T, typename = void >
112+ struct has_size_func : std::false_type
113+ {
114+ }; // default to false if third argument cannot work
115+
116+ template <typename T>
117+ struct has_size_func <T, void_t <decltype (std::declval<T &>().size())>> : std::true_type
118+ {
119+ };
120+ // If the instantation of the Expression works, we set it to true, else we default to the false type
121+
122+ /* the following is an alternative version that achieve the same result
123+
124+ // simple routine to test if a class has a member named size of numbytes (or whatever)
125+ // The caveat is that the member has to have a return type for which sizeof()
126+ // must be defined (so this rules out void functions).
127+ //
128+ // example
129+ // ...
130+ // class A{ int size();};
131+ // has_size<A>::value; // this will return TRUE
132+ // has_size<int>::value; // this will return FALSE
133+ //
134+ // It works because when the static member ::value is calculated during
135+ // instantiation, it will try first to use one of the test functions
136+ // with an actual template. Only if those fails because the return value cannot
137+ // be deduced, it will fall back on the default one, which has size M;
138+ // it is possible to specify M if, for some weird reason, you expect
139+ // siaeof(T::size()) to have size equal to 1000;
140+ */
141+ template <typename T, int M = 1000 >
142+ struct has_size
143+ {
144+ private:
145+ typedef char no[M];
146+ template <typename C>
147+ static auto test (C a) -> decltype(std::declval<C>().size());
148+ template <typename >
149+ static no &test (...);
150+
151+ T t;
152+
153+ public:
154+ static const bool value = sizeof (test<T>(t)) != sizeof (no);
95155};
96- template <class T , class U > struct PM_traits <U T::*> {
97- using member_type = U;
98- }; // dark magic used to check if a class as a .size() function.
156+
157+
158+
159+ // So now we have a mechanism to detect Expression
160+
161+ // now we work out the specific expression we need
99162
100163#include " MayDay.H"
101164
102165class Py
103166{
104167private:
105-
106168// forward declarations
107169#ifdef CHOMBO
108- PyObject *packFAB (FArrayBox &a_q);
170+ PyObject *packFAB (FArrayBox &a_q);
109171 PyObject *packFAB (const FArrayBox &a_q);
110- #endif
172+ #endif
111173 PyObject *packDouble (double a_x);
112174 PyObject *packFloat (float a_x);
113175 PyObject *packInt (int a_i);
@@ -121,7 +183,7 @@ PyObject *packFAB(FArrayBox &a_q);
121183
122184 void runVoidFunction (std::string Module, std::string function, std::vector<PyObject *> arg);
123185 PyObject *runFunction (std::string Module, std::string function, std::vector<PyObject *> arg);
124-
186+
125187 enum
126188 {
127189 MULTIPLE_INSTANCES_DETECTED = 0 ,
@@ -165,27 +227,25 @@ PyObject *packFAB(FArrayBox &a_q);
165227 template <class U , class T >
166228 PyObject *makeView (U &a_v)
167229 {
168-
230+
169231 TypeOf<T>(); // will stop compilation if T is not in the list
170-
232+
171233 unsigned long long size = a_v.size () * sizeof (T);
172234 char *p = reinterpret_cast <char *>(&(a_v[0 ]));
173235 return PyMemoryView_FromMemory (p, size, PyBUF_WRITE);
174236 }
175- template <class U , class T >
237+ template <class U , class T >
176238 PyObject *makeView (const U &a_v)
177239 {
178-
240+
179241 TypeOf<T>(); // will stop compilation if T is not in the list
180-
242+
181243 unsigned long long size = a_v.size () * sizeof (T);
182- char *p = reinterpret_cast <char *>(const_cast <T*>(&(a_v[0 ])));
183-
184- return PyMemoryView_FromMemory (p, size, PyBUF_READ);
244+ char *p = reinterpret_cast <char *>(const_cast <T *>(&(a_v[0 ])));
245+
246+ return PyMemoryView_FromMemory (p, size, PyBUF_READ);
185247 }
186-
187-
188-
248+
189249 // basic packing and unpacking template sfor objects that are are passed by reference
190250 template <class T >
191251 void unpack (T &t, PyObject *a_pin)
@@ -197,6 +257,8 @@ template <class U, class T>
197257 IFTYPEU (double , unpackDouble)
198258
199259 IFTYPEU (float , unpackFloat)
260+
261+ IFTYPEU (std::string, unpackString)
200262 this ->lintcatcher (CANNOT_UNPACK_TYPE, " unpack" );
201263 }
202264
@@ -206,11 +268,11 @@ template <class U, class T>
206268 const bool check_type_is_defined = SAME (bool ) || SAME (int ) || SAME (float ) || SAME (std::string) || SAME (double );
207269 static_assert (check_type_is_defined, " Only bool, int, float, double and std::string are supported, but feel free to add to the list and post back" );
208270 T x = t;
209- IFTYPEP (bool ,packBool)
271+ IFTYPEP (bool , packBool)
210272 IFTYPEP (int , packInt)
211273 IFTYPEP (double , packDouble)
212274 IFTYPEP (float , packFloat)
213-
275+ IFTYPEP (std::string, packString)
214276
215277 this ->lintcatcher (CANNOT_PACK_TYPE, " pack" ); // TODO: catch exception at compile time.
216278 return static_cast <PyObject *>(nullptr );
@@ -221,53 +283,51 @@ template <class U, class T>
221283 {
222284 const bool check_type_is_defined = SAME (bool ) || SAME (int ) || SAME (float ) || SAME (std::string) || SAME (double );
223285 static_assert (check_type_is_defined, " Only bool, int, float, double and std::string are supported, but feel free to add to the list and post back" );
224-
225- IFTYPEP (bool ,packBool)
286+
287+ IFTYPEP (bool , packBool)
226288 IFTYPEP (int , packInt)
227289 IFTYPEP (double , packDouble)
228290 IFTYPEP (float , packFloat)
229-
291+ IFTYPEP (std::string, packString)
230292
231293 this ->lintcatcher (CANNOT_PACK_TYPE, " pack" ); // TODO: catch exception at compile time.
232294 return static_cast <PyObject *>(nullptr );
233295 };
234296
235-
236297 template <class U , class T >
237- PyObject* packCont ( U & a_v){
238- PyObject *pView = makeView<U,T>(a_v);
298+ PyObject *packCont (U &a_v)
299+ {
300+ PyObject *pView = makeView<U, T>(a_v);
239301 PyObject *pSize = PyLong_FromLong (a_v.size ());
240302 PyObject *pTypeOfT = PyUnicode_FromString (TypeOf<T>().c_str ());
241303 PyObject *pArgs = PyTuple_New (3 );
242304 PyTuple_SetItem (pArgs, 0 , pSize);
243305 PyTuple_SetItem (pArgs, 1 , pTypeOfT);
244306 PyTuple_SetItem (pArgs, 2 , pView);
245307 return pArgs;
246-
247308 }
248309
249310 template <class U , class T >
250- PyObject* packCont ( const U & a_v){
251- PyObject *pView = makeView<U,T>(a_v);
311+ PyObject *packCont (const U &a_v)
312+ {
313+ PyObject *pView = makeView<U, T>(a_v);
252314 PyObject *pSize = PyLong_FromLong (a_v.size ());
253315 PyObject *pTypeOfT = PyUnicode_FromString (TypeOf<T>().c_str ());
254316 PyObject *pArgs = PyTuple_New (3 );
255317 PyTuple_SetItem (pArgs, 0 , pSize);
256318 PyTuple_SetItem (pArgs, 1 , pTypeOfT);
257319 PyTuple_SetItem (pArgs, 2 , pView);
258320 return pArgs;
259-
260321 }
261322 template <class T >
262- inline PyObject *pack (std::valarray<T> &a_v) { return this ->packCont <std::valarray<T>,T>(a_v); };
323+ inline PyObject *pack (std::valarray<T> &a_v) { return this ->packCont <std::valarray<T>, T>(a_v); };
263324 template <class T >
264- inline PyObject *pack (const std::valarray<T> &a_v) { return this ->packCont <std::valarray<T>,T>(a_v); };
325+ inline PyObject *pack (const std::valarray<T> &a_v) { return this ->packCont <std::valarray<T>, T>(a_v); };
265326 template <class T >
266- inline PyObject *pack (std::vector<T> &a_v) { return this ->packCont <std::vector<T>,T>(a_v); };
327+ inline PyObject *pack (std::vector<T> &a_v) { return this ->packCont <std::vector<T>, T>(a_v); };
267328 template <class T >
268- inline PyObject *pack (const std::vector<T> &a_v) { return this ->packCont <std::vector<T>,T>(a_v); };
269-
270-
329+ inline PyObject *pack (const std::vector<T> &a_v) { return this ->packCont <std::vector<T>, T>(a_v); };
330+
271331 // bottom of recursion
272332 template <class T >
273333 void BuildArgsVector (T &t)
@@ -306,7 +366,7 @@ public:
306366 {
307367 PyObject *return_value = runFunction (Module, function, m_args);
308368 T t;
309- unpack (t, return_value);
369+ unpack<T> (t, return_value);
310370 Py_DECREF (return_value);
311371 return t;
312372 };
@@ -338,31 +398,14 @@ private:
338398// specializations
339399#ifdef CHOMBO
340400template <>
341- inline PyObject *Py::pack (FArrayBox &a_q) { return this ->packFAB (a_q); }; // return an object that Python uses to alias a_q to a numpy
401+ inline PyObject *Py::pack (FArrayBox &a_q)
402+ {
403+ return this ->packFAB (a_q);
404+ }; // return an object that Python uses to alias a_q to a numpy
342405template <>
343406inline PyObject *Py::pack (const FArrayBox &a_q) { return this ->packFAB (a_q); }; // return an object that Python uses to alias a_q to a numpy
344407#endif
345408
346- template <>
347- inline PyObject *Py::pack (std::string &a_s)
348- {
349- std::string s = a_s;
350- return this ->packString (s);
351- };
352-
353- template <>
354- inline PyObject *Py::pack (const std::string &a_s)
355- {
356- std::string s = a_s;
357- return this ->packString (s);
358- };
359-
360- template <>
361- inline void Py::unpack (std::string &a_i, PyObject *a_pin)
362- {
363- a_i = this ->unpackString (a_pin);
364- };
365-
366409 // In the above specializations, we make local copies to mimic the behavior of a function
367410 // that is called by value. Apparently c++11 does not like mixing and matching of
368411 // templates by reference and by value.
0 commit comments