15
15
namespace matplotlibcpp {
16
16
17
17
namespace detail {
18
- struct _pyplot_global {
18
+ struct _interpreter {
19
19
PyObject *s_python_function_show;
20
20
PyObject *s_python_function_figure;
21
21
PyObject *s_python_function_plot;
@@ -24,13 +24,20 @@ namespace matplotlibcpp {
24
24
PyObject *s_python_function_ylim;
25
25
PyObject *s_python_empty_tuple;
26
26
27
- static _pyplot_global& get () {
28
- static _pyplot_global ctx;
27
+ /* For now, _interpreter is implemented as a singleton since its currently not possible to have
28
+ multiple independent embedded python interpreters without patching the python source code
29
+ or starting a seperate process for each.
30
+
31
+ http://bytes.com/topic/python/answers/793370-multiple-independent-python-interpreters-c-c-program
32
+ */
33
+
34
+ static _interpreter& get () {
35
+ static _interpreter ctx;
29
36
return ctx;
30
37
}
31
38
32
39
private:
33
- _pyplot_global () {
40
+ _interpreter () {
34
41
char name[] = " plotting" ; // silence compiler warning abount const strings
35
42
Py_SetProgramName (name); // optional but recommended
36
43
Py_Initialize ();
@@ -68,7 +75,7 @@ namespace matplotlibcpp {
68
75
s_python_empty_tuple = PyTuple_New (0 );
69
76
}
70
77
71
- ~_pyplot_global () {
78
+ ~_interpreter () {
72
79
Py_Finalize ();
73
80
}
74
81
};
@@ -105,7 +112,7 @@ namespace matplotlibcpp {
105
112
PyDict_SetItemString (kwargs, it->first .c_str (), PyString_FromString (it->second .c_str ()));
106
113
}
107
114
108
- PyObject* res = PyObject_Call (detail::_pyplot_global ::get ().s_python_function_plot , args, kwargs);
115
+ PyObject* res = PyObject_Call (detail::_interpreter ::get ().s_python_function_plot , args, kwargs);
109
116
110
117
Py_DECREF (args);
111
118
Py_DECREF (kwargs);
@@ -136,7 +143,7 @@ namespace matplotlibcpp {
136
143
PyTuple_SetItem (plot_args, 1 , ylist);
137
144
PyTuple_SetItem (plot_args, 2 , pystring);
138
145
139
- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_plot , plot_args);
146
+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_plot , plot_args);
140
147
141
148
Py_DECREF (xlist);
142
149
Py_DECREF (ylist);
@@ -166,7 +173,7 @@ namespace matplotlibcpp {
166
173
PyTuple_SetItem (plot_args, 1 , ylist);
167
174
PyTuple_SetItem (plot_args, 2 , pystring);
168
175
169
- PyObject* res = PyObject_Call (detail::_pyplot_global ::get ().s_python_function_plot , plot_args, kwargs);
176
+ PyObject* res = PyObject_Call (detail::_interpreter ::get ().s_python_function_plot , plot_args, kwargs);
170
177
171
178
Py_DECREF (kwargs);
172
179
Py_DECREF (xlist);
@@ -205,119 +212,8 @@ namespace matplotlibcpp {
205
212
return named_plot<double >(name,x,y,format);
206
213
}
207
214
208
- #if __cplusplus > 199711L
209
-
210
- template <typename T>
211
- using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
212
-
213
- template <bool obj, typename T>
214
- struct is_callable_impl ;
215
-
216
- template <typename T>
217
- struct is_callable_impl <false , T>
218
- {
219
- typedef is_function<T> type;
220
- }; // a non-object is callable iff it is a function
221
-
222
- template <typename T>
223
- struct is_callable_impl <true , T>
224
- {
225
- struct Fallback { void operator ()(); };
226
- struct Derived : T, Fallback { };
227
-
228
- template <typename U, U> struct Check ;
229
-
230
- template <typename U>
231
- static std::true_type test ( ... ); // use a variadic function to make use (1) it accepts everything and (2) its always the worst match
232
-
233
- template <typename U>
234
- static std::false_type test ( Check<void (Fallback::*)(), &U::operator()>* );
235
-
236
- public:
237
- typedef decltype (test<Derived>(nullptr )) type;
238
- typedef decltype (&Fallback::operator ()) dtype;
239
- static constexpr bool value = type::value;
240
- }; // an object is callable iff it defines operator()
241
-
242
- template <typename T>
243
- struct is_callable
244
- {
245
- // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
246
- typedef typename is_callable_impl<std::is_class<T>::value, T>::type type; // todo: restore remove_reference
247
- };
248
-
249
- template <typename IsYDataCallable>
250
- struct plot_impl { };
251
-
252
- template <>
253
- struct plot_impl <std::false_type>
254
- {
255
- template <typename IterableX, typename IterableY>
256
- bool operator ()(const IterableX& x, const IterableY& y, const std::string& format)
257
- {
258
- // It's annoying that we have to repeat the code of plot() above
259
- auto xs = std::distance (std::begin (x), std::end (x));
260
- auto ys = std::distance (std::begin (y), std::end (y));
261
- assert (xs == ys && " x and y data must have the same number of elements!" );
262
-
263
- PyObject* xlist = PyList_New (xs);
264
- PyObject* ylist = PyList_New (ys);
265
- PyObject* pystring = PyString_FromString (format.c_str ());
266
-
267
- auto itx = std::begin (x), ity = std::begin (y);
268
- for (size_t i = 0 ; i < xs; ++i) {
269
- PyList_SetItem (xlist, i, PyFloat_FromDouble (*itx++));
270
- PyList_SetItem (ylist, i, PyFloat_FromDouble (*ity++));
271
- }
272
-
273
- PyObject* plot_args = PyTuple_New (3 );
274
- PyTuple_SetItem (plot_args, 0 , xlist);
275
- PyTuple_SetItem (plot_args, 1 , ylist);
276
- PyTuple_SetItem (plot_args, 2 , pystring);
277
-
278
- PyObject* res = PyObject_CallObject (detail::_pyplot_global::get ().s_python_function_plot , plot_args);
279
-
280
- Py_DECREF (xlist);
281
- Py_DECREF (ylist);
282
- Py_DECREF (plot_args);
283
- if (res) Py_DECREF (res);
284
-
285
- return res;
286
- }
287
- };
288
-
289
- template <>
290
- struct plot_impl <std::true_type>
291
- {
292
- template <typename Iterable, typename Callable>
293
- bool operator ()(const Iterable& ticks, const Callable& f, const std::string& format)
294
- {
295
- // std::cout << "Callable impl called" << std::endl;
296
-
297
- if (begin (ticks) == end (ticks)) return true ;
298
-
299
- // We could use additional meta-programming to deduce the correct element type of y,
300
- // but all values have to be convertible to double anyways
301
- std::vector<double > y;
302
- for (auto x : ticks) y.push_back (f (x));
303
- return plot_impl<std::false_type>()(ticks,y,format);
304
- }
305
- };
306
-
307
- // recursion stop for the above
308
- template <typename ... Args>
309
- bool plot () { return true ; }
310
-
311
- template <typename A, typename B, typename ... Args>
312
- bool plot (const A& a, const B& b, const std::string& format, Args... args)
313
- {
314
- return plot_impl<typename is_callable<B>::type>()(a,b,format) && plot (args...);
315
- }
316
-
317
- #endif
318
-
319
- inline void legend () {
320
- PyObject* res = PyObject_CallObject (detail::_pyplot_global::get ().s_python_function_legend , detail::_pyplot_global::get ().s_python_empty_tuple );
215
+ inline void legend () {
216
+ PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_legend , detail::_interpreter::get ().s_python_empty_tuple );
321
217
if (!res) throw std::runtime_error (" Call to legend() failed." );
322
218
323
219
Py_DECREF (res);
@@ -333,7 +229,7 @@ namespace matplotlibcpp {
333
229
PyObject* args = PyTuple_New (1 );
334
230
PyTuple_SetItem (args, 0 , list);
335
231
336
- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_ylim , args);
232
+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_ylim , args);
337
233
if (!res) throw std::runtime_error (" Call to ylim() failed." );
338
234
339
235
Py_DECREF (list);
@@ -351,7 +247,7 @@ namespace matplotlibcpp {
351
247
PyObject* args = PyTuple_New (1 );
352
248
PyTuple_SetItem (args, 0 , list);
353
249
354
- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_xlim , args);
250
+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_xlim , args);
355
251
if (!res) throw std::runtime_error (" Call to xlim() failed." );
356
252
357
253
Py_DECREF (list);
@@ -360,11 +256,127 @@ namespace matplotlibcpp {
360
256
}
361
257
362
258
inline void show () {
363
- PyObject* res = PyObject_CallObject (detail::_pyplot_global ::get ().s_python_function_show , detail::_pyplot_global ::get ().s_python_empty_tuple );
259
+ PyObject* res = PyObject_CallObject (detail::_interpreter ::get ().s_python_function_show , detail::_interpreter ::get ().s_python_empty_tuple );
364
260
if (!res) throw std::runtime_error (" Call to show() failed." );
365
261
366
262
Py_DECREF (res);
367
263
}
368
264
265
+ #if __cplusplus > 199711L
266
+ // C++11-exclusive content starts here, in particular the variadic plot()
267
+
268
+ namespace detail {
269
+ template <typename T>
270
+ using is_function = typename std::is_function<std::remove_pointer<std::remove_reference<T>>>::type;
271
+
272
+ template <bool obj, typename T>
273
+ struct is_callable_impl ;
274
+
275
+ template <typename T>
276
+ struct is_callable_impl <false , T>
277
+ {
278
+ typedef is_function<T> type;
279
+ }; // a non-object is callable iff it is a function
280
+
281
+ template <typename T>
282
+ struct is_callable_impl <true , T>
283
+ {
284
+ struct Fallback { void operator ()(); };
285
+ struct Derived : T, Fallback { };
286
+
287
+ template <typename U, U> struct Check ;
288
+
289
+ template <typename U>
290
+ static std::true_type test ( ... ); // use a variadic function to make sure (1) it accepts everything and (2) its always the worst match
291
+
292
+ template <typename U>
293
+ static std::false_type test ( Check<void (Fallback::*)(), &U::operator()>* );
294
+
295
+ public:
296
+ typedef decltype (test<Derived>(nullptr )) type;
297
+ typedef decltype (&Fallback::operator ()) dtype;
298
+ static constexpr bool value = type::value;
299
+ }; // an object is callable iff it defines operator()
300
+
301
+ template <typename T>
302
+ struct is_callable
303
+ {
304
+ // dispatch to is_callable_impl<true, T> or is_callable_impl<false, T> depending on whether T is of class type or not
305
+ typedef typename is_callable_impl<std::is_class<T>::value, T>::type type; // todo: restore remove_reference
306
+ };
307
+
308
+ template <typename IsYDataCallable>
309
+ struct plot_impl { };
310
+
311
+ template <>
312
+ struct plot_impl <std::false_type>
313
+ {
314
+ template <typename IterableX, typename IterableY>
315
+ bool operator ()(const IterableX& x, const IterableY& y, const std::string& format)
316
+ {
317
+ // It's annoying that we have to repeat the code of plot() above
318
+ auto xs = std::distance (std::begin (x), std::end (x));
319
+ auto ys = std::distance (std::begin (y), std::end (y));
320
+ assert (xs == ys && " x and y data must have the same number of elements!" );
321
+
322
+ PyObject* xlist = PyList_New (xs);
323
+ PyObject* ylist = PyList_New (ys);
324
+ PyObject* pystring = PyString_FromString (format.c_str ());
325
+
326
+ auto itx = std::begin (x), ity = std::begin (y);
327
+ for (size_t i = 0 ; i < xs; ++i) {
328
+ PyList_SetItem (xlist, i, PyFloat_FromDouble (*itx++));
329
+ PyList_SetItem (ylist, i, PyFloat_FromDouble (*ity++));
330
+ }
331
+
332
+ PyObject* plot_args = PyTuple_New (3 );
333
+ PyTuple_SetItem (plot_args, 0 , xlist);
334
+ PyTuple_SetItem (plot_args, 1 , ylist);
335
+ PyTuple_SetItem (plot_args, 2 , pystring);
336
+
337
+ PyObject* res = PyObject_CallObject (detail::_interpreter::get ().s_python_function_plot , plot_args);
338
+
339
+ Py_DECREF (xlist);
340
+ Py_DECREF (ylist);
341
+ Py_DECREF (plot_args);
342
+ if (res) Py_DECREF (res);
343
+
344
+ return res;
345
+ }
346
+ };
347
+
348
+ template <>
349
+ struct plot_impl <std::true_type>
350
+ {
351
+ template <typename Iterable, typename Callable>
352
+ bool operator ()(const Iterable& ticks, const Callable& f, const std::string& format)
353
+ {
354
+ // std::cout << "Callable impl called" << std::endl;
355
+
356
+ if (begin (ticks) == end (ticks)) return true ;
357
+
358
+ // We could use additional meta-programming to deduce the correct element type of y,
359
+ // but all values have to be convertible to double anyways
360
+ std::vector<double > y;
361
+ for (auto x : ticks) y.push_back (f (x));
362
+ return plot_impl<std::false_type>()(ticks,y,format);
363
+ }
364
+ };
365
+ }
366
+
367
+ // recursion stop for the above
368
+ template <typename ... Args>
369
+ bool plot () { return true ; }
370
+
371
+ template <typename A, typename B, typename ... Args>
372
+ bool plot (const A& a, const B& b, const std::string& format, Args... args)
373
+ {
374
+ return detail::plot_impl<typename detail::is_callable<B>::type>()(a,b,format) && plot (args...);
375
+ }
376
+
377
+ #endif
378
+
379
+
380
+
369
381
370
382
}
0 commit comments