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