1//--------------------------------------------------------------------------
2// Name:        src/arrays.sip
3// Purpose:     Implements a %MappedType for wxArrayString and wxArrayInt
4//
5// Author:      Robin Dunn
6//
7// Created:     2-Sept-2011
8// Copyright:   (c) 2011-2018 by Total Control Software
9// Licence:     wxWindows license
10//--------------------------------------------------------------------------
11
12
13// Some SIP MappedTypes that automatically convert Python lists of
14// strings/ints to and from wxArrayString/wxArrayInt.
15
16// TODO: SWitch to iterator protocol APIs
17
18//--------------------------------------------------------------------------
19
20%MappedType wxArrayString
21{
22    %ConvertToTypeCode
23        // Code to test a PyObject for compatibility
24        // Verify that the object is a sequence, but not bytes or unicode
25        if (!sipIsErr) {
26            return (PySequence_Check(sipPy) &&
27                    !(PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)));
28        }
29
30
31        // Code to create a new wxArrayString and convert a compatible PyObject
32        wxArrayString *array = new wxArrayString;
33        Py_ssize_t i, len = PySequence_Length(sipPy);
34        for (i=0; i<len; i++) {
35            PyObject* item = PySequence_GetItem(sipPy, i);
36
37            // Ensure each item is a bytes or string/unicode object
38            if ( !PyBytes_Check(item) && !PyUnicode_Check(item) ) {
39                // raise a TypeError if not
40                PyErr_Format(PyExc_TypeError,
41                             "Item at index %zd has type '%s' but a sequence of bytes or strings is expected",
42                             i, sipPyTypeName(Py_TYPE(item)));
43                delete array;
44                Py_DECREF(item);
45                *sipIsErr = 1;
46                return 0;
47            }
48
49            // if it's a string object convert it to unicode first, assuming utf-8
50            if (PyBytes_Check(item)) {
51                Py_DECREF(item);
52                item = PyUnicode_FromEncodedObject(item, "utf-8", "strict");
53                if (PyErr_Occurred()) {
54                    *sipIsErr = 1;
55                    delete array;
56                    Py_DECREF(item);
57                    return 0;
58                }
59            }
60            PyErr_Clear();
61            wxString string;
62            size_t len = PyUnicode_GET_SIZE(item);
63            if (len) {
64                wxPyUnicode_AsWideChar(item, wxStringBuffer(string, len), len);
65            }
66            if (PyErr_Occurred()) {
67                *sipIsErr = 1;
68                delete array;
69                Py_DECREF(item);
70                return 0;
71            }
72            array->Add(string);
73            Py_DECREF(item);
74        }
75        *sipCppPtr = array;
76        return sipGetState(sipTransferObj);
77    %End
78
79
80    %ConvertFromTypeCode
81        // Code to convert a wxArrayString to a Python list of strings.
82        PyObject* list = PyList_New(0);
83        for (size_t i=0; i < sipCpp->GetCount(); i++) {
84            PyObject* str = wx2PyString(sipCpp->Item(i));
85            PyList_Append(list, str);
86            Py_DECREF(str);
87        }
88        return list;
89    %End
90
91};
92
93
94// Used just for unittesting the MappedType code, it can be removed later
95%ModuleCode
96wxArrayString testArrayStringTypemap(const wxArrayString& arr)
97{
98    wxArrayString local = arr;  // force a copy
99    return local;
100}
101%End
102wxArrayString testArrayStringTypemap(const wxArrayString& arr);
103
104
105//--------------------------------------------------------------------------
106
107%MappedType wxArrayInt
108{
109    %ConvertToTypeCode
110        // Code to test a PyObject for compatibility
111        if (!sipIsErr) {
112            return (PySequence_Check(sipPy) &&
113                    !(PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)));
114        }
115
116        // Code to create a new wxArrayInt and convert a compatible PyObject
117        wxArrayInt *array = new wxArrayInt;
118        Py_ssize_t i, len = PySequence_Length(sipPy);
119        for (i=0; i<len; i++) {
120            PyObject* item = PySequence_GetItem(sipPy, i);
121
122            // Ensure each item is a number object
123            if ( !PyNumber_Check(item) ) {
124                // raise a TypeError if not
125                PyErr_Format(PyExc_TypeError,
126                             "Item at index %zd has type '%s' but a sequence of numbers is expected",
127                             i, sipPyTypeName(Py_TYPE(item)));
128                delete array;
129                Py_DECREF(item);
130                *sipIsErr = 1;
131                return 0;
132            }
133
134            // Convert to Integer
135            PyObject* number = wxPyNumber_Int(item);
136            if (PyErr_Occurred()) {
137                *sipIsErr = 1;
138                delete array;
139                Py_DECREF(item);
140                return 0;
141            }
142            // And add it to the array
143            array->Add(wxPyInt_AS_LONG(number));
144            Py_DECREF(item);
145            Py_DECREF(number);
146        }
147        *sipCppPtr = array;
148        return sipGetState(sipTransferObj);
149    %End
150
151
152    %ConvertFromTypeCode
153        // Code to convert a wxArrayInt to a Python list of integers.
154        PyObject* list = PyList_New(0);
155        for (size_t i=0; i < sipCpp->GetCount(); i++) {
156            PyObject* number = wxPyInt_FromLong(sipCpp->Item(i));
157            PyList_Append(list, number);
158            Py_DECREF(number);
159        }
160        return list;
161    %End
162
163};
164
165
166// Used just for unittesting the MappedType code, it can be removed later
167%ModuleCode
168wxArrayInt testArrayIntTypemap(const wxArrayInt& arr)
169{
170    wxArrayInt local = arr;  // force a copy
171    return local;
172}
173%End
174wxArrayInt testArrayIntTypemap(const wxArrayInt& arr);
175
176
177//--------------------------------------------------------------------------
178
179
180%MappedType wxArrayDouble
181{
182    %ConvertToTypeCode
183        // Code to test a PyObject for compatibility
184        if (!sipIsErr) {
185            return (PySequence_Check(sipPy) &&
186                    !(PyBytes_Check(sipPy) || PyUnicode_Check(sipPy)));
187        }
188
189        // Code to create a new wxArrayDouble and convert a compatible PyObject
190        wxArrayDouble *array = new wxArrayDouble;
191        Py_ssize_t i, len = PySequence_Length(sipPy);
192        for (i=0; i<len; i++) {
193            PyObject* item = PySequence_GetItem(sipPy, i);
194
195            // Ensure each item is a number object
196            if ( !PyNumber_Check(item) ) {
197                // raise a TypeError if not
198                PyErr_Format(PyExc_TypeError,
199                             "Item at index %zd has type '%s' but a sequence of numbers is expected",
200                             i, sipPyTypeName(Py_TYPE(item)));
201                delete array;
202                Py_DECREF(item);
203                *sipIsErr = 1;
204                return 0;
205            }
206
207            // Convert to a Float
208            PyObject* number = PyNumber_Float(item);
209            if (PyErr_Occurred()) {
210                *sipIsErr = 1;
211                delete array;
212                Py_DECREF(item);
213                return 0;
214            }
215            // And add it to the array
216            array->Add(PyFloat_AS_DOUBLE(number));
217            Py_DECREF(item);
218            Py_DECREF(number);
219        }
220        *sipCppPtr = array;
221        return sipGetState(sipTransferObj);
222    %End
223
224
225    %ConvertFromTypeCode
226        // Code to convert a wxArrayDouble to a Python list of floating point values.
227        PyObject* list = PyList_New(0);
228        for (size_t i=0; i < sipCpp->GetCount(); i++) {
229            PyObject* number = PyFloat_FromDouble(sipCpp->Item(i));
230            PyList_Append(list, number);
231            Py_DECREF(number);
232        }
233        return list;
234    %End
235
236};
237
238
239// Used just for unittesting the MappedType code, it can be removed later
240%ModuleCode
241wxArrayDouble testArrayDoubleTypemap(const wxArrayDouble& arr)
242{
243    wxArrayDouble local = arr;  // force a copy
244    return local;
245}
246%End
247wxArrayDouble testArrayDoubleTypemap(const wxArrayDouble& arr);
248
249//--------------------------------------------------------------------------
250