[2] | 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 | #include "structseq.h"
|
---|
| 7 |
|
---|
| 8 | static char visible_length_key[] = "n_sequence_fields";
|
---|
| 9 | static char real_length_key[] = "n_fields";
|
---|
| 10 | static char unnamed_fields_key[] = "n_unnamed_fields";
|
---|
| 11 |
|
---|
[391] | 12 | /* Fields with this name have only a field index, not a field name.
|
---|
[2] | 13 | They are only allowed for indices < n_visible_fields. */
|
---|
| 14 | char *PyStructSequence_UnnamedField = "unnamed field";
|
---|
| 15 |
|
---|
| 16 | #define VISIBLE_SIZE(op) Py_SIZE(op)
|
---|
| 17 | #define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \
|
---|
| 18 | PyDict_GetItemString((tp)->tp_dict, visible_length_key))
|
---|
| 19 |
|
---|
| 20 | #define REAL_SIZE_TP(tp) PyInt_AsLong( \
|
---|
| 21 | PyDict_GetItemString((tp)->tp_dict, real_length_key))
|
---|
| 22 | #define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
|
---|
| 23 |
|
---|
| 24 | #define UNNAMED_FIELDS_TP(tp) PyInt_AsLong( \
|
---|
| 25 | PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))
|
---|
| 26 | #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
|
---|
| 27 |
|
---|
| 28 |
|
---|
| 29 | PyObject *
|
---|
| 30 | PyStructSequence_New(PyTypeObject *type)
|
---|
| 31 | {
|
---|
[391] | 32 | PyStructSequence *obj;
|
---|
[2] | 33 |
|
---|
[391] | 34 | obj = PyObject_New(PyStructSequence, type);
|
---|
| 35 | if (obj == NULL)
|
---|
| 36 | return NULL;
|
---|
| 37 | Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
|
---|
[2] | 38 |
|
---|
[391] | 39 | return (PyObject*) obj;
|
---|
[2] | 40 | }
|
---|
| 41 |
|
---|
| 42 | static void
|
---|
| 43 | structseq_dealloc(PyStructSequence *obj)
|
---|
| 44 | {
|
---|
[391] | 45 | Py_ssize_t i, size;
|
---|
[2] | 46 |
|
---|
[391] | 47 | size = REAL_SIZE(obj);
|
---|
| 48 | for (i = 0; i < size; ++i) {
|
---|
| 49 | Py_XDECREF(obj->ob_item[i]);
|
---|
| 50 | }
|
---|
| 51 | PyObject_Del(obj);
|
---|
[2] | 52 | }
|
---|
| 53 |
|
---|
| 54 | static Py_ssize_t
|
---|
| 55 | structseq_length(PyStructSequence *obj)
|
---|
| 56 | {
|
---|
[391] | 57 | return VISIBLE_SIZE(obj);
|
---|
[2] | 58 | }
|
---|
| 59 |
|
---|
| 60 | static PyObject*
|
---|
| 61 | structseq_item(PyStructSequence *obj, Py_ssize_t i)
|
---|
| 62 | {
|
---|
[391] | 63 | if (i < 0 || i >= VISIBLE_SIZE(obj)) {
|
---|
| 64 | PyErr_SetString(PyExc_IndexError, "tuple index out of range");
|
---|
| 65 | return NULL;
|
---|
| 66 | }
|
---|
| 67 | Py_INCREF(obj->ob_item[i]);
|
---|
| 68 | return obj->ob_item[i];
|
---|
[2] | 69 | }
|
---|
| 70 |
|
---|
| 71 | static PyObject*
|
---|
| 72 | structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high)
|
---|
| 73 | {
|
---|
[391] | 74 | PyTupleObject *np;
|
---|
| 75 | Py_ssize_t i;
|
---|
[2] | 76 |
|
---|
[391] | 77 | if (low < 0)
|
---|
| 78 | low = 0;
|
---|
| 79 | if (high > VISIBLE_SIZE(obj))
|
---|
| 80 | high = VISIBLE_SIZE(obj);
|
---|
| 81 | if (high < low)
|
---|
| 82 | high = low;
|
---|
| 83 | np = (PyTupleObject *)PyTuple_New(high-low);
|
---|
| 84 | if (np == NULL)
|
---|
| 85 | return NULL;
|
---|
| 86 | for(i = low; i < high; ++i) {
|
---|
| 87 | PyObject *v = obj->ob_item[i];
|
---|
| 88 | Py_INCREF(v);
|
---|
| 89 | PyTuple_SET_ITEM(np, i-low, v);
|
---|
| 90 | }
|
---|
| 91 | return (PyObject *) np;
|
---|
[2] | 92 | }
|
---|
| 93 |
|
---|
| 94 | static PyObject *
|
---|
| 95 | structseq_subscript(PyStructSequence *self, PyObject *item)
|
---|
| 96 | {
|
---|
[391] | 97 | if (PyIndex_Check(item)) {
|
---|
| 98 | Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
|
---|
| 99 | if (i == -1 && PyErr_Occurred())
|
---|
| 100 | return NULL;
|
---|
[2] | 101 |
|
---|
[391] | 102 | if (i < 0)
|
---|
| 103 | i += VISIBLE_SIZE(self);
|
---|
[2] | 104 |
|
---|
[391] | 105 | if (i < 0 || i >= VISIBLE_SIZE(self)) {
|
---|
| 106 | PyErr_SetString(PyExc_IndexError,
|
---|
| 107 | "tuple index out of range");
|
---|
| 108 | return NULL;
|
---|
| 109 | }
|
---|
| 110 | Py_INCREF(self->ob_item[i]);
|
---|
| 111 | return self->ob_item[i];
|
---|
| 112 | }
|
---|
| 113 | else if (PySlice_Check(item)) {
|
---|
| 114 | Py_ssize_t start, stop, step, slicelen, cur, i;
|
---|
| 115 | PyObject *result;
|
---|
| 116 |
|
---|
| 117 | if (PySlice_GetIndicesEx((PySliceObject *)item,
|
---|
| 118 | VISIBLE_SIZE(self), &start, &stop,
|
---|
| 119 | &step, &slicelen) < 0) {
|
---|
| 120 | return NULL;
|
---|
| 121 | }
|
---|
| 122 | if (slicelen <= 0)
|
---|
| 123 | return PyTuple_New(0);
|
---|
| 124 | result = PyTuple_New(slicelen);
|
---|
| 125 | if (result == NULL)
|
---|
| 126 | return NULL;
|
---|
| 127 | for (cur = start, i = 0; i < slicelen;
|
---|
| 128 | cur += step, i++) {
|
---|
| 129 | PyObject *v = self->ob_item[cur];
|
---|
| 130 | Py_INCREF(v);
|
---|
| 131 | PyTuple_SET_ITEM(result, i, v);
|
---|
| 132 | }
|
---|
| 133 | return result;
|
---|
| 134 | }
|
---|
| 135 | else {
|
---|
| 136 | PyErr_SetString(PyExc_TypeError,
|
---|
| 137 | "structseq index must be integer");
|
---|
| 138 | return NULL;
|
---|
| 139 | }
|
---|
[2] | 140 | }
|
---|
| 141 |
|
---|
| 142 | static PyObject *
|
---|
| 143 | structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
---|
| 144 | {
|
---|
[391] | 145 | PyObject *arg = NULL;
|
---|
| 146 | PyObject *dict = NULL;
|
---|
| 147 | PyObject *ob;
|
---|
| 148 | PyStructSequence *res = NULL;
|
---|
| 149 | Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
|
---|
| 150 | static char *kwlist[] = {"sequence", "dict", 0};
|
---|
[2] | 151 |
|
---|
[391] | 152 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
|
---|
| 153 | kwlist, &arg, &dict))
|
---|
| 154 | return NULL;
|
---|
[2] | 155 |
|
---|
[391] | 156 | arg = PySequence_Fast(arg, "constructor requires a sequence");
|
---|
[2] | 157 |
|
---|
[391] | 158 | if (!arg) {
|
---|
| 159 | return NULL;
|
---|
| 160 | }
|
---|
[2] | 161 |
|
---|
[391] | 162 | if (dict && !PyDict_Check(dict)) {
|
---|
| 163 | PyErr_Format(PyExc_TypeError,
|
---|
| 164 | "%.500s() takes a dict as second arg, if any",
|
---|
| 165 | type->tp_name);
|
---|
| 166 | Py_DECREF(arg);
|
---|
| 167 | return NULL;
|
---|
| 168 | }
|
---|
[2] | 169 |
|
---|
[391] | 170 | len = PySequence_Fast_GET_SIZE(arg);
|
---|
| 171 | min_len = VISIBLE_SIZE_TP(type);
|
---|
| 172 | max_len = REAL_SIZE_TP(type);
|
---|
| 173 | n_unnamed_fields = UNNAMED_FIELDS_TP(type);
|
---|
[2] | 174 |
|
---|
[391] | 175 | if (min_len != max_len) {
|
---|
| 176 | if (len < min_len) {
|
---|
| 177 | PyErr_Format(PyExc_TypeError,
|
---|
| 178 | "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
|
---|
| 179 | type->tp_name, min_len, len);
|
---|
| 180 | Py_DECREF(arg);
|
---|
| 181 | return NULL;
|
---|
| 182 | }
|
---|
[2] | 183 |
|
---|
[391] | 184 | if (len > max_len) {
|
---|
| 185 | PyErr_Format(PyExc_TypeError,
|
---|
| 186 | "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
|
---|
| 187 | type->tp_name, max_len, len);
|
---|
| 188 | Py_DECREF(arg);
|
---|
| 189 | return NULL;
|
---|
| 190 | }
|
---|
| 191 | }
|
---|
| 192 | else {
|
---|
| 193 | if (len != min_len) {
|
---|
| 194 | PyErr_Format(PyExc_TypeError,
|
---|
| 195 | "%.500s() takes a %zd-sequence (%zd-sequence given)",
|
---|
| 196 | type->tp_name, min_len, len);
|
---|
| 197 | Py_DECREF(arg);
|
---|
| 198 | return NULL;
|
---|
| 199 | }
|
---|
| 200 | }
|
---|
[2] | 201 |
|
---|
[391] | 202 | res = (PyStructSequence*) PyStructSequence_New(type);
|
---|
| 203 | if (res == NULL) {
|
---|
| 204 | Py_DECREF(arg);
|
---|
| 205 | return NULL;
|
---|
| 206 | }
|
---|
| 207 | for (i = 0; i < len; ++i) {
|
---|
| 208 | PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
|
---|
| 209 | Py_INCREF(v);
|
---|
| 210 | res->ob_item[i] = v;
|
---|
| 211 | }
|
---|
| 212 | for (; i < max_len; ++i) {
|
---|
| 213 | if (dict && (ob = PyDict_GetItemString(
|
---|
| 214 | dict, type->tp_members[i-n_unnamed_fields].name))) {
|
---|
| 215 | }
|
---|
| 216 | else {
|
---|
| 217 | ob = Py_None;
|
---|
| 218 | }
|
---|
| 219 | Py_INCREF(ob);
|
---|
| 220 | res->ob_item[i] = ob;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | Py_DECREF(arg);
|
---|
| 224 | return (PyObject*) res;
|
---|
[2] | 225 | }
|
---|
| 226 |
|
---|
| 227 | static PyObject *
|
---|
| 228 | make_tuple(PyStructSequence *obj)
|
---|
| 229 | {
|
---|
[391] | 230 | return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
|
---|
[2] | 231 | }
|
---|
| 232 |
|
---|
| 233 | static PyObject *
|
---|
| 234 | structseq_repr(PyStructSequence *obj)
|
---|
| 235 | {
|
---|
[391] | 236 | /* buffer and type size were chosen well considered. */
|
---|
[2] | 237 | #define REPR_BUFFER_SIZE 512
|
---|
| 238 | #define TYPE_MAXSIZE 100
|
---|
| 239 |
|
---|
[391] | 240 | PyObject *tup;
|
---|
| 241 | PyTypeObject *typ = Py_TYPE(obj);
|
---|
| 242 | int i, removelast = 0;
|
---|
| 243 | Py_ssize_t len;
|
---|
| 244 | char buf[REPR_BUFFER_SIZE];
|
---|
| 245 | char *endofbuf, *pbuf = buf;
|
---|
[2] | 246 |
|
---|
[391] | 247 | /* pointer to end of writeable buffer; safes space for "...)\0" */
|
---|
| 248 | endofbuf= &buf[REPR_BUFFER_SIZE-5];
|
---|
[2] | 249 |
|
---|
[391] | 250 | if ((tup = make_tuple(obj)) == NULL) {
|
---|
| 251 | return NULL;
|
---|
| 252 | }
|
---|
[2] | 253 |
|
---|
[391] | 254 | /* "typename(", limited to TYPE_MAXSIZE */
|
---|
| 255 | len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
|
---|
| 256 | strlen(typ->tp_name);
|
---|
| 257 | strncpy(pbuf, typ->tp_name, len);
|
---|
| 258 | pbuf += len;
|
---|
| 259 | *pbuf++ = '(';
|
---|
[2] | 260 |
|
---|
[391] | 261 | for (i=0; i < VISIBLE_SIZE(obj); i++) {
|
---|
| 262 | PyObject *val, *repr;
|
---|
| 263 | char *cname, *crepr;
|
---|
[2] | 264 |
|
---|
[391] | 265 | cname = typ->tp_members[i].name;
|
---|
[2] | 266 |
|
---|
[391] | 267 | val = PyTuple_GetItem(tup, i);
|
---|
| 268 | if (cname == NULL || val == NULL) {
|
---|
| 269 | return NULL;
|
---|
| 270 | }
|
---|
| 271 | repr = PyObject_Repr(val);
|
---|
| 272 | if (repr == NULL) {
|
---|
| 273 | Py_DECREF(tup);
|
---|
| 274 | return NULL;
|
---|
| 275 | }
|
---|
| 276 | crepr = PyString_AsString(repr);
|
---|
| 277 | if (crepr == NULL) {
|
---|
| 278 | Py_DECREF(tup);
|
---|
| 279 | Py_DECREF(repr);
|
---|
| 280 | return NULL;
|
---|
| 281 | }
|
---|
| 282 |
|
---|
| 283 | /* + 3: keep space for "=" and ", " */
|
---|
| 284 | len = strlen(cname) + strlen(crepr) + 3;
|
---|
| 285 | if ((pbuf+len) <= endofbuf) {
|
---|
| 286 | strcpy(pbuf, cname);
|
---|
| 287 | pbuf += strlen(cname);
|
---|
| 288 | *pbuf++ = '=';
|
---|
| 289 | strcpy(pbuf, crepr);
|
---|
| 290 | pbuf += strlen(crepr);
|
---|
| 291 | *pbuf++ = ',';
|
---|
| 292 | *pbuf++ = ' ';
|
---|
| 293 | removelast = 1;
|
---|
| 294 | Py_DECREF(repr);
|
---|
| 295 | }
|
---|
| 296 | else {
|
---|
| 297 | strcpy(pbuf, "...");
|
---|
| 298 | pbuf += 3;
|
---|
| 299 | removelast = 0;
|
---|
| 300 | Py_DECREF(repr);
|
---|
| 301 | break;
|
---|
| 302 | }
|
---|
| 303 | }
|
---|
| 304 | Py_DECREF(tup);
|
---|
| 305 | if (removelast) {
|
---|
| 306 | /* overwrite last ", " */
|
---|
| 307 | pbuf-=2;
|
---|
| 308 | }
|
---|
| 309 | *pbuf++ = ')';
|
---|
| 310 | *pbuf = '\0';
|
---|
| 311 |
|
---|
| 312 | return PyString_FromString(buf);
|
---|
[2] | 313 | }
|
---|
| 314 |
|
---|
| 315 | static PyObject *
|
---|
| 316 | structseq_concat(PyStructSequence *obj, PyObject *b)
|
---|
| 317 | {
|
---|
[391] | 318 | PyObject *tup, *result;
|
---|
| 319 | tup = make_tuple(obj);
|
---|
| 320 | result = PySequence_Concat(tup, b);
|
---|
| 321 | Py_DECREF(tup);
|
---|
| 322 | return result;
|
---|
[2] | 323 | }
|
---|
| 324 |
|
---|
| 325 | static PyObject *
|
---|
| 326 | structseq_repeat(PyStructSequence *obj, Py_ssize_t n)
|
---|
| 327 | {
|
---|
[391] | 328 | PyObject *tup, *result;
|
---|
| 329 | tup = make_tuple(obj);
|
---|
| 330 | result = PySequence_Repeat(tup, n);
|
---|
| 331 | Py_DECREF(tup);
|
---|
| 332 | return result;
|
---|
[2] | 333 | }
|
---|
| 334 |
|
---|
| 335 | static int
|
---|
| 336 | structseq_contains(PyStructSequence *obj, PyObject *o)
|
---|
| 337 | {
|
---|
[391] | 338 | PyObject *tup;
|
---|
| 339 | int result;
|
---|
| 340 | tup = make_tuple(obj);
|
---|
| 341 | if (!tup)
|
---|
| 342 | return -1;
|
---|
| 343 | result = PySequence_Contains(tup, o);
|
---|
| 344 | Py_DECREF(tup);
|
---|
| 345 | return result;
|
---|
[2] | 346 | }
|
---|
| 347 |
|
---|
| 348 | static long
|
---|
| 349 | structseq_hash(PyObject *obj)
|
---|
| 350 | {
|
---|
[391] | 351 | PyObject *tup;
|
---|
| 352 | long result;
|
---|
| 353 | tup = make_tuple((PyStructSequence*) obj);
|
---|
| 354 | if (!tup)
|
---|
| 355 | return -1;
|
---|
| 356 | result = PyObject_Hash(tup);
|
---|
| 357 | Py_DECREF(tup);
|
---|
| 358 | return result;
|
---|
[2] | 359 | }
|
---|
| 360 |
|
---|
| 361 | static PyObject *
|
---|
| 362 | structseq_richcompare(PyObject *obj, PyObject *o2, int op)
|
---|
| 363 | {
|
---|
[391] | 364 | PyObject *tup, *result;
|
---|
| 365 | tup = make_tuple((PyStructSequence*) obj);
|
---|
| 366 | result = PyObject_RichCompare(tup, o2, op);
|
---|
| 367 | Py_DECREF(tup);
|
---|
| 368 | return result;
|
---|
[2] | 369 | }
|
---|
| 370 |
|
---|
| 371 | static PyObject *
|
---|
| 372 | structseq_reduce(PyStructSequence* self)
|
---|
| 373 | {
|
---|
[391] | 374 | PyObject* tup;
|
---|
| 375 | PyObject* dict;
|
---|
| 376 | PyObject* result;
|
---|
| 377 | Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
|
---|
| 378 | int i;
|
---|
[2] | 379 |
|
---|
[391] | 380 | n_fields = REAL_SIZE(self);
|
---|
| 381 | n_visible_fields = VISIBLE_SIZE(self);
|
---|
| 382 | n_unnamed_fields = UNNAMED_FIELDS(self);
|
---|
| 383 | tup = PyTuple_New(n_visible_fields);
|
---|
| 384 | if (!tup) {
|
---|
| 385 | return NULL;
|
---|
| 386 | }
|
---|
[2] | 387 |
|
---|
[391] | 388 | dict = PyDict_New();
|
---|
| 389 | if (!dict) {
|
---|
| 390 | Py_DECREF(tup);
|
---|
| 391 | return NULL;
|
---|
| 392 | }
|
---|
[2] | 393 |
|
---|
[391] | 394 | for (i = 0; i < n_visible_fields; i++) {
|
---|
| 395 | Py_INCREF(self->ob_item[i]);
|
---|
| 396 | PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
|
---|
| 397 | }
|
---|
[2] | 398 |
|
---|
[391] | 399 | for (; i < n_fields; i++) {
|
---|
| 400 | char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
|
---|
| 401 | PyDict_SetItemString(dict, n,
|
---|
| 402 | self->ob_item[i]);
|
---|
| 403 | }
|
---|
[2] | 404 |
|
---|
[391] | 405 | result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
|
---|
| 406 |
|
---|
| 407 | Py_DECREF(tup);
|
---|
| 408 | Py_DECREF(dict);
|
---|
| 409 |
|
---|
| 410 | return result;
|
---|
[2] | 411 | }
|
---|
| 412 |
|
---|
| 413 | static PySequenceMethods structseq_as_sequence = {
|
---|
[391] | 414 | (lenfunc)structseq_length,
|
---|
| 415 | (binaryfunc)structseq_concat, /* sq_concat */
|
---|
| 416 | (ssizeargfunc)structseq_repeat, /* sq_repeat */
|
---|
| 417 | (ssizeargfunc)structseq_item, /* sq_item */
|
---|
| 418 | (ssizessizeargfunc)structseq_slice, /* sq_slice */
|
---|
| 419 | 0, /* sq_ass_item */
|
---|
| 420 | 0, /* sq_ass_slice */
|
---|
| 421 | (objobjproc)structseq_contains, /* sq_contains */
|
---|
[2] | 422 | };
|
---|
| 423 |
|
---|
| 424 | static PyMappingMethods structseq_as_mapping = {
|
---|
[391] | 425 | (lenfunc)structseq_length,
|
---|
| 426 | (binaryfunc)structseq_subscript,
|
---|
[2] | 427 | };
|
---|
| 428 |
|
---|
| 429 | static PyMethodDef structseq_methods[] = {
|
---|
[391] | 430 | {"__reduce__", (PyCFunction)structseq_reduce,
|
---|
| 431 | METH_NOARGS, NULL},
|
---|
| 432 | {NULL, NULL}
|
---|
[2] | 433 | };
|
---|
| 434 |
|
---|
| 435 | static PyTypeObject _struct_sequence_template = {
|
---|
[391] | 436 | PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
---|
| 437 | NULL, /* tp_name */
|
---|
| 438 | 0, /* tp_basicsize */
|
---|
| 439 | 0, /* tp_itemsize */
|
---|
| 440 | (destructor)structseq_dealloc, /* tp_dealloc */
|
---|
| 441 | 0, /* tp_print */
|
---|
| 442 | 0, /* tp_getattr */
|
---|
| 443 | 0, /* tp_setattr */
|
---|
| 444 | 0, /* tp_compare */
|
---|
| 445 | (reprfunc)structseq_repr, /* tp_repr */
|
---|
| 446 | 0, /* tp_as_number */
|
---|
| 447 | &structseq_as_sequence, /* tp_as_sequence */
|
---|
| 448 | &structseq_as_mapping, /* tp_as_mapping */
|
---|
| 449 | structseq_hash, /* tp_hash */
|
---|
| 450 | 0, /* tp_call */
|
---|
| 451 | 0, /* tp_str */
|
---|
| 452 | 0, /* tp_getattro */
|
---|
| 453 | 0, /* tp_setattro */
|
---|
| 454 | 0, /* tp_as_buffer */
|
---|
| 455 | Py_TPFLAGS_DEFAULT, /* tp_flags */
|
---|
| 456 | NULL, /* tp_doc */
|
---|
| 457 | 0, /* tp_traverse */
|
---|
| 458 | 0, /* tp_clear */
|
---|
| 459 | structseq_richcompare, /* tp_richcompare */
|
---|
| 460 | 0, /* tp_weaklistoffset */
|
---|
| 461 | 0, /* tp_iter */
|
---|
| 462 | 0, /* tp_iternext */
|
---|
| 463 | structseq_methods, /* tp_methods */
|
---|
| 464 | NULL, /* tp_members */
|
---|
| 465 | 0, /* tp_getset */
|
---|
| 466 | 0, /* tp_base */
|
---|
| 467 | 0, /* tp_dict */
|
---|
| 468 | 0, /* tp_descr_get */
|
---|
| 469 | 0, /* tp_descr_set */
|
---|
| 470 | 0, /* tp_dictoffset */
|
---|
| 471 | 0, /* tp_init */
|
---|
| 472 | 0, /* tp_alloc */
|
---|
| 473 | structseq_new, /* tp_new */
|
---|
[2] | 474 | };
|
---|
| 475 |
|
---|
| 476 | void
|
---|
| 477 | PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
|
---|
| 478 | {
|
---|
[391] | 479 | PyObject *dict;
|
---|
| 480 | PyMemberDef* members;
|
---|
| 481 | int n_members, n_unnamed_members, i, k;
|
---|
[2] | 482 |
|
---|
| 483 | #ifdef Py_TRACE_REFS
|
---|
[391] | 484 | /* if the type object was chained, unchain it first
|
---|
| 485 | before overwriting its storage */
|
---|
| 486 | if (type->_ob_next) {
|
---|
| 487 | _Py_ForgetReference((PyObject*)type);
|
---|
| 488 | }
|
---|
[2] | 489 | #endif
|
---|
| 490 |
|
---|
[391] | 491 | n_unnamed_members = 0;
|
---|
| 492 | for (i = 0; desc->fields[i].name != NULL; ++i)
|
---|
| 493 | if (desc->fields[i].name == PyStructSequence_UnnamedField)
|
---|
| 494 | n_unnamed_members++;
|
---|
| 495 | n_members = i;
|
---|
[2] | 496 |
|
---|
[391] | 497 | memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
|
---|
| 498 | type->tp_name = desc->name;
|
---|
| 499 | type->tp_doc = desc->doc;
|
---|
| 500 | type->tp_basicsize = sizeof(PyStructSequence)+
|
---|
| 501 | sizeof(PyObject*)*(n_members-1);
|
---|
| 502 | type->tp_itemsize = 0;
|
---|
[2] | 503 |
|
---|
[391] | 504 | members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
|
---|
| 505 | if (members == NULL)
|
---|
| 506 | return;
|
---|
[2] | 507 |
|
---|
[391] | 508 | for (i = k = 0; i < n_members; ++i) {
|
---|
| 509 | if (desc->fields[i].name == PyStructSequence_UnnamedField)
|
---|
| 510 | continue;
|
---|
| 511 | members[k].name = desc->fields[i].name;
|
---|
| 512 | members[k].type = T_OBJECT;
|
---|
| 513 | members[k].offset = offsetof(PyStructSequence, ob_item)
|
---|
| 514 | + i * sizeof(PyObject*);
|
---|
| 515 | members[k].flags = READONLY;
|
---|
| 516 | members[k].doc = desc->fields[i].doc;
|
---|
| 517 | k++;
|
---|
| 518 | }
|
---|
| 519 | members[k].name = NULL;
|
---|
[2] | 520 |
|
---|
[391] | 521 | type->tp_members = members;
|
---|
[2] | 522 |
|
---|
[391] | 523 | if (PyType_Ready(type) < 0)
|
---|
| 524 | return;
|
---|
| 525 | Py_INCREF(type);
|
---|
[2] | 526 |
|
---|
[391] | 527 | dict = type->tp_dict;
|
---|
| 528 | #define SET_DICT_FROM_INT(key, value) \
|
---|
| 529 | do { \
|
---|
| 530 | PyObject *v = PyInt_FromLong((long) value); \
|
---|
| 531 | if (v != NULL) { \
|
---|
| 532 | PyDict_SetItemString(dict, key, v); \
|
---|
| 533 | Py_DECREF(v); \
|
---|
| 534 | } \
|
---|
| 535 | } while (0)
|
---|
| 536 |
|
---|
| 537 | SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
|
---|
| 538 | SET_DICT_FROM_INT(real_length_key, n_members);
|
---|
| 539 | SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
|
---|
[2] | 540 | }
|
---|