mirror of https://github.com/swig/swig
Add support for all STL containers to be constructible from a Python set
This commit is contained in:
parent
6098b26f3e
commit
b2fd91bc41
|
@ -7,6 +7,13 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/
|
|||
Version 4.2.0 (in progress)
|
||||
===========================
|
||||
|
||||
2023-04-05: wsfulton
|
||||
[Python] #2515 Add support for all STL containers to be constructible from a Python set.
|
||||
|
||||
The previous implementation used the Python Sequence Protocol to convert from Python types
|
||||
to STL containers. The new implementation uses the Python Iterator Protocol instead and
|
||||
thereby can convert from a Python set too.
|
||||
|
||||
2023-03-25: alatina
|
||||
[Octave] #2512 Add support for Octave 8.1.
|
||||
|
||||
|
|
|
@ -57,6 +57,16 @@ void arrayInPtr(std::array<int, 6> * myarray) {
|
|||
val *= 10;
|
||||
}
|
||||
}
|
||||
|
||||
std::array<int, 6> overloadFunc(std::array<int, 6> myarray) {
|
||||
std::array<int, 6> newarray(myarray);
|
||||
for (auto& val : newarray) {
|
||||
val *= 100;
|
||||
}
|
||||
return newarray;
|
||||
}
|
||||
void overloadFunc(int i, int j) {
|
||||
}
|
||||
%}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -56,6 +56,14 @@ def setslice_exception(swigarray, newval):
|
|||
# print("exception: {}".format(e))
|
||||
pass
|
||||
|
||||
def overload_type_exception(pythonlist):
|
||||
try:
|
||||
overloadFunc(pythonlist)
|
||||
raise RuntimeError("overloadFunc({}) missed raising TypeError exception".format(pythonlist))
|
||||
except TypeError as e:
|
||||
# print("exception: {}".format(e))
|
||||
pass
|
||||
|
||||
|
||||
# Check std::array has similar behaviour to a Python list
|
||||
# except it is not resizable
|
||||
|
@ -161,3 +169,21 @@ compare_containers(ai, [90, 80, 70, 60, 50, 40])
|
|||
# fill
|
||||
ai.fill(111)
|
||||
compare_containers(ai, [111, 111, 111, 111, 111, 111])
|
||||
|
||||
# Overloading
|
||||
newarray = overloadFunc([9, 8, 7, 6, 5, 4])
|
||||
compare_containers(newarray, [900, 800, 700, 600, 500, 400])
|
||||
|
||||
ai = ArrayInt6([9, 8, 7, 6, 5, 4])
|
||||
newarray = overloadFunc([9, 8, 7, 6, 5, 4])
|
||||
compare_containers(newarray, [900, 800, 700, 600, 500, 400])
|
||||
|
||||
overloadFunc(1, 2)
|
||||
overload_type_exception([1, 2, 3, 4, 5, "6"])
|
||||
overload_type_exception([1, 2, 3, 4, 5])
|
||||
overload_type_exception([1, 2, 3, 4, 5, 6, 7])
|
||||
|
||||
# Construct from Python set
|
||||
myset = {11, 12, 13, 14, 15, 16}
|
||||
ai = ArrayInt6(myset)
|
||||
compare_containers(ai, list(myset))
|
||||
|
|
|
@ -279,3 +279,9 @@ try:
|
|||
raise RuntimeError("Zero step not caught")
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# Construct from set (Iterator protocol, not Sequence protocol)
|
||||
ps = {11, 22, 33}
|
||||
iv = vector_int(ps)
|
||||
il = vector_int(ps)
|
||||
compare_containers(list(ps), iv, il)
|
||||
|
|
|
@ -92,3 +92,13 @@ for i in s:
|
|||
|
||||
if (len(sum) != 3 or (not 1 in sum) or (not "hello" in sum) or (not (1, 2) in sum)):
|
||||
raise RuntimeError
|
||||
|
||||
# Create from Python set
|
||||
s = set_string({"x", "y", "z"})
|
||||
sum = ""
|
||||
for i in s:
|
||||
sum = sum + i
|
||||
|
||||
if sum != "xyz":
|
||||
raise RuntimeError
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
or as a member variable:
|
||||
|
||||
struct A {
|
||||
SwigPtr_PyObject obj;
|
||||
SwigPtr_PyObject _obj;
|
||||
A(PyObject *o) : _obj(o) {
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1015,36 +1015,28 @@ namespace swig {
|
|||
|
||||
template <class Seq, class T = typename Seq::value_type >
|
||||
struct IteratorProtocol {
|
||||
static int assign(PyObject *obj, Seq **seq) {
|
||||
int ret = SWIG_ERROR;
|
||||
PyObject *iter = PyObject_GetIter(obj);
|
||||
static void assign(PyObject *obj, Seq *seq) {
|
||||
SwigVar_PyObject iter = PyObject_GetIter(obj);
|
||||
if (iter) {
|
||||
PyObject *item = PyIter_Next(iter);
|
||||
ret = SWIG_OK;
|
||||
if (seq)
|
||||
*seq = new Seq();
|
||||
SwigVar_PyObject item = PyIter_Next(iter);
|
||||
while (item) {
|
||||
try {
|
||||
if (seq) {
|
||||
(*seq)->insert((*seq)->end(), swig::as<T>(item));
|
||||
} else {
|
||||
if (!swig::check<T>(item))
|
||||
ret = SWIG_ERROR;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
if (seq) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, e.what());
|
||||
}
|
||||
}
|
||||
ret = SWIG_ERROR;
|
||||
}
|
||||
Py_DECREF(item);
|
||||
item = (ret == SWIG_OK) ? PyIter_Next(iter) : 0;
|
||||
seq->insert(seq->end(), swig::as<T>(item));
|
||||
item = PyIter_Next(iter);
|
||||
}
|
||||
Py_DECREF(iter);
|
||||
}
|
||||
}
|
||||
|
||||
static bool check(PyObject *obj) {
|
||||
int ret = false;
|
||||
SwigVar_PyObject iter = PyObject_GetIter(obj);
|
||||
if (iter) {
|
||||
SwigVar_PyObject item = PyIter_Next(iter);
|
||||
ret = true;
|
||||
while (item) {
|
||||
ret = swig::check<T>(item);
|
||||
item = ret ? PyIter_Next(iter) : 0;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
@ -1055,11 +1047,9 @@ namespace swig {
|
|||
typedef T value_type;
|
||||
|
||||
static bool is_iterable(PyObject *obj) {
|
||||
PyObject *iter = PyObject_GetIter(obj);
|
||||
bool is_iter = iter != 0;
|
||||
Py_XDECREF(iter);
|
||||
SwigVar_PyObject iter = PyObject_GetIter(obj);
|
||||
PyErr_Clear();
|
||||
return is_iter;
|
||||
return iter != 0;
|
||||
}
|
||||
|
||||
static int asptr(PyObject *obj, sequence **seq) {
|
||||
|
@ -1072,7 +1062,22 @@ namespace swig {
|
|||
return SWIG_OLDOBJ;
|
||||
}
|
||||
} else if (is_iterable(obj)) {
|
||||
ret = IteratorProtocol<Seq, T>::assign(obj, seq);
|
||||
try {
|
||||
if (seq) {
|
||||
*seq = new sequence();
|
||||
IteratorProtocol<Seq, T>::assign(obj, *seq);
|
||||
if (!PyErr_Occurred())
|
||||
return SWIG_NEWOBJ;
|
||||
} else {
|
||||
return IteratorProtocol<Seq, T>::check(obj) ? SWIG_OK : SWIG_ERROR;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
if (seq && !PyErr_Occurred())
|
||||
PyErr_SetString(PyExc_TypeError, e.what());
|
||||
}
|
||||
if (seq)
|
||||
delete *seq;
|
||||
return SWIG_ERROR;
|
||||
} else if (PySequence_Check(obj)) {
|
||||
try {
|
||||
SwigPySequence_Cont<value_type> swigpyseq(obj);
|
||||
|
|
|
@ -31,48 +31,38 @@
|
|||
|
||||
template <class T, size_t N>
|
||||
struct IteratorProtocol<std::array<T, N>, T> {
|
||||
static int assign(PyObject *obj, std::array<T, N> **seq) {
|
||||
int ret = SWIG_ERROR;
|
||||
PyObject *iter = PyObject_GetIter(obj);
|
||||
if (iter) {
|
||||
PyObject *item = PyIter_Next(iter);
|
||||
size_t count = 0;
|
||||
typename std::array<T, N>::iterator array_iter = nullptr;
|
||||
ret = SWIG_OK;
|
||||
if (seq) {
|
||||
*seq = new std::array<T, N>();
|
||||
array_iter = (*seq)->begin();
|
||||
}
|
||||
while (item && (count < N)) {
|
||||
try {
|
||||
if (seq) {
|
||||
*array_iter++ = swig::as<T>(item);
|
||||
} else {
|
||||
if (!swig::check<T>(item))
|
||||
ret = SWIG_ERROR;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
if (seq) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_TypeError, e.what());
|
||||
}
|
||||
}
|
||||
ret = SWIG_ERROR;
|
||||
}
|
||||
++count;
|
||||
Py_DECREF(item);
|
||||
item = (ret == SWIG_OK) ? PyIter_Next(iter) : 0;
|
||||
}
|
||||
if ((ret == SWIG_OK) && (count != N || item)) {
|
||||
PyErr_SetString(PyExc_TypeError, "std::array size does not match source container size");
|
||||
ret = SWIG_ERROR;
|
||||
}
|
||||
Py_XDECREF(item);
|
||||
Py_DECREF(iter);
|
||||
if (seq && (ret == SWIG_ERROR))
|
||||
delete *seq;
|
||||
}
|
||||
|
||||
static void assign(PyObject *obj, std::array<T, N> *seq) {
|
||||
SwigVar_PyObject iter = PyObject_GetIter(obj);
|
||||
if (iter) {
|
||||
SwigVar_PyObject item = PyIter_Next(iter);
|
||||
size_t count = 0;
|
||||
typename std::array<T, N>::iterator array_iter = seq->begin();
|
||||
while (item && (count < N)) {
|
||||
++count;
|
||||
*array_iter++ = swig::as<T>(item);
|
||||
item = PyIter_Next(iter);
|
||||
}
|
||||
if (count != N || item)
|
||||
throw std::invalid_argument("std::array size does not match source container size");
|
||||
}
|
||||
}
|
||||
|
||||
static bool check(PyObject *obj) {
|
||||
int ret = false;
|
||||
SwigVar_PyObject iter = PyObject_GetIter(obj);
|
||||
if (iter) {
|
||||
SwigVar_PyObject item = PyIter_Next(iter);
|
||||
size_t count = 0;
|
||||
ret = true;
|
||||
while (item && (count < N)) {
|
||||
++count;
|
||||
ret = swig::check<T>(item);
|
||||
item = ret ? PyIter_Next(iter) : 0;
|
||||
}
|
||||
if (count != N || item)
|
||||
ret = false;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue