| 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 |
|
|---|
| 12 | /* Fields with this name have only a field index, not a field name.
|
|---|
| 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 | {
|
|---|
| 32 | PyStructSequence *obj;
|
|---|
| 33 |
|
|---|
| 34 | obj = PyObject_New(PyStructSequence, type);
|
|---|
| 35 | if (obj == NULL)
|
|---|
| 36 | return NULL;
|
|---|
| 37 | Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
|
|---|
| 38 |
|
|---|
| 39 | return (PyObject*) obj;
|
|---|
| 40 | }
|
|---|
| 41 |
|
|---|
| 42 | static void
|
|---|
| 43 | structseq_dealloc(PyStructSequence *obj)
|
|---|
| 44 | {
|
|---|
| 45 | Py_ssize_t i, size;
|
|---|
| 46 |
|
|---|
| 47 | size = REAL_SIZE(obj);
|
|---|
| 48 | for (i = 0; i < size; ++i) {
|
|---|
| 49 | Py_XDECREF(obj->ob_item[i]);
|
|---|
| 50 | }
|
|---|
| 51 | PyObject_Del(obj);
|
|---|
| 52 | }
|
|---|
| 53 |
|
|---|
| 54 | static Py_ssize_t
|
|---|
| 55 | structseq_length(PyStructSequence *obj)
|
|---|
| 56 | {
|
|---|
| 57 | return VISIBLE_SIZE(obj);
|
|---|
| 58 | }
|
|---|
| 59 |
|
|---|
| 60 | static PyObject*
|
|---|
| 61 | structseq_item(PyStructSequence *obj, Py_ssize_t i)
|
|---|
| 62 | {
|
|---|
| 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];
|
|---|
| 69 | }
|
|---|
| 70 |
|
|---|
| 71 | static PyObject*
|
|---|
| 72 | structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high)
|
|---|
| 73 | {
|
|---|
| 74 | PyTupleObject *np;
|
|---|
| 75 | Py_ssize_t i;
|
|---|
| 76 |
|
|---|
| 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;
|
|---|
| 92 | }
|
|---|
| 93 |
|
|---|
| 94 | static PyObject *
|
|---|
| 95 | structseq_subscript(PyStructSequence *self, PyObject *item)
|
|---|
| 96 | {
|
|---|
| 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;
|
|---|
| 101 |
|
|---|
| 102 | if (i < 0)
|
|---|
| 103 | i += VISIBLE_SIZE(self);
|
|---|
| 104 |
|
|---|
| 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 | }
|
|---|
| 140 | }
|
|---|
| 141 |
|
|---|
| 142 | static PyObject *
|
|---|
| 143 | structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
|
|---|
| 144 | {
|
|---|
| 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};
|
|---|
| 151 |
|
|---|
| 152 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
|
|---|
| 153 | kwlist, &arg, &dict))
|
|---|
| 154 | return NULL;
|
|---|
| 155 |
|
|---|
| 156 | arg = PySequence_Fast(arg, "constructor requires a sequence");
|
|---|
| 157 |
|
|---|
| 158 | if (!arg) {
|
|---|
| 159 | return NULL;
|
|---|
| 160 | }
|
|---|
| 161 |
|
|---|
| 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 | }
|
|---|
| 169 |
|
|---|
| 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);
|
|---|
| 174 |
|
|---|
| 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 | }
|
|---|
| 183 |
|
|---|
| 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 | }
|
|---|
| 201 |
|
|---|
| 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;
|
|---|
| 225 | }
|
|---|
| 226 |
|
|---|
| 227 | static PyObject *
|
|---|
| 228 | make_tuple(PyStructSequence *obj)
|
|---|
| 229 | {
|
|---|
| 230 | return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
|
|---|
| 231 | }
|
|---|
| 232 |
|
|---|
| 233 | static PyObject *
|
|---|
| 234 | structseq_repr(PyStructSequence *obj)
|
|---|
| 235 | {
|
|---|
| 236 | /* buffer and type size were chosen well considered. */
|
|---|
| 237 | #define REPR_BUFFER_SIZE 512
|
|---|
| 238 | #define TYPE_MAXSIZE 100
|
|---|
| 239 |
|
|---|
| 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;
|
|---|
| 246 |
|
|---|
| 247 | /* pointer to end of writeable buffer; safes space for "...)\0" */
|
|---|
| 248 | endofbuf= &buf[REPR_BUFFER_SIZE-5];
|
|---|
| 249 |
|
|---|
| 250 | if ((tup = make_tuple(obj)) == NULL) {
|
|---|
| 251 | return NULL;
|
|---|
| 252 | }
|
|---|
| 253 |
|
|---|
| 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++ = '(';
|
|---|
| 260 |
|
|---|
| 261 | for (i=0; i < VISIBLE_SIZE(obj); i++) {
|
|---|
| 262 | PyObject *val, *repr;
|
|---|
| 263 | char *cname, *crepr;
|
|---|
| 264 |
|
|---|
| 265 | cname = typ->tp_members[i].name;
|
|---|
| 266 |
|
|---|
| 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);
|
|---|
| 313 | }
|
|---|
| 314 |
|
|---|
| 315 | static PyObject *
|
|---|
| 316 | structseq_concat(PyStructSequence *obj, PyObject *b)
|
|---|
| 317 | {
|
|---|
| 318 | PyObject *tup, *result;
|
|---|
| 319 | tup = make_tuple(obj);
|
|---|
| 320 | result = PySequence_Concat(tup, b);
|
|---|
| 321 | Py_DECREF(tup);
|
|---|
| 322 | return result;
|
|---|
| 323 | }
|
|---|
| 324 |
|
|---|
| 325 | static PyObject *
|
|---|
| 326 | structseq_repeat(PyStructSequence *obj, Py_ssize_t n)
|
|---|
| 327 | {
|
|---|
| 328 | PyObject *tup, *result;
|
|---|
| 329 | tup = make_tuple(obj);
|
|---|
| 330 | result = PySequence_Repeat(tup, n);
|
|---|
| 331 | Py_DECREF(tup);
|
|---|
| 332 | return result;
|
|---|
| 333 | }
|
|---|
| 334 |
|
|---|
| 335 | static int
|
|---|
| 336 | structseq_contains(PyStructSequence *obj, PyObject *o)
|
|---|
| 337 | {
|
|---|
| 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;
|
|---|
| 346 | }
|
|---|
| 347 |
|
|---|
| 348 | static long
|
|---|
| 349 | structseq_hash(PyObject *obj)
|
|---|
| 350 | {
|
|---|
| 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;
|
|---|
| 359 | }
|
|---|
| 360 |
|
|---|
| 361 | static PyObject *
|
|---|
| 362 | structseq_richcompare(PyObject *obj, PyObject *o2, int op)
|
|---|
| 363 | {
|
|---|
| 364 | PyObject *tup, *result;
|
|---|
| 365 | tup = make_tuple((PyStructSequence*) obj);
|
|---|
| 366 | result = PyObject_RichCompare(tup, o2, op);
|
|---|
| 367 | Py_DECREF(tup);
|
|---|
| 368 | return result;
|
|---|
| 369 | }
|
|---|
| 370 |
|
|---|
| 371 | static PyObject *
|
|---|
| 372 | structseq_reduce(PyStructSequence* self)
|
|---|
| 373 | {
|
|---|
| 374 | PyObject* tup;
|
|---|
| 375 | PyObject* dict;
|
|---|
| 376 | PyObject* result;
|
|---|
| 377 | Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
|
|---|
| 378 | int i;
|
|---|
| 379 |
|
|---|
| 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 | }
|
|---|
| 387 |
|
|---|
| 388 | dict = PyDict_New();
|
|---|
| 389 | if (!dict) {
|
|---|
| 390 | Py_DECREF(tup);
|
|---|
| 391 | return NULL;
|
|---|
| 392 | }
|
|---|
| 393 |
|
|---|
| 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 | }
|
|---|
| 398 |
|
|---|
| 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 | }
|
|---|
| 404 |
|
|---|
| 405 | result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
|
|---|
| 406 |
|
|---|
| 407 | Py_DECREF(tup);
|
|---|
| 408 | Py_DECREF(dict);
|
|---|
| 409 |
|
|---|
| 410 | return result;
|
|---|
| 411 | }
|
|---|
| 412 |
|
|---|
| 413 | static PySequenceMethods structseq_as_sequence = {
|
|---|
| 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 */
|
|---|
| 422 | };
|
|---|
| 423 |
|
|---|
| 424 | static PyMappingMethods structseq_as_mapping = {
|
|---|
| 425 | (lenfunc)structseq_length,
|
|---|
| 426 | (binaryfunc)structseq_subscript,
|
|---|
| 427 | };
|
|---|
| 428 |
|
|---|
| 429 | static PyMethodDef structseq_methods[] = {
|
|---|
| 430 | {"__reduce__", (PyCFunction)structseq_reduce,
|
|---|
| 431 | METH_NOARGS, NULL},
|
|---|
| 432 | {NULL, NULL}
|
|---|
| 433 | };
|
|---|
| 434 |
|
|---|
| 435 | static PyTypeObject _struct_sequence_template = {
|
|---|
| 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 */
|
|---|
| 474 | };
|
|---|
| 475 |
|
|---|
| 476 | void
|
|---|
| 477 | PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
|
|---|
| 478 | {
|
|---|
| 479 | PyObject *dict;
|
|---|
| 480 | PyMemberDef* members;
|
|---|
| 481 | int n_members, n_unnamed_members, i, k;
|
|---|
| 482 |
|
|---|
| 483 | #ifdef Py_TRACE_REFS
|
|---|
| 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 | }
|
|---|
| 489 | #endif
|
|---|
| 490 |
|
|---|
| 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;
|
|---|
| 496 |
|
|---|
| 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;
|
|---|
| 503 |
|
|---|
| 504 | members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
|
|---|
| 505 | if (members == NULL)
|
|---|
| 506 | return;
|
|---|
| 507 |
|
|---|
| 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;
|
|---|
| 520 |
|
|---|
| 521 | type->tp_members = members;
|
|---|
| 522 |
|
|---|
| 523 | if (PyType_Ready(type) < 0)
|
|---|
| 524 | return;
|
|---|
| 525 | Py_INCREF(type);
|
|---|
| 526 |
|
|---|
| 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);
|
|---|
| 540 | }
|
|---|