LCOV - code coverage report
Current view: top level - Objects - structseq.c (source / functions) Hit Total Coverage
Test: CPython lcov report Lines: 43 243 17.7 %
Date: 2017-04-19 Functions: 3 16 18.8 %

          Line data    Source code
       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          12 : PyStructSequence_New(PyTypeObject *type)
      31             : {
      32             :     PyStructSequence *obj;
      33             : 
      34          12 :     obj = PyObject_New(PyStructSequence, type);
      35          12 :     if (obj == NULL)
      36           0 :         return NULL;
      37          12 :     Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
      38             : 
      39          12 :     return (PyObject*) obj;
      40             : }
      41             : 
      42             : static void
      43          12 : structseq_dealloc(PyStructSequence *obj)
      44             : {
      45             :     Py_ssize_t i, size;
      46             : 
      47          12 :     size = REAL_SIZE(obj);
      48         114 :     for (i = 0; i < size; ++i) {
      49         102 :         Py_XDECREF(obj->ob_item[i]);
      50             :     }
      51          12 :     PyObject_Del(obj);
      52          12 : }
      53             : 
      54             : static Py_ssize_t
      55           0 : structseq_length(PyStructSequence *obj)
      56             : {
      57           0 :     return VISIBLE_SIZE(obj);
      58             : }
      59             : 
      60             : static PyObject*
      61           0 : structseq_item(PyStructSequence *obj, Py_ssize_t i)
      62             : {
      63           0 :     if (i < 0 || i >= VISIBLE_SIZE(obj)) {
      64           0 :         PyErr_SetString(PyExc_IndexError, "tuple index out of range");
      65           0 :         return NULL;
      66             :     }
      67           0 :     Py_INCREF(obj->ob_item[i]);
      68           0 :     return obj->ob_item[i];
      69             : }
      70             : 
      71             : static PyObject*
      72           0 : structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high)
      73             : {
      74             :     PyTupleObject *np;
      75             :     Py_ssize_t i;
      76             : 
      77           0 :     if (low < 0)
      78           0 :         low = 0;
      79           0 :     if (high > VISIBLE_SIZE(obj))
      80           0 :         high = VISIBLE_SIZE(obj);
      81           0 :     if (high < low)
      82           0 :         high = low;
      83           0 :     np = (PyTupleObject *)PyTuple_New(high-low);
      84           0 :     if (np == NULL)
      85           0 :         return NULL;
      86           0 :     for(i = low; i < high; ++i) {
      87           0 :         PyObject *v = obj->ob_item[i];
      88           0 :         Py_INCREF(v);
      89           0 :         PyTuple_SET_ITEM(np, i-low, v);
      90             :     }
      91           0 :     return (PyObject *) np;
      92             : }
      93             : 
      94             : static PyObject *
      95           0 : structseq_subscript(PyStructSequence *self, PyObject *item)
      96             : {
      97           0 :     if (PyIndex_Check(item)) {
      98           0 :         Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
      99           0 :         if (i == -1 && PyErr_Occurred())
     100           0 :             return NULL;
     101             : 
     102           0 :         if (i < 0)
     103           0 :             i += VISIBLE_SIZE(self);
     104             : 
     105           0 :         if (i < 0 || i >= VISIBLE_SIZE(self)) {
     106           0 :             PyErr_SetString(PyExc_IndexError,
     107             :                 "tuple index out of range");
     108           0 :             return NULL;
     109             :         }
     110           0 :         Py_INCREF(self->ob_item[i]);
     111           0 :         return self->ob_item[i];
     112             :     }
     113           0 :     else if (PySlice_Check(item)) {
     114             :         Py_ssize_t start, stop, step, slicelen, cur, i;
     115             :         PyObject *result;
     116             : 
     117           0 :         if (PySlice_GetIndicesEx((PySliceObject *)item,
     118             :                                  VISIBLE_SIZE(self), &start, &stop,
     119             :                                  &step, &slicelen) < 0) {
     120           0 :             return NULL;
     121             :         }
     122           0 :         if (slicelen <= 0)
     123           0 :             return PyTuple_New(0);
     124           0 :         result = PyTuple_New(slicelen);
     125           0 :         if (result == NULL)
     126           0 :             return NULL;
     127           0 :         for (cur = start, i = 0; i < slicelen;
     128           0 :              cur += step, i++) {
     129           0 :             PyObject *v = self->ob_item[cur];
     130           0 :             Py_INCREF(v);
     131           0 :             PyTuple_SET_ITEM(result, i, v);
     132             :         }
     133           0 :         return result;
     134             :     }
     135             :     else {
     136           0 :         PyErr_SetString(PyExc_TypeError,
     137             :                         "structseq index must be integer");
     138           0 :         return NULL;
     139             :     }
     140             : }
     141             : 
     142             : static PyObject *
     143           0 : structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
     144             : {
     145           0 :     PyObject *arg = NULL;
     146           0 :     PyObject *dict = NULL;
     147             :     PyObject *ob;
     148           0 :     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           0 :     if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
     153             :                                      kwlist, &arg, &dict))
     154           0 :         return NULL;
     155             : 
     156           0 :     arg = PySequence_Fast(arg, "constructor requires a sequence");
     157             : 
     158           0 :     if (!arg) {
     159           0 :         return NULL;
     160             :     }
     161             : 
     162           0 :     if (dict && !PyDict_Check(dict)) {
     163           0 :         PyErr_Format(PyExc_TypeError,
     164             :                      "%.500s() takes a dict as second arg, if any",
     165             :                      type->tp_name);
     166           0 :         Py_DECREF(arg);
     167           0 :         return NULL;
     168             :     }
     169             : 
     170           0 :     len = PySequence_Fast_GET_SIZE(arg);
     171           0 :     min_len = VISIBLE_SIZE_TP(type);
     172           0 :     max_len = REAL_SIZE_TP(type);
     173           0 :     n_unnamed_fields = UNNAMED_FIELDS_TP(type);
     174             : 
     175           0 :     if (min_len != max_len) {
     176           0 :         if (len < min_len) {
     177           0 :             PyErr_Format(PyExc_TypeError,
     178             :                 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
     179             :                 type->tp_name, min_len, len);
     180           0 :             Py_DECREF(arg);
     181           0 :             return NULL;
     182             :         }
     183             : 
     184           0 :         if (len > max_len) {
     185           0 :             PyErr_Format(PyExc_TypeError,
     186             :                          "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
     187             :                          type->tp_name, max_len, len);
     188           0 :             Py_DECREF(arg);
     189           0 :             return NULL;
     190             :         }
     191             :     }
     192             :     else {
     193           0 :         if (len != min_len) {
     194           0 :             PyErr_Format(PyExc_TypeError,
     195             :                          "%.500s() takes a %zd-sequence (%zd-sequence given)",
     196             :                          type->tp_name, min_len, len);
     197           0 :             Py_DECREF(arg);
     198           0 :             return NULL;
     199             :         }
     200             :     }
     201             : 
     202           0 :     res = (PyStructSequence*) PyStructSequence_New(type);
     203           0 :     if (res == NULL) {
     204           0 :         Py_DECREF(arg);
     205           0 :         return NULL;
     206             :     }
     207           0 :     for (i = 0; i < len; ++i) {
     208           0 :         PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
     209           0 :         Py_INCREF(v);
     210           0 :         res->ob_item[i] = v;
     211             :     }
     212           0 :     for (; i < max_len; ++i) {
     213           0 :         if (dict && (ob = PyDict_GetItemString(
     214           0 :             dict, type->tp_members[i-n_unnamed_fields].name))) {
     215             :         }
     216             :         else {
     217           0 :             ob = Py_None;
     218             :         }
     219           0 :         Py_INCREF(ob);
     220           0 :         res->ob_item[i] = ob;
     221             :     }
     222             : 
     223           0 :     Py_DECREF(arg);
     224           0 :     return (PyObject*) res;
     225             : }
     226             : 
     227             : static PyObject *
     228           0 : make_tuple(PyStructSequence *obj)
     229             : {
     230           0 :     return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
     231             : }
     232             : 
     233             : static PyObject *
     234           0 : 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           0 :     PyTypeObject *typ = Py_TYPE(obj);
     242           0 :     int i, removelast = 0;
     243             :     Py_ssize_t len;
     244             :     char buf[REPR_BUFFER_SIZE];
     245           0 :     char *endofbuf, *pbuf = buf;
     246             : 
     247             :     /* pointer to end of writeable buffer; safes space for "...)\0" */
     248           0 :     endofbuf= &buf[REPR_BUFFER_SIZE-5];
     249             : 
     250           0 :     if ((tup = make_tuple(obj)) == NULL) {
     251           0 :         return NULL;
     252             :     }
     253             : 
     254             :     /* "typename(", limited to  TYPE_MAXSIZE */
     255           0 :     len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
     256           0 :                             strlen(typ->tp_name);
     257           0 :     strncpy(pbuf, typ->tp_name, len);
     258           0 :     pbuf += len;
     259           0 :     *pbuf++ = '(';
     260             : 
     261           0 :     for (i=0; i < VISIBLE_SIZE(obj); i++) {
     262             :         PyObject *val, *repr;
     263             :         char *cname, *crepr;
     264             : 
     265           0 :         cname = typ->tp_members[i].name;
     266             : 
     267           0 :         val = PyTuple_GetItem(tup, i);
     268           0 :         if (cname == NULL || val == NULL) {
     269           0 :             return NULL;
     270             :         }
     271           0 :         repr = PyObject_Repr(val);
     272           0 :         if (repr == NULL) {
     273           0 :             Py_DECREF(tup);
     274           0 :             return NULL;
     275             :         }
     276           0 :         crepr = PyString_AsString(repr);
     277           0 :         if (crepr == NULL) {
     278           0 :             Py_DECREF(tup);
     279           0 :             Py_DECREF(repr);
     280           0 :             return NULL;
     281             :         }
     282             : 
     283             :         /* + 3: keep space for "=" and ", " */
     284           0 :         len = strlen(cname) + strlen(crepr) + 3;
     285           0 :         if ((pbuf+len) <= endofbuf) {
     286           0 :             strcpy(pbuf, cname);
     287           0 :             pbuf += strlen(cname);
     288           0 :             *pbuf++ = '=';
     289           0 :             strcpy(pbuf, crepr);
     290           0 :             pbuf += strlen(crepr);
     291           0 :             *pbuf++ = ',';
     292           0 :             *pbuf++ = ' ';
     293           0 :             removelast = 1;
     294           0 :             Py_DECREF(repr);
     295             :         }
     296             :         else {
     297           0 :             strcpy(pbuf, "...");
     298           0 :             pbuf += 3;
     299           0 :             removelast = 0;
     300           0 :             Py_DECREF(repr);
     301           0 :             break;
     302             :         }
     303             :     }
     304           0 :     Py_DECREF(tup);
     305           0 :     if (removelast) {
     306             :         /* overwrite last ", " */
     307           0 :         pbuf-=2;
     308             :     }
     309           0 :     *pbuf++ = ')';
     310           0 :     *pbuf = '\0';
     311             : 
     312           0 :     return PyString_FromString(buf);
     313             : }
     314             : 
     315             : static PyObject *
     316           0 : structseq_concat(PyStructSequence *obj, PyObject *b)
     317             : {
     318             :     PyObject *tup, *result;
     319           0 :     tup = make_tuple(obj);
     320           0 :     result = PySequence_Concat(tup, b);
     321           0 :     Py_DECREF(tup);
     322           0 :     return result;
     323             : }
     324             : 
     325             : static PyObject *
     326           0 : structseq_repeat(PyStructSequence *obj, Py_ssize_t n)
     327             : {
     328             :     PyObject *tup, *result;
     329           0 :     tup = make_tuple(obj);
     330           0 :     result = PySequence_Repeat(tup, n);
     331           0 :     Py_DECREF(tup);
     332           0 :     return result;
     333             : }
     334             : 
     335             : static int
     336           0 : structseq_contains(PyStructSequence *obj, PyObject *o)
     337             : {
     338             :     PyObject *tup;
     339             :     int result;
     340           0 :     tup = make_tuple(obj);
     341           0 :     if (!tup)
     342           0 :         return -1;
     343           0 :     result = PySequence_Contains(tup, o);
     344           0 :     Py_DECREF(tup);
     345           0 :     return result;
     346             : }
     347             : 
     348             : static long
     349           0 : structseq_hash(PyObject *obj)
     350             : {
     351             :     PyObject *tup;
     352             :     long result;
     353           0 :     tup = make_tuple((PyStructSequence*) obj);
     354           0 :     if (!tup)
     355           0 :         return -1;
     356           0 :     result = PyObject_Hash(tup);
     357           0 :     Py_DECREF(tup);
     358           0 :     return result;
     359             : }
     360             : 
     361             : static PyObject *
     362           0 : structseq_richcompare(PyObject *obj, PyObject *o2, int op)
     363             : {
     364             :     PyObject *tup, *result;
     365           0 :     tup = make_tuple((PyStructSequence*) obj);
     366           0 :     result = PyObject_RichCompare(tup, o2, op);
     367           0 :     Py_DECREF(tup);
     368           0 :     return result;
     369             : }
     370             : 
     371             : static PyObject *
     372           0 : 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           0 :     n_fields = REAL_SIZE(self);
     381           0 :     n_visible_fields = VISIBLE_SIZE(self);
     382           0 :     n_unnamed_fields = UNNAMED_FIELDS(self);
     383           0 :     tup = PyTuple_New(n_visible_fields);
     384           0 :     if (!tup) {
     385           0 :         return NULL;
     386             :     }
     387             : 
     388           0 :     dict = PyDict_New();
     389           0 :     if (!dict) {
     390           0 :         Py_DECREF(tup);
     391           0 :         return NULL;
     392             :     }
     393             : 
     394           0 :     for (i = 0; i < n_visible_fields; i++) {
     395           0 :         Py_INCREF(self->ob_item[i]);
     396           0 :         PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
     397             :     }
     398             : 
     399           0 :     for (; i < n_fields; i++) {
     400           0 :         char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
     401           0 :         PyDict_SetItemString(dict, n,
     402             :                              self->ob_item[i]);
     403             :     }
     404             : 
     405           0 :     result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
     406             : 
     407           0 :     Py_DECREF(tup);
     408           0 :     Py_DECREF(dict);
     409             : 
     410           0 :     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          24 : 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          24 :     n_unnamed_members = 0;
     492         252 :     for (i = 0; desc->fields[i].name != NULL; ++i)
     493         228 :         if (desc->fields[i].name == PyStructSequence_UnnamedField)
     494           9 :             n_unnamed_members++;
     495          24 :     n_members = i;
     496             : 
     497          24 :     memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
     498          24 :     type->tp_name = desc->name;
     499          24 :     type->tp_doc = desc->doc;
     500          24 :     type->tp_basicsize = sizeof(PyStructSequence)+
     501          24 :         sizeof(PyObject*)*(n_members-1);
     502          24 :     type->tp_itemsize = 0;
     503             : 
     504          24 :     members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
     505          24 :     if (members == NULL)
     506           0 :         return;
     507             : 
     508         252 :     for (i = k = 0; i < n_members; ++i) {
     509         228 :         if (desc->fields[i].name == PyStructSequence_UnnamedField)
     510           9 :             continue;
     511         219 :         members[k].name = desc->fields[i].name;
     512         219 :         members[k].type = T_OBJECT;
     513         438 :         members[k].offset = offsetof(PyStructSequence, ob_item)
     514         219 :           + i * sizeof(PyObject*);
     515         219 :         members[k].flags = READONLY;
     516         219 :         members[k].doc = desc->fields[i].doc;
     517         219 :         k++;
     518             :     }
     519          24 :     members[k].name = NULL;
     520             : 
     521          24 :     type->tp_members = members;
     522             : 
     523          24 :     if (PyType_Ready(type) < 0)
     524           0 :         return;
     525          24 :     Py_INCREF(type);
     526             : 
     527          24 :     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          24 :     SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
     538          24 :     SET_DICT_FROM_INT(real_length_key, n_members);
     539          24 :     SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
     540             : }

Generated by: LCOV version 1.10