1// This is the SIP interface definition for the majority of the QMap and 2// QMultiMap based mapped types. 3// 4// Copyright (c) 2021 Riverbank Computing Limited <info@riverbankcomputing.com> 5// 6// This file is part of PyQt5. 7// 8// This file may be used under the terms of the GNU General Public License 9// version 3.0 as published by the Free Software Foundation and appearing in 10// the file LICENSE included in the packaging of this file. Please review the 11// following information to ensure the GNU General Public License version 3.0 12// requirements will be met: http://www.gnu.org/copyleft/gpl.html. 13// 14// If you do not wish to use this file under the terms of the GPL version 3.0 15// then you may purchase a commercial license. For more information contact 16// info@riverbankcomputing.com. 17// 18// This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE 19// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 20 21 22template<_TYPE1_, _TYPE2_> 23%MappedType QMap<_TYPE1_, _TYPE2_> 24 /TypeHint="Dict[_TYPE1_, _TYPE2_]", TypeHintValue="{}"/ 25{ 26%TypeHeaderCode 27#include <qmap.h> 28%End 29 30%ConvertFromTypeCode 31 PyObject *d = PyDict_New(); 32 33 if (!d) 34 return 0; 35 36 QMap<_TYPE1_, _TYPE2_>::const_iterator it = sipCpp->constBegin(); 37 QMap<_TYPE1_, _TYPE2_>::const_iterator end = sipCpp->constEnd(); 38 39 while (it != end) 40 { 41 _TYPE1_ *k = new _TYPE1_(it.key()); 42 PyObject *kobj = sipConvertFromNewType(k, sipType__TYPE1_, 43 sipTransferObj); 44 45 if (!kobj) 46 { 47 delete k; 48 Py_DECREF(d); 49 50 return 0; 51 } 52 53 _TYPE2_ *v = new _TYPE2_(it.value()); 54 PyObject *vobj = sipConvertFromNewType(v, sipType__TYPE2_, 55 sipTransferObj); 56 57 if (!vobj) 58 { 59 delete v; 60 Py_DECREF(kobj); 61 Py_DECREF(d); 62 63 return 0; 64 } 65 66 int rc = PyDict_SetItem(d, kobj, vobj); 67 68 Py_DECREF(vobj); 69 Py_DECREF(kobj); 70 71 if (rc < 0) 72 { 73 Py_DECREF(d); 74 75 return 0; 76 } 77 78 ++it; 79 } 80 81 return d; 82%End 83 84%ConvertToTypeCode 85 if (!sipIsErr) 86 return PyDict_Check(sipPy); 87 88 QMap<_TYPE1_, _TYPE2_> *qm = new QMap<_TYPE1_, _TYPE2_>; 89 90 Py_ssize_t pos = 0; 91 PyObject *kobj, *vobj; 92 93 while (PyDict_Next(sipPy, &pos, &kobj, &vobj)) 94 { 95 int kstate; 96 _TYPE1_ *k = reinterpret_cast<_TYPE1_ *>( 97 sipForceConvertToType(kobj, sipType__TYPE1_, sipTransferObj, 98 SIP_NOT_NONE, &kstate, sipIsErr)); 99 100 if (*sipIsErr) 101 { 102 PyErr_Format(PyExc_TypeError, 103 "a dict key has type '%s' but '_TYPE1_' is expected", 104 sipPyTypeName(Py_TYPE(kobj))); 105 106 delete qm; 107 108 return 0; 109 } 110 111 int vstate; 112 _TYPE2_ *v = reinterpret_cast<_TYPE2_ *>( 113 sipForceConvertToType(vobj, sipType__TYPE2_, sipTransferObj, 114 SIP_NOT_NONE, &vstate, sipIsErr)); 115 116 if (*sipIsErr) 117 { 118 PyErr_Format(PyExc_TypeError, 119 "a dict value has type '%s' but '_TYPE2_' is expected", 120 sipPyTypeName(Py_TYPE(vobj))); 121 122 sipReleaseType(k, sipType__TYPE1_, kstate); 123 delete qm; 124 125 return 0; 126 } 127 128 qm->insert(*k, *v); 129 130 sipReleaseType(v, sipType__TYPE2_, vstate); 131 sipReleaseType(k, sipType__TYPE1_, kstate); 132 } 133 134 *sipCppPtr = qm; 135 136 return sipGetState(sipTransferObj); 137%End 138}; 139 140 141template<int, _TYPE_> 142%MappedType QMap<int, _TYPE_> 143 /TypeHint="Dict[int, _TYPE_]", TypeHintValue="{}"/ 144{ 145%TypeHeaderCode 146#include <qmap.h> 147%End 148 149%ConvertFromTypeCode 150 PyObject *d = PyDict_New(); 151 152 if (!d) 153 return 0; 154 155 QMap<int, _TYPE_>::const_iterator it = sipCpp->constBegin(); 156 QMap<int, _TYPE_>::const_iterator end = sipCpp->constEnd(); 157 158 while (it != end) 159 { 160 PyObject *kobj = SIPLong_FromLong(it.key()); 161 162 if (!kobj) 163 { 164 Py_DECREF(d); 165 166 return 0; 167 } 168 169 _TYPE_ *v = new _TYPE_(it.value()); 170 PyObject *vobj = sipConvertFromNewType(v, sipType__TYPE_, 171 sipTransferObj); 172 173 if (!vobj) 174 { 175 delete v; 176 Py_DECREF(kobj); 177 Py_DECREF(d); 178 179 return 0; 180 } 181 182 int rc = PyDict_SetItem(d, kobj, vobj); 183 184 Py_DECREF(vobj); 185 Py_DECREF(kobj); 186 187 if (rc < 0) 188 { 189 Py_DECREF(d); 190 191 return 0; 192 } 193 194 ++it; 195 } 196 197 return d; 198%End 199 200%ConvertToTypeCode 201 if (!sipIsErr) 202 return PyDict_Check(sipPy); 203 204 QMap<int, _TYPE_> *qm = new QMap<int, _TYPE_>; 205 206 Py_ssize_t pos = 0; 207 PyObject *kobj, *vobj; 208 209 while (PyDict_Next(sipPy, &pos, &kobj, &vobj)) 210 { 211 int k = sipLong_AsInt(kobj); 212 213 if (PyErr_Occurred()) 214 { 215 if (PyErr_ExceptionMatches(PyExc_TypeError)) 216 PyErr_Format(PyExc_TypeError, 217 "a dict key has type '%s' but 'int' is expected", 218 sipPyTypeName(Py_TYPE(kobj))); 219 220 delete qm; 221 *sipIsErr = 1; 222 223 return 0; 224 } 225 226 int vstate; 227 _TYPE_ *v = reinterpret_cast<_TYPE_ *>( 228 sipForceConvertToType(vobj, sipType__TYPE_, sipTransferObj, 229 SIP_NOT_NONE, &vstate, sipIsErr)); 230 231 if (*sipIsErr) 232 { 233 PyErr_Format(PyExc_TypeError, 234 "a dict value has type '%s' but '_TYPE_' is expected", 235 sipPyTypeName(Py_TYPE(vobj))); 236 237 delete qm; 238 239 return 0; 240 } 241 242 qm->insert(k, *v); 243 244 sipReleaseType(v, sipType__TYPE_, vstate); 245 } 246 247 *sipCppPtr = qm; 248 249 return sipGetState(sipTransferObj); 250%End 251}; 252 253 254template<_TYPE1_, _TYPE2_> 255%MappedType QMultiMap<_TYPE1_, _TYPE2_> 256 /TypeHintOut="Dict[_TYPE1_, List[_TYPE2_]]", TypeHintValue="{}"/ 257{ 258%TypeHeaderCode 259#include <qmap.h> 260%End 261 262%ConvertFromTypeCode 263 PyObject *d = PyDict_New(); 264 265 if (!d) 266 return 0; 267 268 QList<_TYPE1_> keys = sipCpp->keys(); 269 QList<_TYPE1_>::const_iterator kit = keys.constBegin(); 270 QList<_TYPE1_>::const_iterator kit_end = keys.constEnd(); 271 272 while (kit != kit_end) 273 { 274 _TYPE1_ *k = new _TYPE1_(*kit); 275 PyObject *kobj = sipConvertFromNewType(k, sipType__TYPE1_, 276 sipTransferObj); 277 278 if (!kobj) 279 { 280 delete k; 281 Py_DECREF(d); 282 283 return 0; 284 } 285 286 // Create a Python list as the dictionary value. 287 QList<_TYPE2_> values = sipCpp->values(*kit); 288 PyObject *vobj = PyList_New(values.count()); 289 290 if (!vobj) 291 { 292 Py_DECREF(kobj); 293 Py_DECREF(d); 294 295 return 0; 296 } 297 298 QList<_TYPE2_>::const_iterator vit = values.constBegin(); 299 QList<_TYPE2_>::const_iterator vit_end = values.constEnd(); 300 301 for (int i = 0; vit != vit_end; ++i) 302 { 303 _TYPE2_ *sv = new _TYPE2_(*vit); 304 PyObject *svobj = sipConvertFromNewType(sv, sipType__TYPE2_, 305 sipTransferObj); 306 307 if (!svobj) 308 { 309 delete sv; 310 Py_DECREF(vobj); 311 Py_DECREF(kobj); 312 Py_DECREF(d); 313 314 return 0; 315 } 316 317 PyList_SetItem(vobj, i, svobj); 318 319 ++vit; 320 } 321 322 int rc = PyDict_SetItem(d, kobj, vobj); 323 324 Py_DECREF(vobj); 325 Py_DECREF(kobj); 326 327 if (rc < 0) 328 { 329 Py_DECREF(d); 330 331 return 0; 332 } 333 334 ++kit; 335 } 336 337 return d; 338%End 339 340%ConvertToTypeCode 341 if (!sipIsErr) 342 return PyDict_Check(sipPy); 343 344 // Note that PyQt v5.1 contains an unused implementation that can be 345 // restored if needed (although it will need updating to accept an iterable 346 // rather than just a list of values). 347 PyErr_SetString(PyExc_NotImplementedError, 348 "converting to QMultiMap<_TYPE1_, _TYPE2_> is unsupported"); 349 350 return 0; 351%End 352}; 353