1 /* Implementation helper: a struct that looks like a tuple. See timemodule 2 and posixmodule for example uses. */ 3 4 #include "Python.h" 5 #include "structmember.h" 6 7 static const char visible_length_key[] = "n_sequence_fields"; 8 static const char real_length_key[] = "n_fields"; 9 static const char unnamed_fields_key[] = "n_unnamed_fields"; 10 11 /* Fields with this name have only a field index, not a field name. 12 They are only allowed for indices < n_visible_fields. */ 13 char *PyStructSequence_UnnamedField = "unnamed field"; 14 _Py_IDENTIFIER(n_sequence_fields); 15 _Py_IDENTIFIER(n_fields); 16 _Py_IDENTIFIER(n_unnamed_fields); 17 18 #define VISIBLE_SIZE(op) Py_SIZE(op) 19 #define VISIBLE_SIZE_TP(tp) PyLong_AsSsize_t( \ 20 _PyDict_GetItemId((tp)->tp_dict, &PyId_n_sequence_fields)) 21 22 #define REAL_SIZE_TP(tp) PyLong_AsSsize_t( \ 23 _PyDict_GetItemId((tp)->tp_dict, &PyId_n_fields)) 24 #define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op)) 25 26 #define UNNAMED_FIELDS_TP(tp) PyLong_AsSsize_t( \ 27 _PyDict_GetItemId((tp)->tp_dict, &PyId_n_unnamed_fields)) 28 #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op)) 29 30 31 PyObject * 32 PyStructSequence_New(PyTypeObject *type) 33 { 34 PyStructSequence *obj; 35 Py_ssize_t size = REAL_SIZE_TP(type), i; 36 37 obj = PyObject_GC_NewVar(PyStructSequence, type, size); 38 if (obj == NULL) 39 return NULL; 40 /* Hack the size of the variable object, so invisible fields don't appear 41 to Python code. */ 42 Py_SIZE(obj) = VISIBLE_SIZE_TP(type); 43 for (i = 0; i < size; i++) 44 obj->ob_item[i] = NULL; 45 46 return (PyObject*)obj; 47 } 48 49 void 50 PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v) 51 { 52 PyStructSequence_SET_ITEM(op, i, v); 53 } 54 55 PyObject* 56 PyStructSequence_GetItem(PyObject* op, Py_ssize_t i) 57 { 58 return PyStructSequence_GET_ITEM(op, i); 59 } 60 61 static void 62 structseq_dealloc(PyStructSequence *obj) 63 { 64 Py_ssize_t i, size; 65 66 size = REAL_SIZE(obj); 67 for (i = 0; i < size; ++i) { 68 Py_XDECREF(obj->ob_item[i]); 69 } 70 PyObject_GC_Del(obj); 71 } 72 73 /*[clinic input] 74 class structseq "PyStructSequence *" "NULL" 75 [clinic start generated code]*/ 76 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9d781c6922c77752]*/ 77 78 #include "clinic/structseq.c.h" 79 80 /*[clinic input] 81 @classmethod 82 structseq.__new__ as structseq_new 83 sequence as arg: object 84 dict: object = NULL 85 [clinic start generated code]*/ 86 87 static PyObject * 88 structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict) 89 /*[clinic end generated code: output=baa082e788b171da input=9b44810243907377]*/ 90 { 91 PyObject *ob; 92 PyStructSequence *res = NULL; 93 Py_ssize_t len, min_len, max_len, i, n_unnamed_fields; 94 95 arg = PySequence_Fast(arg, "constructor requires a sequence"); 96 97 if (!arg) { 98 return NULL; 99 } 100 101 if (dict && !PyDict_Check(dict)) { 102 PyErr_Format(PyExc_TypeError, 103 "%.500s() takes a dict as second arg, if any", 104 type->tp_name); 105 Py_DECREF(arg); 106 return NULL; 107 } 108 109 len = PySequence_Fast_GET_SIZE(arg); 110 min_len = VISIBLE_SIZE_TP(type); 111 max_len = REAL_SIZE_TP(type); 112 n_unnamed_fields = UNNAMED_FIELDS_TP(type); 113 114 if (min_len != max_len) { 115 if (len < min_len) { 116 PyErr_Format(PyExc_TypeError, 117 "%.500s() takes an at least %zd-sequence (%zd-sequence given)", 118 type->tp_name, min_len, len); 119 Py_DECREF(arg); 120 return NULL; 121 } 122 123 if (len > max_len) { 124 PyErr_Format(PyExc_TypeError, 125 "%.500s() takes an at most %zd-sequence (%zd-sequence given)", 126 type->tp_name, max_len, len); 127 Py_DECREF(arg); 128 return NULL; 129 } 130 } 131 else { 132 if (len != min_len) { 133 PyErr_Format(PyExc_TypeError, 134 "%.500s() takes a %zd-sequence (%zd-sequence given)", 135 type->tp_name, min_len, len); 136 Py_DECREF(arg); 137 return NULL; 138 } 139 } 140 141 res = (PyStructSequence*) PyStructSequence_New(type); 142 if (res == NULL) { 143 Py_DECREF(arg); 144 return NULL; 145 } 146 for (i = 0; i < len; ++i) { 147 PyObject *v = PySequence_Fast_GET_ITEM(arg, i); 148 Py_INCREF(v); 149 res->ob_item[i] = v; 150 } 151 for (; i < max_len; ++i) { 152 if (dict && (ob = PyDict_GetItemString( 153 dict, type->tp_members[i-n_unnamed_fields].name))) { 154 } 155 else { 156 ob = Py_None; 157 } 158 Py_INCREF(ob); 159 res->ob_item[i] = ob; 160 } 161 162 Py_DECREF(arg); 163 return (PyObject*) res; 164 } 165 166 167 static PyObject * 168 structseq_repr(PyStructSequence *obj) 169 { 170 /* buffer and type size were chosen well considered. */ 171 #define REPR_BUFFER_SIZE 512 172 #define TYPE_MAXSIZE 100 173 174 PyTypeObject *typ = Py_TYPE(obj); 175 Py_ssize_t i; 176 int removelast = 0; 177 Py_ssize_t len; 178 char buf[REPR_BUFFER_SIZE]; 179 char *endofbuf, *pbuf = buf; 180 181 /* pointer to end of writeable buffer; safes space for "...)\0" */ 182 endofbuf= &buf[REPR_BUFFER_SIZE-5]; 183 184 /* "typename(", limited to TYPE_MAXSIZE */ 185 len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE : 186 strlen(typ->tp_name); 187 strncpy(pbuf, typ->tp_name, len); 188 pbuf += len; 189 *pbuf++ = '('; 190 191 for (i=0; i < VISIBLE_SIZE(obj); i++) { 192 PyObject *val, *repr; 193 const char *cname, *crepr; 194 195 cname = typ->tp_members[i].name; 196 if (cname == NULL) { 197 PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL" 198 " for type %.500s", i, typ->tp_name); 199 return NULL; 200 } 201 val = PyStructSequence_GET_ITEM(obj, i); 202 repr = PyObject_Repr(val); 203 if (repr == NULL) 204 return NULL; 205 crepr = PyUnicode_AsUTF8(repr); 206 if (crepr == NULL) { 207 Py_DECREF(repr); 208 return NULL; 209 } 210 211 /* + 3: keep space for "=" and ", " */ 212 len = strlen(cname) + strlen(crepr) + 3; 213 if ((pbuf+len) <= endofbuf) { 214 strcpy(pbuf, cname); 215 pbuf += strlen(cname); 216 *pbuf++ = '='; 217 strcpy(pbuf, crepr); 218 pbuf += strlen(crepr); 219 *pbuf++ = ','; 220 *pbuf++ = ' '; 221 removelast = 1; 222 Py_DECREF(repr); 223 } 224 else { 225 strcpy(pbuf, "..."); 226 pbuf += 3; 227 removelast = 0; 228 Py_DECREF(repr); 229 break; 230 } 231 } 232 if (removelast) { 233 /* overwrite last ", " */ 234 pbuf-=2; 235 } 236 *pbuf++ = ')'; 237 *pbuf = '\0'; 238 239 return PyUnicode_FromString(buf); 240 } 241 242 static PyObject * 243 structseq_reduce(PyStructSequence* self) 244 { 245 PyObject* tup = NULL; 246 PyObject* dict = NULL; 247 PyObject* result; 248 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i; 249 250 n_fields = REAL_SIZE(self); 251 n_visible_fields = VISIBLE_SIZE(self); 252 n_unnamed_fields = UNNAMED_FIELDS(self); 253 tup = PyTuple_New(n_visible_fields); 254 if (!tup) 255 goto error; 256 257 dict = PyDict_New(); 258 if (!dict) 259 goto error; 260 261 for (i = 0; i < n_visible_fields; i++) { 262 Py_INCREF(self->ob_item[i]); 263 PyTuple_SET_ITEM(tup, i, self->ob_item[i]); 264 } 265 266 for (; i < n_fields; i++) { 267 const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name; 268 if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0) 269 goto error; 270 } 271 272 result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict); 273 274 Py_DECREF(tup); 275 Py_DECREF(dict); 276 277 return result; 278 279 error: 280 Py_XDECREF(tup); 281 Py_XDECREF(dict); 282 return NULL; 283 } 284 285 static PyMethodDef structseq_methods[] = { 286 {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL}, 287 {NULL, NULL} 288 }; 289 290 static PyTypeObject _struct_sequence_template = { 291 PyVarObject_HEAD_INIT(&PyType_Type, 0) 292 NULL, /* tp_name */ 293 sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */ 294 sizeof(PyObject *), /* tp_itemsize */ 295 (destructor)structseq_dealloc, /* tp_dealloc */ 296 0, /* tp_print */ 297 0, /* tp_getattr */ 298 0, /* tp_setattr */ 299 0, /* tp_reserved */ 300 (reprfunc)structseq_repr, /* tp_repr */ 301 0, /* tp_as_number */ 302 0, /* tp_as_sequence */ 303 0, /* tp_as_mapping */ 304 0, /* tp_hash */ 305 0, /* tp_call */ 306 0, /* tp_str */ 307 0, /* tp_getattro */ 308 0, /* tp_setattro */ 309 0, /* tp_as_buffer */ 310 Py_TPFLAGS_DEFAULT, /* tp_flags */ 311 NULL, /* tp_doc */ 312 0, /* tp_traverse */ 313 0, /* tp_clear */ 314 0, /* tp_richcompare */ 315 0, /* tp_weaklistoffset */ 316 0, /* tp_iter */ 317 0, /* tp_iternext */ 318 structseq_methods, /* tp_methods */ 319 NULL, /* tp_members */ 320 0, /* tp_getset */ 321 0, /* tp_base */ 322 0, /* tp_dict */ 323 0, /* tp_descr_get */ 324 0, /* tp_descr_set */ 325 0, /* tp_dictoffset */ 326 0, /* tp_init */ 327 0, /* tp_alloc */ 328 structseq_new, /* tp_new */ 329 }; 330 331 int 332 PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) 333 { 334 PyObject *dict; 335 PyMemberDef* members; 336 Py_ssize_t n_members, n_unnamed_members, i, k; 337 PyObject *v; 338 339 #ifdef Py_TRACE_REFS 340 /* if the type object was chained, unchain it first 341 before overwriting its storage */ 342 if (type->ob_base.ob_base._ob_next) { 343 _Py_ForgetReference((PyObject*)type); 344 } 345 #endif 346 347 n_unnamed_members = 0; 348 for (i = 0; desc->fields[i].name != NULL; ++i) 349 if (desc->fields[i].name == PyStructSequence_UnnamedField) 350 n_unnamed_members++; 351 n_members = i; 352 353 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject)); 354 type->tp_base = &PyTuple_Type; 355 type->tp_name = desc->name; 356 type->tp_doc = desc->doc; 357 358 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1); 359 if (members == NULL) { 360 PyErr_NoMemory(); 361 return -1; 362 } 363 364 for (i = k = 0; i < n_members; ++i) { 365 if (desc->fields[i].name == PyStructSequence_UnnamedField) 366 continue; 367 members[k].name = desc->fields[i].name; 368 members[k].type = T_OBJECT; 369 members[k].offset = offsetof(PyStructSequence, ob_item) 370 + i * sizeof(PyObject*); 371 members[k].flags = READONLY; 372 members[k].doc = desc->fields[i].doc; 373 k++; 374 } 375 members[k].name = NULL; 376 377 type->tp_members = members; 378 379 if (PyType_Ready(type) < 0) 380 return -1; 381 Py_INCREF(type); 382 383 dict = type->tp_dict; 384 #define SET_DICT_FROM_SIZE(key, value) \ 385 do { \ 386 v = PyLong_FromSsize_t(value); \ 387 if (v == NULL) \ 388 return -1; \ 389 if (PyDict_SetItemString(dict, key, v) < 0) { \ 390 Py_DECREF(v); \ 391 return -1; \ 392 } \ 393 Py_DECREF(v); \ 394 } while (0) 395 396 SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence); 397 SET_DICT_FROM_SIZE(real_length_key, n_members); 398 SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members); 399 400 return 0; 401 } 402 403 void 404 PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc) 405 { 406 (void)PyStructSequence_InitType2(type, desc); 407 } 408 409 PyTypeObject* 410 PyStructSequence_NewType(PyStructSequence_Desc *desc) 411 { 412 PyTypeObject *result; 413 414 result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0); 415 if (result == NULL) 416 return NULL; 417 if (PyStructSequence_InitType2(result, desc) < 0) { 418 Py_DECREF(result); 419 return NULL; 420 } 421 return result; 422 } 423 424 int _PyStructSequence_Init(void) 425 { 426 if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL 427 || _PyUnicode_FromId(&PyId_n_fields) == NULL 428 || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL) 429 return -1; 430 431 return 0; 432 } 433