// Copyright (c) 1998-2000 The Regents of the University of California. // All rights reserved. // // Redistribution and use in source and binary forms are permitted // provided that the above copyright notice and this paragraph are // duplicated in all such forms and that any documentation, // distribution and/or use acknowledge that the software was developed // by the Computer Graphics Laboratory, University of California, // San Francisco. The name of the University may not be used to // endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR // IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED // WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. // IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, // OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE. // $Id: WrapPy2.h 37506 2012-09-25 05:45:02Z gregc $ #ifndef otf_WrapPy_h # define otf_WrapPy_h # ifndef OTF_WRAPPY_DLL # if (__GNUC__ > 4) || (__GNUC__ == 4 && (defined(__APPLE__) || __GNUC_MINOR__ >= 3)) # define OTF_WRAPPY_IMEX __attribute__((__visibility__("default"))) # else # define OTF_WRAPPY_IMEX # endif # elif defined(OTF_WRAPPY_EXPORT) # define OTF_WRAPPY_IMEX __declspec(dllexport) # else # define OTF_WRAPPY_IMEX __declspec(dllimport) # endif // see wrappy's documentation for more details // // _WC is the wrapped C++ class // // A wrapped C++ class, _WC, has an additional base class, WrapPyObj. // The wpyGetObject() member function is used to return an owned Python object. // // Use WrapPyType<_WC>::check(PyObject*) to check if the PyObject is // of the wrapped type (typically WC_objectType). // # define PY_SSIZE_T_CLEAN 1 # include <Python.h> #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) typedef int Py_ssize_t; #define PY_SSIZE_T_MAX INT_MAX #define PY_SSIZE_T_MIN INT_MIN #endif # include <stdexcept> # include <string> # include <vector> # include <list> # include <set> # include <map> # ifdef __APPLE__ // workaround interaction with Python 2.7 header files # undef isspace # undef isupper # undef islower # undef isalpha # undef isalnum # undef tolower # undef toupper # endif # include <iostream> # include "WrapPyFile.h" namespace otf { // like PyNumber_Check, but only check if convertible to int or float, not both extern OTF_WRAPPY_IMEX bool WrapPyInt_Check(PyObject* obj); extern OTF_WRAPPY_IMEX bool WrapPyFloat_Check(PyObject* obj); extern OTF_WRAPPY_IMEX bool WrapPyLong_Check(PyObject* obj); class OTF_WRAPPY_IMEX PythonError: public std::runtime_error { // Throw a PythonError in wrapped functions when a Python error // has occurred, so the Python error will propagate back. public: PythonError(); }; // forward declarations for templates template <class _c> PyObject* pyObject(_c _x); template <class _iterator> PyObject* cvtSequenceToPyList(_iterator _b, _iterator _e); template <class _iterator> PyObject* cvtSequenceToPyTuple(_iterator _b, _iterator _e); template <class _iterator> PyObject* cvtSetToPySet(_iterator _b, _iterator _e); template <class _iterator> PyObject* cvtMapToPyDict(_iterator _b, _iterator _e); template <class _MultiMap> PyObject* cvtMultiMapToPyDict(_MultiMap const& _mm); template <class _iterator> PyObject* cvtMultiMapToPyDict(_iterator _b, _iterator _e); template <class _WC> struct WrapPyType { static bool check(PyObject*, bool noneOk = false); }; enum WrapPyCreate { PWC_DONT_CREATE, PWC_CREATE, PWC_CREATE_AND_OWN }; class OTF_WRAPPY_IMEX WrapPyObj { // use as a non-template base class, so we can dynamic_cast to/from it void operator=(const WrapPyObj&); protected: mutable PyObject* pyObj; mutable bool owner; // true if Python dealloc deletes C++ object public: WrapPyObj(): pyObj(0), owner(false) {} WrapPyObj(const WrapPyObj&): pyObj(0), owner(false) {} PyObject* wpyGetObject(WrapPyCreate pwc = PWC_CREATE) const; virtual PyObject* wpyNew() const = 0; virtual void wpyDisassociate(); // for Python Object's dealloc method virtual void wpyAssociate(PyObject* o) const; bool pyOwned() const { return owner; } void setPyOwned() { owner = true; } virtual ~WrapPyObj(); }; extern "C" { // All Python types for subclasses of WrapPyObj // must have the exact layout as WrapPyObj_object. struct WrapPyObj_object: public PyObject { PyObject* _inst_dict; WrapPyObj* _inst_data; PyObject* _weaklist; }; OTF_WRAPPY_IMEX extern PyTypeObject WrapPyObj_objectType; OTF_WRAPPY_IMEX extern PyTypeObject WrapPyMutable_Type; } // extern "C" // // The pyObject template is for converting C++ types to Python types // # ifdef TODO // Can't specialize function templates yet template <class _c> PyObject* pyObject<_c*>(_c* xp) { if (xp == NULL) { Py_INCREF(Py_None); return Py_None; } return xp->wpyGetObject(); } # endif template <> inline PyObject* pyObject(char _x) { return PyString_FromStringAndSize(&_x, int(_x != '\0')); } template <> inline PyObject* pyObject(bool _x) { PyObject* _o = (_x) ? Py_True : Py_False; Py_INCREF(_o); return _o; } // TODO: figure out how to give optional allocator to std::vector<bool> template <> inline PyObject* pyObject(std::vector<bool>::reference _x) { return PyInt_FromLong(static_cast<long>(_x)); } template <> inline PyObject* pyObject(short _x) { return PyInt_FromLong(static_cast<long>(_x)); } template <> inline PyObject* pyObject(int _x) { return PyInt_FromLong(static_cast<long>(_x)); } template <> inline PyObject* pyObject(long _x) { return PyInt_FromLong(_x); } template <> inline PyObject* pyObject(unsigned long _x) { return PyLong_FromUnsignedLong(_x); } # ifdef HAVE_LONG_LONG template <> inline PyObject* pyObject(long long _x) { return PyLong_FromLongLong(_x); } template <> inline PyObject* pyObject(unsigned long long _x) { return PyLong_FromUnsignedLongLong(_x); } # endif template <> inline PyObject* pyObject(float _x) { return PyFloat_FromDouble(static_cast<double>(_x)); } template <> inline PyObject* pyObject(double _x) { return PyFloat_FromDouble(_x); } template <> inline PyObject* pyObject(char const* _x) { if (_x == NULL) { Py_INCREF(Py_None); return Py_None; } return PyUnicode_Decode(_x, strlen(_x), "utf-8", "replace"); } template <> inline PyObject* pyObject(std::string _x) { return PyUnicode_Decode(_x.data(), _x.size(), "utf-8", "replace"); } template <> inline PyObject* pyObject(const std::string &_x) { return PyUnicode_Decode(_x.data(), _x.size(), "utf-8", "replace"); } template <> inline PyObject* pyObject(PyObject* _x) { Py_XINCREF(_x); return _x; } # if 0 // leave undefined so we get compiler/linkage errors template <> inline PyObject* pyObject(std::istream* _x) { throw std::runtime_error("wrong way"); } template <> inline PyObject* pyObject(std::ostream* _x) { throw std::runtime_error("wrong way"); } # endif template <class _c> PyObject* pyObject(std::vector<_c> const& container) { return cvtSequenceToPyList(container.begin(), container.end()); } template <class _c> PyObject* pyObject(std::list<_c> const& container) { return cvtSequenceToPyList(container.begin(), container.end()); } template <class _c> PyObject* pyObject(std::set<_c> const& container) { return cvtSetToPySet(container.begin(), container.end()); } template <class _c> PyObject* pyObject(std::multiset<_c> const& container) { return cvtSequenceToPyList(container.begin(), container.end()); } template <class _c, class _d> PyObject* pyObject(std::map<_c, _d> const& container) { return cvtMapToPyDict(container.begin(), container.end()); } template <class _c, class _d> PyObject* pyObject(std::multimap<_c, _d> const& container) { return cvtMultiMapToPyDict(container); } template <class _c, class _d> PyObject* pyObject(std::pair<_c, _d> const& _p) { PyObject* _r = PyTuple_New(2); PyObject* _fo = pyObject(_p.first); if (_fo == NULL) { Py_DECREF(_r); return NULL; } PyTuple_SET_ITEM(_r, 0, _fo); PyObject* _so = pyObject(_p.second); if (_so == NULL) { Py_DECREF(_r); return NULL; } PyTuple_SET_ITEM(_r, 1, _so); return _r; } // nomenclature: // // _r result // _b beginning of range // _e end of range // _i integer index // _n next item in range // _k key // _ko key object // _vo value object template <class _iterator> PyObject* cvtSequenceToPyList(_iterator _b, _iterator _e) { PyObject* _r = PyList_New(std::distance(_b, _e)); if (_r == NULL) return NULL; for (Py_ssize_t _i = 0; _b != _e; ++_i, ++_b) { # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _vo = pyObject(*_b); # else PyObject* _vo = pyObject<std::iterator_traits<_iterator>::value_type>(*_b); # endif if (_vo == NULL) { Py_DECREF(_r); return NULL; } # ifdef PyList_SET_ITEM PyList_SET_ITEM(_r, _i, _vo); # else PyList_SetItem(_r, _i, _vo); # endif } return _r; } template <class _iterator> PyObject* cvtSequenceToPyTuple(_iterator _b, _iterator _e) { PyObject* _r = PyTuple_New(std::distance(_b, _e)); if (_r == NULL) return NULL; for (Py_ssize_t _i = 0; _b != _e; ++_i, ++_b) { # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _vo = pyObject(*_b); # else PyObject* _vo = pyObject<std::iterator_traits<_iterator>::value_type>(*_b); # endif if (_vo == NULL) { Py_DECREF(_r); return NULL; } # ifdef PyTuple_SET_ITEM PyTuple_SET_ITEM(_r, _i, _vo); # else PyTuple_SetItem(_r, _i, _vo); # endif } return _r; } # ifdef OTF_NEED_EXPLICIT_TEMPLATES template <class _t> struct StripConst { typedef _t type; typedef _t const const_type; }; # endif inline Py_complex makePy_complex(double r, double i) { Py_complex c; c.real = r; c.imag = i; return c; } template <class _iterator> PyObject* cvtSetToPySet(_iterator _b, _iterator _e) { # if PY_VERSION_HEX < 0x02050000 // This follows internal Python/Objects/setobject.c code because // there is no external API. PySetObject* _so = reinterpret_cast<PySetObject*>( PySet_Type.tp_new(&PySet_Type, NULL, NULL)); if (_so == NULL) return NULL; PyObject* _data = _so->data; // borrowed reference for (; _b != _e; ++_b) { # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _vo = pyObject(*_b); # else PyObject* _vo = pyObject<std::iterator_traits<_iterator>::value_type::second_type>(*_b); # endif if (_vo == NULL || PyDict_SetItem(_data, _vo, Py_True) == -1) { Py_XDECREF(_vo); Py_DECREF(_so); return NULL; } Py_DECREF(_vo); } return reinterpret_cast<PyObject*>(_so); # else PyObject* _tmp = cvtSequenceToPyList(_b, _e); if (_tmp == NULL) return NULL; PyObject* _r = PySet_New(_tmp); Py_DECREF(_tmp); return _r; # endif } template <class _iterator> PyObject* cvtMapToPyDict(_iterator _b, _iterator _e) { PyObject* _r = PyDict_New(); if (_r == NULL) return NULL; for (; _b != _e; ++_b) { # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _ko = pyObject(_b->first); # else PyObject* _ko = pyObject<StripConst<std::iterator_traits<_iterator>::value_type::first_type>::type>(_b->first); # endif if (_ko == NULL) { Py_DECREF(_r); return NULL; } # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _vo = pyObject(_b->second); # else PyObject* _vo = pyObject<std::iterator_traits<_iterator>::value_type::second_type>(_b->second); # endif if (_vo == NULL) { Py_DECREF(_ko); Py_DECREF(_r); return NULL; } int _i = PyDict_SetItem(_r, _ko, _vo); Py_DECREF(_ko); Py_DECREF(_vo); if (_i == -1) { Py_DECREF(_r); return NULL; } } return _r; } template <class _MultiMap> PyObject* cvtMultiMapToPyDict(_MultiMap const& _mm) { PyObject* _r = PyDict_New(); if (_r == NULL) return NULL; for (typename _MultiMap::const_iterator _b = _mm.begin(); _b != _mm.end();) { typename _MultiMap::key_type const _k = _b->first; typename _MultiMap::const_iterator _n = _mm.upper_bound(_k); PyObject* _vo = PyList_New(std::distance(_b, _n)); if (_vo == NULL) { Py_DECREF(_r); return NULL; } for (Py_ssize_t _i = 0; _b != _n; ++_i, ++_b) { # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _o = pyObject(_b->second); # else PyObject* _o = pyObject<_MultiMap::mapped_type>(_b->second); # endif if (_o == NULL) { Py_DECREF(_vo); Py_DECREF(_r); return NULL; } # ifdef PyList_SET_ITEM PyList_SET_ITEM(_vo, _i, _o); # else PyList_SetItem(_vo, _i, _o); # endif } # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _ko = pyObject(_k); # else PyObject* _ko = pyObject<_MultiMap::key_type>(_k); # endif if (_ko == NULL) { Py_DECREF(_vo); Py_DECREF(_r); return NULL; } PyDict_SetItem(_r, _ko, _vo); Py_DECREF(_ko); Py_DECREF(_vo); } return _r; } template <class _iterator> PyObject* cvtMultiMapToPyDict(_iterator _b, _iterator _e) { PyObject* _r = PyDict_New(); if (_r == NULL) return NULL; _iterator _n; for (; _b != _e; _b = _n) { PyObject* _vo = PyList_New(0); if (_vo == NULL) { Py_DECREF(_r); return NULL; } for (_n = _b; _n != _e && _n->first == _b->first; ++_n) { # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _o = pyObject(_n->second); # else PyObject* _o = pyObject<std::iterator_traits<_iterator>::value_type::second_type>(_n->second); # endif if (_o == NULL) { Py_DECREF(_vo); Py_DECREF(_r); return NULL; } PyList_Append(_vo, _o); Py_DECREF(_o); } # ifndef OTF_NEED_EXPLICIT_TEMPLATES PyObject* _ko = pyObject(_b->first); # else PyObject* _ko = pyObject<StripConst<std::iterator_traits<_iterator>::value_type::first_type>::type>(_b->first); # endif if (_ko == NULL) { Py_DECREF(_r); return NULL; } PyDict_SetItem(_r, _ko, _vo); Py_DECREF(_ko); Py_DECREF(_vo); } return _r; } extern OTF_WRAPPY_IMEX int WrapPyMutableType_Ready(PyTypeObject* t); // for module building (ideally this code would be part of Python) extern OTF_WRAPPY_IMEX int PyType_AddObject(PyTypeObject* t, const char* name, PyObject* o); extern OTF_WRAPPY_IMEX std::string PythonBaseString_AsCppString(PyObject *obj); extern OTF_WRAPPY_IMEX char PythonBaseString_AsCChar(PyObject *obj); #ifdef _WIN32 class OTF_WRAPPY_IMEX SE_Exception: public std::exception { private: unsigned int nSE; public: SE_Exception(SE_Exception&) throw () ; SE_Exception(unsigned int n) throw () ; virtual ~SE_Exception() throw (); unsigned int getSeNumber() throw () { return nSE; } virtual const char *what() throw (); }; #endif } // namespace otf // Python module init function extern "C" OTF_WRAPPY_IMEX void initlibwrappy2(); #endif