diff options
-rw-r--r-- | CHANGES.current | 70 | ||||
-rw-r--r-- | Examples/test-suite/python/li_std_map.i | 4 | ||||
-rw-r--r-- | Examples/test-suite/python/li_std_map_runme.py | 13 | ||||
-rw-r--r-- | Examples/test-suite/python/li_std_set.i | 2 | ||||
-rw-r--r-- | Examples/test-suite/python/li_std_set_runme.py | 12 | ||||
-rw-r--r-- | Examples/test-suite/python/li_std_vector.i | 2 | ||||
-rw-r--r-- | Lib/python/pycontainer.swg | 109 |
7 files changed, 206 insertions, 6 deletions
diff --git a/CHANGES.current b/CHANGES.current index e6dc1bebd..0ff0cd025 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -3,6 +3,76 @@ Unreleased changes 11/02/2005: mmatus + [Python] Adding more fun to STL/STD containers, now you + can do + + %template(pyset) std::set<PyObject *>; + %template(pyvector) std::vector<PyObject *>; + %template() std::pair<PyObject *,PyObject *>; + %template(pyvector) std::map<PyObject *,PyObject *>; + .... + + The same applies to std::list, std::deque, std::multiset, etc. + + Then, at the python side you can do now: + + # C++ std::vector as native python sequence + v = pyvector([1,"hello",(1,2)]) + print v[1] + >> 'hello' + print v[2] + >> (1,2) + + # C++ std::set as native python sequence + s = pyset() + s.insert((1,2)) + s.insert(1) + s.insert("hello") + sum=() + for i in s: + sum +=(i,) + print sum + >>> (1, 'hello', (1, 2)) + + # C++ std::map as native python sequence + m = pymap() + m["foo"] = "hello" + m[1] = (1,2) + pm = {} + for k in m: + pm[k] = m[k] + print pm + >>> {1: (1, 2), 'foo': 'hello'} + + ie, the STD/STL containers work as real native python + container, with arbitrary item types and so. + + But since normal C++ containers do not properly ref/unref + their items, you should use the safer versions: + + %template(pyset) std::set<swig::PyItem>; + %template(pyvector) std::vector<swig::PyItem>; + %template() std::pair<swig::PyItem, swig::PyItem>; + %template(pyvector) std::map<swig::PyItem,swig::PyItem>; + .... + + where swig::PyItem is a PyObject * envelope class provided + to safely incref/decref the python object. + + So, now you can use all the STL/STD containers as native + Python containers. + + Note 1: std::map, std::set and the other 'ordered' + containers will properly use PyObject_Compare for sorting, + when needed. + + Note 2: all the STL/STD containers have a limit size of + SIZE_MAX, ie, you can have manage containers larger than + INT_MAX, the python limit. + + +11/02/2005: mmatus + [Python] - add 'iterator()' method for all sequences and additionally 'key_iterator()' for maps. diff --git a/Examples/test-suite/python/li_std_map.i b/Examples/test-suite/python/li_std_map.i index 0418613f2..4ff822d78 100644 --- a/Examples/test-suite/python/li_std_map.i +++ b/Examples/test-suite/python/li_std_map.i @@ -29,8 +29,8 @@ namespace std %template(pairiiAc) pair<int,const pair<int, A*> >; - %template() pair<PyObject *, PyObject *>; - %template(pymap) map<PyObject *, PyObject*>; + %template() pair<swig::PyItem, swig::PyItem>; + %template(pymap) map<swig::PyItem, swig::PyItem>; } diff --git a/Examples/test-suite/python/li_std_map_runme.py b/Examples/test-suite/python/li_std_map_runme.py index f45d288ab..4241c584d 100644 --- a/Examples/test-suite/python/li_std_map_runme.py +++ b/Examples/test-suite/python/li_std_map_runme.py @@ -32,10 +32,17 @@ for k in m: + +m = {} +m[1] = (1,2) +m["foo"] = "hello" + pm = li_std_map.pymap() -pm[1] = (1,2) -pm["foo"] = "hello" +for k in m: + pm[k] = m[k] for k in pm: - print pm[k] + if (pm[k] != m[k]): + raise RuntimeError + diff --git a/Examples/test-suite/python/li_std_set.i b/Examples/test-suite/python/li_std_set.i index 3c833f39c..2d7b0cce4 100644 --- a/Examples/test-suite/python/li_std_set.i +++ b/Examples/test-suite/python/li_std_set.i @@ -13,3 +13,5 @@ + +%template(pyset) std::set<swig::PyItem>; diff --git a/Examples/test-suite/python/li_std_set_runme.py b/Examples/test-suite/python/li_std_set_runme.py index 71d398d92..50471ea13 100644 --- a/Examples/test-suite/python/li_std_set_runme.py +++ b/Examples/test-suite/python/li_std_set_runme.py @@ -82,3 +82,15 @@ if m.value() != "c": +s = pyset() +s.insert((1,2)) +s.insert(1) +s.insert("hello") + + +sum = () +for i in s: + sum += (i,) + +if sum != (1, 'hello', (1, 2)): + raise RuntimeError diff --git a/Examples/test-suite/python/li_std_vector.i b/Examples/test-suite/python/li_std_vector.i index e6dc180f8..40023eac8 100644 --- a/Examples/test-suite/python/li_std_vector.i +++ b/Examples/test-suite/python/li_std_vector.i @@ -123,4 +123,4 @@ std::vector<std::string> vecStr(std::vector<std::string> v) { %array_functions(int,ArrInt) -%template(pyvector) std::vector<PyObject*>; +%template(pyvector) std::vector<swig::PyItem>; diff --git a/Lib/python/pycontainer.swg b/Lib/python/pycontainer.swg index 3f773c3cd..d7b505002 100644 --- a/Lib/python/pycontainer.swg +++ b/Lib/python/pycontainer.swg @@ -24,8 +24,64 @@ %include std_except.i + + +namespace swig { + %ignore PyItem; + struct PyItem {}; + %apply PyObject * {PyItem}; + %apply PyObject * const& {PyItem const&}; +} + +%fragment(SWIG_Traits_frag(swig::PyItem),"header",fragment="StdTraits") { +namespace swig { + template <> struct traits<PyItem > { + typedef value_category category; + static const char* type_name() { return "PyItem"; } + }; + + template <> struct traits_from<PyItem> { + typedef PyItem value_type; + static PyObject *from(const value_type& val) { + return static_cast<PyObject *>(val); + } + }; + + template <> + struct traits_check<PyItem, value_category> { + static bool check(PyObject *obj) { + return true; + } + }; + + template <> struct traits_asval<PyItem > { + typedef PyItem value_type; + static int asval(PyObject *obj, value_type *val) { + if (val) *val = obj; + return SWIG_OK; + } + }; +} +} + +%fragment(SWIG_Traits_frag(PyItem),"header") +{ +} + + %fragment("PySequence_Base","header") { + +namespace std { + template <> + struct less <PyObject *>: public binary_function<PyObject *, PyObject *, bool> + { + bool + operator()(PyObject * v, PyObject *w) const + { return PyObject_Compare(v, w) < 0; } + }; +} + namespace swig { template <> struct traits<PyObject *> { typedef value_category category; @@ -45,6 +101,59 @@ namespace swig { return val; } }; + + class PyItem { + PyObject *_obj; + public: + PyItem(const PyItem& item) : _obj(item._obj) + { + Py_XINCREF(_obj); + } + + PyItem(PyObject *obj = 0) :_obj(obj) + { + Py_XINCREF(obj); + } + + PyItem & operator=(PyObject *obj) { + Py_XINCREF(obj); + Py_XDECREF(_obj); + _obj = obj; + return *this; + } + + PyItem & operator=(const PyItem& item) { + this->operator=(static_cast<PyObject *>(item)); + return *this; + } + + ~PyItem() + { + Py_XDECREF(_obj); + } + + operator PyObject *() const + { + return _obj; + } + + PyObject *operator->() const + { + return _obj; + } + + }; + +} + +namespace std { + template <> + struct less <swig::PyItem>: public binary_function<swig::PyItem, swig::PyItem, bool> + { + bool + operator()(const swig::PyItem& v, const swig::PyItem& w) const + { return PyObject_Compare(v, w) < 0; } + }; } namespace swig { |