summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES.current70
-rw-r--r--Examples/test-suite/python/li_std_map.i4
-rw-r--r--Examples/test-suite/python/li_std_map_runme.py13
-rw-r--r--Examples/test-suite/python/li_std_set.i2
-rw-r--r--Examples/test-suite/python/li_std_set_runme.py12
-rw-r--r--Examples/test-suite/python/li_std_vector.i2
-rw-r--r--Lib/python/pycontainer.swg109
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 {