+++ /dev/null
-/* Implementation helper: a struct that looks like a tuple. See timemodule\r
- and posixmodule for example uses. */\r
-\r
-#include "Python.h"\r
-#include "structmember.h"\r
-#include "structseq.h"\r
-\r
-static char visible_length_key[] = "n_sequence_fields";\r
-static char real_length_key[] = "n_fields";\r
-static char unnamed_fields_key[] = "n_unnamed_fields";\r
-\r
-/* Fields with this name have only a field index, not a field name.\r
- They are only allowed for indices < n_visible_fields. */\r
-char *PyStructSequence_UnnamedField = "unnamed field";\r
-\r
-#define VISIBLE_SIZE(op) Py_SIZE(op)\r
-#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \\r
- PyDict_GetItemString((tp)->tp_dict, visible_length_key))\r
-\r
-#define REAL_SIZE_TP(tp) PyInt_AsLong( \\r
- PyDict_GetItemString((tp)->tp_dict, real_length_key))\r
-#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))\r
-\r
-#define UNNAMED_FIELDS_TP(tp) PyInt_AsLong( \\r
- PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))\r
-#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))\r
-\r
-\r
-PyObject *\r
-PyStructSequence_New(PyTypeObject *type)\r
-{\r
- PyStructSequence *obj;\r
-\r
- obj = PyObject_New(PyStructSequence, type);\r
- if (obj == NULL)\r
- return NULL;\r
- Py_SIZE(obj) = VISIBLE_SIZE_TP(type);\r
-\r
- return (PyObject*) obj;\r
-}\r
-\r
-static void\r
-structseq_dealloc(PyStructSequence *obj)\r
-{\r
- Py_ssize_t i, size;\r
-\r
- size = REAL_SIZE(obj);\r
- for (i = 0; i < size; ++i) {\r
- Py_XDECREF(obj->ob_item[i]);\r
- }\r
- PyObject_Del(obj);\r
-}\r
-\r
-static Py_ssize_t\r
-structseq_length(PyStructSequence *obj)\r
-{\r
- return VISIBLE_SIZE(obj);\r
-}\r
-\r
-static PyObject*\r
-structseq_item(PyStructSequence *obj, Py_ssize_t i)\r
-{\r
- if (i < 0 || i >= VISIBLE_SIZE(obj)) {\r
- PyErr_SetString(PyExc_IndexError, "tuple index out of range");\r
- return NULL;\r
- }\r
- Py_INCREF(obj->ob_item[i]);\r
- return obj->ob_item[i];\r
-}\r
-\r
-static PyObject*\r
-structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high)\r
-{\r
- PyTupleObject *np;\r
- Py_ssize_t i;\r
-\r
- if (low < 0)\r
- low = 0;\r
- if (high > VISIBLE_SIZE(obj))\r
- high = VISIBLE_SIZE(obj);\r
- if (high < low)\r
- high = low;\r
- np = (PyTupleObject *)PyTuple_New(high-low);\r
- if (np == NULL)\r
- return NULL;\r
- for(i = low; i < high; ++i) {\r
- PyObject *v = obj->ob_item[i];\r
- Py_INCREF(v);\r
- PyTuple_SET_ITEM(np, i-low, v);\r
- }\r
- return (PyObject *) np;\r
-}\r
-\r
-static PyObject *\r
-structseq_subscript(PyStructSequence *self, PyObject *item)\r
-{\r
- if (PyIndex_Check(item)) {\r
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);\r
- if (i == -1 && PyErr_Occurred())\r
- return NULL;\r
-\r
- if (i < 0)\r
- i += VISIBLE_SIZE(self);\r
-\r
- if (i < 0 || i >= VISIBLE_SIZE(self)) {\r
- PyErr_SetString(PyExc_IndexError,\r
- "tuple index out of range");\r
- return NULL;\r
- }\r
- Py_INCREF(self->ob_item[i]);\r
- return self->ob_item[i];\r
- }\r
- else if (PySlice_Check(item)) {\r
- Py_ssize_t start, stop, step, slicelen, cur, i;\r
- PyObject *result;\r
-\r
- if (PySlice_GetIndicesEx((PySliceObject *)item,\r
- VISIBLE_SIZE(self), &start, &stop,\r
- &step, &slicelen) < 0) {\r
- return NULL;\r
- }\r
- if (slicelen <= 0)\r
- return PyTuple_New(0);\r
- result = PyTuple_New(slicelen);\r
- if (result == NULL)\r
- return NULL;\r
- for (cur = start, i = 0; i < slicelen;\r
- cur += step, i++) {\r
- PyObject *v = self->ob_item[cur];\r
- Py_INCREF(v);\r
- PyTuple_SET_ITEM(result, i, v);\r
- }\r
- return result;\r
- }\r
- else {\r
- PyErr_SetString(PyExc_TypeError,\r
- "structseq index must be integer");\r
- return NULL;\r
- }\r
-}\r
-\r
-static PyObject *\r
-structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r
-{\r
- PyObject *arg = NULL;\r
- PyObject *dict = NULL;\r
- PyObject *ob;\r
- PyStructSequence *res = NULL;\r
- Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;\r
- static char *kwlist[] = {"sequence", "dict", 0};\r
-\r
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",\r
- kwlist, &arg, &dict))\r
- return NULL;\r
-\r
- arg = PySequence_Fast(arg, "constructor requires a sequence");\r
-\r
- if (!arg) {\r
- return NULL;\r
- }\r
-\r
- if (dict && !PyDict_Check(dict)) {\r
- PyErr_Format(PyExc_TypeError,\r
- "%.500s() takes a dict as second arg, if any",\r
- type->tp_name);\r
- Py_DECREF(arg);\r
- return NULL;\r
- }\r
-\r
- len = PySequence_Fast_GET_SIZE(arg);\r
- min_len = VISIBLE_SIZE_TP(type);\r
- max_len = REAL_SIZE_TP(type);\r
- n_unnamed_fields = UNNAMED_FIELDS_TP(type);\r
-\r
- if (min_len != max_len) {\r
- if (len < min_len) {\r
- PyErr_Format(PyExc_TypeError,\r
- "%.500s() takes an at least %zd-sequence (%zd-sequence given)",\r
- type->tp_name, min_len, len);\r
- Py_DECREF(arg);\r
- return NULL;\r
- }\r
-\r
- if (len > max_len) {\r
- PyErr_Format(PyExc_TypeError,\r
- "%.500s() takes an at most %zd-sequence (%zd-sequence given)",\r
- type->tp_name, max_len, len);\r
- Py_DECREF(arg);\r
- return NULL;\r
- }\r
- }\r
- else {\r
- if (len != min_len) {\r
- PyErr_Format(PyExc_TypeError,\r
- "%.500s() takes a %zd-sequence (%zd-sequence given)",\r
- type->tp_name, min_len, len);\r
- Py_DECREF(arg);\r
- return NULL;\r
- }\r
- }\r
-\r
- res = (PyStructSequence*) PyStructSequence_New(type);\r
- if (res == NULL) {\r
- return NULL;\r
- }\r
- for (i = 0; i < len; ++i) {\r
- PyObject *v = PySequence_Fast_GET_ITEM(arg, i);\r
- Py_INCREF(v);\r
- res->ob_item[i] = v;\r
- }\r
- for (; i < max_len; ++i) {\r
- if (dict && (ob = PyDict_GetItemString(\r
- dict, type->tp_members[i-n_unnamed_fields].name))) {\r
- }\r
- else {\r
- ob = Py_None;\r
- }\r
- Py_INCREF(ob);\r
- res->ob_item[i] = ob;\r
- }\r
-\r
- Py_DECREF(arg);\r
- return (PyObject*) res;\r
-}\r
-\r
-static PyObject *\r
-make_tuple(PyStructSequence *obj)\r
-{\r
- return structseq_slice(obj, 0, VISIBLE_SIZE(obj));\r
-}\r
-\r
-static PyObject *\r
-structseq_repr(PyStructSequence *obj)\r
-{\r
- /* buffer and type size were chosen well considered. */\r
-#define REPR_BUFFER_SIZE 512\r
-#define TYPE_MAXSIZE 100\r
-\r
- PyObject *tup;\r
- PyTypeObject *typ = Py_TYPE(obj);\r
- int i, removelast = 0;\r
- Py_ssize_t len;\r
- char buf[REPR_BUFFER_SIZE];\r
- char *endofbuf, *pbuf = buf;\r
-\r
- /* pointer to end of writeable buffer; safes space for "...)\0" */\r
- endofbuf= &buf[REPR_BUFFER_SIZE-5];\r
-\r
- if ((tup = make_tuple(obj)) == NULL) {\r
- return NULL;\r
- }\r
-\r
- /* "typename(", limited to TYPE_MAXSIZE */\r
- len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :\r
- strlen(typ->tp_name);\r
- strncpy(pbuf, typ->tp_name, len);\r
- pbuf += len;\r
- *pbuf++ = '(';\r
-\r
- for (i=0; i < VISIBLE_SIZE(obj); i++) {\r
- PyObject *val, *repr;\r
- char *cname, *crepr;\r
-\r
- cname = typ->tp_members[i].name;\r
-\r
- val = PyTuple_GetItem(tup, i);\r
- if (cname == NULL || val == NULL) {\r
- return NULL;\r
- }\r
- repr = PyObject_Repr(val);\r
- if (repr == NULL) {\r
- Py_DECREF(tup);\r
- return NULL;\r
- }\r
- crepr = PyString_AsString(repr);\r
- if (crepr == NULL) {\r
- Py_DECREF(tup);\r
- Py_DECREF(repr);\r
- return NULL;\r
- }\r
-\r
- /* + 3: keep space for "=" and ", " */\r
- len = strlen(cname) + strlen(crepr) + 3;\r
- if ((pbuf+len) <= endofbuf) {\r
- strcpy(pbuf, cname);\r
- pbuf += strlen(cname);\r
- *pbuf++ = '=';\r
- strcpy(pbuf, crepr);\r
- pbuf += strlen(crepr);\r
- *pbuf++ = ',';\r
- *pbuf++ = ' ';\r
- removelast = 1;\r
- Py_DECREF(repr);\r
- }\r
- else {\r
- strcpy(pbuf, "...");\r
- pbuf += 3;\r
- removelast = 0;\r
- Py_DECREF(repr);\r
- break;\r
- }\r
- }\r
- Py_DECREF(tup);\r
- if (removelast) {\r
- /* overwrite last ", " */\r
- pbuf-=2;\r
- }\r
- *pbuf++ = ')';\r
- *pbuf = '\0';\r
-\r
- return PyString_FromString(buf);\r
-}\r
-\r
-static PyObject *\r
-structseq_concat(PyStructSequence *obj, PyObject *b)\r
-{\r
- PyObject *tup, *result;\r
- tup = make_tuple(obj);\r
- result = PySequence_Concat(tup, b);\r
- Py_DECREF(tup);\r
- return result;\r
-}\r
-\r
-static PyObject *\r
-structseq_repeat(PyStructSequence *obj, Py_ssize_t n)\r
-{\r
- PyObject *tup, *result;\r
- tup = make_tuple(obj);\r
- result = PySequence_Repeat(tup, n);\r
- Py_DECREF(tup);\r
- return result;\r
-}\r
-\r
-static int\r
-structseq_contains(PyStructSequence *obj, PyObject *o)\r
-{\r
- PyObject *tup;\r
- int result;\r
- tup = make_tuple(obj);\r
- if (!tup)\r
- return -1;\r
- result = PySequence_Contains(tup, o);\r
- Py_DECREF(tup);\r
- return result;\r
-}\r
-\r
-static long\r
-structseq_hash(PyObject *obj)\r
-{\r
- PyObject *tup;\r
- long result;\r
- tup = make_tuple((PyStructSequence*) obj);\r
- if (!tup)\r
- return -1;\r
- result = PyObject_Hash(tup);\r
- Py_DECREF(tup);\r
- return result;\r
-}\r
-\r
-static PyObject *\r
-structseq_richcompare(PyObject *obj, PyObject *o2, int op)\r
-{\r
- PyObject *tup, *result;\r
- tup = make_tuple((PyStructSequence*) obj);\r
- result = PyObject_RichCompare(tup, o2, op);\r
- Py_DECREF(tup);\r
- return result;\r
-}\r
-\r
-static PyObject *\r
-structseq_reduce(PyStructSequence* self)\r
-{\r
- PyObject* tup;\r
- PyObject* dict;\r
- PyObject* result;\r
- Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;\r
- int i;\r
-\r
- n_fields = REAL_SIZE(self);\r
- n_visible_fields = VISIBLE_SIZE(self);\r
- n_unnamed_fields = UNNAMED_FIELDS(self);\r
- tup = PyTuple_New(n_visible_fields);\r
- if (!tup) {\r
- return NULL;\r
- }\r
-\r
- dict = PyDict_New();\r
- if (!dict) {\r
- Py_DECREF(tup);\r
- return NULL;\r
- }\r
-\r
- for (i = 0; i < n_visible_fields; i++) {\r
- Py_INCREF(self->ob_item[i]);\r
- PyTuple_SET_ITEM(tup, i, self->ob_item[i]);\r
- }\r
-\r
- for (; i < n_fields; i++) {\r
- char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;\r
- PyDict_SetItemString(dict, n,\r
- self->ob_item[i]);\r
- }\r
-\r
- result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);\r
-\r
- Py_DECREF(tup);\r
- Py_DECREF(dict);\r
-\r
- return result;\r
-}\r
-\r
-static PySequenceMethods structseq_as_sequence = {\r
- (lenfunc)structseq_length,\r
- (binaryfunc)structseq_concat, /* sq_concat */\r
- (ssizeargfunc)structseq_repeat, /* sq_repeat */\r
- (ssizeargfunc)structseq_item, /* sq_item */\r
- (ssizessizeargfunc)structseq_slice, /* sq_slice */\r
- 0, /* sq_ass_item */\r
- 0, /* sq_ass_slice */\r
- (objobjproc)structseq_contains, /* sq_contains */\r
-};\r
-\r
-static PyMappingMethods structseq_as_mapping = {\r
- (lenfunc)structseq_length,\r
- (binaryfunc)structseq_subscript,\r
-};\r
-\r
-static PyMethodDef structseq_methods[] = {\r
- {"__reduce__", (PyCFunction)structseq_reduce,\r
- METH_NOARGS, NULL},\r
- {NULL, NULL}\r
-};\r
-\r
-static PyTypeObject _struct_sequence_template = {\r
- PyVarObject_HEAD_INIT(&PyType_Type, 0)\r
- NULL, /* tp_name */\r
- 0, /* tp_basicsize */\r
- 0, /* tp_itemsize */\r
- (destructor)structseq_dealloc, /* tp_dealloc */\r
- 0, /* tp_print */\r
- 0, /* tp_getattr */\r
- 0, /* tp_setattr */\r
- 0, /* tp_compare */\r
- (reprfunc)structseq_repr, /* tp_repr */\r
- 0, /* tp_as_number */\r
- &structseq_as_sequence, /* tp_as_sequence */\r
- &structseq_as_mapping, /* tp_as_mapping */\r
- structseq_hash, /* tp_hash */\r
- 0, /* tp_call */\r
- 0, /* tp_str */\r
- 0, /* tp_getattro */\r
- 0, /* tp_setattro */\r
- 0, /* tp_as_buffer */\r
- Py_TPFLAGS_DEFAULT, /* tp_flags */\r
- NULL, /* tp_doc */\r
- 0, /* tp_traverse */\r
- 0, /* tp_clear */\r
- structseq_richcompare, /* tp_richcompare */\r
- 0, /* tp_weaklistoffset */\r
- 0, /* tp_iter */\r
- 0, /* tp_iternext */\r
- structseq_methods, /* tp_methods */\r
- NULL, /* tp_members */\r
- 0, /* tp_getset */\r
- 0, /* tp_base */\r
- 0, /* tp_dict */\r
- 0, /* tp_descr_get */\r
- 0, /* tp_descr_set */\r
- 0, /* tp_dictoffset */\r
- 0, /* tp_init */\r
- 0, /* tp_alloc */\r
- structseq_new, /* tp_new */\r
-};\r
-\r
-void\r
-PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)\r
-{\r
- PyObject *dict;\r
- PyMemberDef* members;\r
- int n_members, n_unnamed_members, i, k;\r
-\r
-#ifdef Py_TRACE_REFS\r
- /* if the type object was chained, unchain it first\r
- before overwriting its storage */\r
- if (type->_ob_next) {\r
- _Py_ForgetReference((PyObject*)type);\r
- }\r
-#endif\r
-\r
- n_unnamed_members = 0;\r
- for (i = 0; desc->fields[i].name != NULL; ++i)\r
- if (desc->fields[i].name == PyStructSequence_UnnamedField)\r
- n_unnamed_members++;\r
- n_members = i;\r
-\r
- memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));\r
- type->tp_name = desc->name;\r
- type->tp_doc = desc->doc;\r
- type->tp_basicsize = sizeof(PyStructSequence)+\r
- sizeof(PyObject*)*(n_members-1);\r
- type->tp_itemsize = 0;\r
-\r
- members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);\r
- if (members == NULL)\r
- return;\r
-\r
- for (i = k = 0; i < n_members; ++i) {\r
- if (desc->fields[i].name == PyStructSequence_UnnamedField)\r
- continue;\r
- members[k].name = desc->fields[i].name;\r
- members[k].type = T_OBJECT;\r
- members[k].offset = offsetof(PyStructSequence, ob_item)\r
- + i * sizeof(PyObject*);\r
- members[k].flags = READONLY;\r
- members[k].doc = desc->fields[i].doc;\r
- k++;\r
- }\r
- members[k].name = NULL;\r
-\r
- type->tp_members = members;\r
-\r
- if (PyType_Ready(type) < 0)\r
- return;\r
- Py_INCREF(type);\r
-\r
- dict = type->tp_dict;\r
-#define SET_DICT_FROM_INT(key, value) \\r
- do { \\r
- PyObject *v = PyInt_FromLong((long) value); \\r
- if (v != NULL) { \\r
- PyDict_SetItemString(dict, key, v); \\r
- Py_DECREF(v); \\r
- } \\r
- } while (0)\r
-\r
- SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);\r
- SET_DICT_FROM_INT(real_length_key, n_members);\r
- SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);\r
-}\r