*** Include/structseq.h 3 Feb 2004 20:06:53 -0000 1.1.1.1 --- Include/structseq.h 26 Jun 2004 23:48:51 -0000 *************** *** 25,30 **** --- 25,31 ---- PyStructSequence_Desc *desc); PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); + PyAPI_FUNC(PyTypeObject *) PyStructSequence_NewType(PyStringObject * name, int n_in_sequence, PyObject * fields, PyStringObject * docstring); typedef struct { PyObject_VAR_HEAD *** Objects/structseq.c 3 Feb 2004 20:06:58 -0000 1.1.1.1 --- Objects/structseq.c 26 Jun 2004 23:49:01 -0000 *************** *** 393,395 **** --- 393,541 ---- PyDict_SetItemString(dict, unnamed_fields_key, PyInt_FromLong((long) n_unnamed_members)); } + + PyTypeObject * + PyStructSequence_NewType(PyStringObject * name, int n_in_sequence, PyObject * fields, PyStringObject * docstring) + { + PyObject *dict; + PyObject *slots; + PyObject *slotname; + PyMemberDef *mp; + PyTypeObject * type; + PyHeapTypeObject *et; + int i, k, slot_offset; + size_t size; + int num_fields; + PyObject * field; + + /* Verify that is in the correct format. */ + if(!PySequence_Check(fields)) { + PyErr_SetString(PyExc_TypeError, "Fields must be a sequence."); + return NULL; + } + num_fields = PySequence_Size(fields); + if(num_fields==-1) { + PyErr_SetString(PyExc_TypeError, "Sequence has length -1."); + return NULL; + } + if(num_fields==0) { + PyErr_SetString(PyExc_ValueError, "Sequence must have at least 1 element."); + return NULL; + } + if(n_in_sequence == -1) { + n_in_sequence = num_fields; + } else { + if(n_in_sequence > num_fields) { + PyErr_SetString(PyExc_ValueError, "Not enough fields defined for n_in_sequence."); + return NULL; + } + } + + /* Create a type object. */ + /* +1 for sentinel */ + size = _PyObject_VAR_SIZE(&PyType_Type, num_fields+1); + type = (PyTypeObject *) _PyObject_GC_NewVar(&PyType_Type, num_fields); + if(type==NULL) { + return NULL; + } + memset(type, 0, size); + (void) PyObject_INIT_VAR((PyVarObject *)type, &PyType_Type, num_fields); + type->ob_type = &PyType_Type; + + /* Initialize Extended Type attributes. */ + et = (PyHeapTypeObject *)type; + et->name = (PyObject *)name; + Py_INCREF(name); + + /* Initialize Type attributes. */ + /* XXX: Why does PyStructSequence_InitType set itemsize to zero? */ + type->tp_name = PyString_AS_STRING(et->name); + type->tp_itemsize = sizeof(PyObject *); + type->tp_dealloc = (destructor)structseq_dealloc; + type->tp_repr = (reprfunc)structseq_repr; + type->tp_as_sequence = &structseq_as_sequence; + type->tp_hash = (hashfunc)structseq_hash; + type->tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HEAPTYPE | Py_TPFLAGS_BASETYPE; + if(docstring) { + type->tp_doc = PyObject_MALLOC(PyString_GET_SIZE(docstring)+1); + if(type->tp_doc == NULL) { + Py_DECREF(type); + return NULL; + } + strcpy(type->tp_doc, PyString_AS_STRING(docstring)); + } + type->tp_richcompare = structseq_richcompare; + type->tp_methods = structseq_methods; + type->tp_new = structseq_new; + + /* Setup slots. */ + slots = PyTuple_New(num_fields); + if(slots==NULL) { + Py_DECREF(type); + return NULL; + } + et->slots = slots; + mp = PyHeapType_GET_MEMBERS(et); + // XXX: What is correct way to compute slot_offset? + slot_offset = offsetof(PyStructSequence, ob_item); + for (i = k = 0; i < num_fields; i++) { + field = PySequence_GetItem(fields, i); /* new reference */ + if(field==NULL) { + PyErr_SetString(PyExc_TypeError, "Sequence contains NULL element."); + Py_DECREF(type); + return NULL; + } + if(!PyTuple_Check(field) || PyTuple_GET_SIZE(field) != 2) { + Py_DECREF(field); + Py_DECREF(type); + PyErr_SetString(PyExc_TypeError, "Fields must be a tuple of two elements."); + return NULL; + } + if(!PyString_Check(PyTuple_GET_ITEM(field, 0)) || + !PyString_Check(PyTuple_GET_ITEM(field, 1))) { + Py_DECREF(field); + Py_DECREF(type); + PyErr_SetString(PyExc_TypeError, "Both elements in the field tuple must be a string."); + return NULL; + } + + slotname = PyTuple_GET_ITEM(field, 0); + PyTuple_SET_ITEM(slots, k, slotname); + Py_INCREF(slotname); + + mp->name = PyString_AS_STRING(slotname); + /* XXX: Can't set mp->doc because we can't just borrow a C + reference from the tuple because Not sure if there's a + convenient place to stick a refernce to these docstrings + so that they live with the Type object. Oh well. + */ + Py_DECREF(field); + mp->doc = NULL; + mp->type = T_OBJECT_EX; + mp->offset = slot_offset; + mp->flags = READONLY; + slot_offset += sizeof(PyObject *); + mp++; + k++; + } + mp->name = NULL; /* sentinel */ + type->tp_basicsize = slot_offset; + type->tp_members = PyHeapType_GET_MEMBERS(et); + + if(PyType_Ready(type)) { + Py_DECREF(type); + return NULL; + } + + dict = type->tp_dict; + //XXX: error handling + PyDict_SetItemString(dict, visible_length_key, + PyInt_FromLong((long) n_in_sequence)); + PyDict_SetItemString(dict, real_length_key, + PyInt_FromLong((long) num_fields)); + PyDict_SetItemString(dict, unnamed_fields_key, + PyInt_FromLong((long) 0)); + + _PyObject_GC_TRACK(type); + return type; + } *** Python/bltinmodule.c 28 May 2004 18:36:03 -0000 1.4 --- Python/bltinmodule.c 26 Jun 2004 23:49:15 -0000 *************** *** 2,7 **** --- 2,8 ---- /* Built-in functions */ #include "Python.h" + #include "structseq.h" /* XXX: Add to Python.h? */ #include "node.h" #include "compile.h" *************** *** 2015,2020 **** --- 2016,2052 ---- from each of the argument sequences. The returned list is truncated\n\ in length to the length of the shortest argument sequence."); + static PyObject * + builtin_struct_seq(PyObject *self, PyObject *args, PyObject *kwargs) + { + PyObject * name; + PyObject * fields; + PyObject * docstring = NULL; + int n_in_sequence=-1; + + static char *kwlist[] = {"name", "fields", "n_in_sequence", "docstring", NULL}; + if(!PyArg_ParseTupleAndKeywords(args, kwargs, + "O!O|iO!", kwlist, + &PyString_Type, &name, + &fields, + &n_in_sequence, + &PyString_Type, &docstring)) { + return NULL; + } + return (PyObject *)PyStructSequence_NewType((PyStringObject *)name, n_in_sequence, fields, (PyStringObject *)docstring); + } + + PyDoc_STRVAR(struct_seq_doc, + "struct_seq(name, fields, n_in_sequence=-1, docstring='') -> struct_seq_type_object\n\ + \n\ + Return a new struct_seq type object.\n\ + \n\ + : Name of the new type object.\n\ + : Sequence of (name, docstring) tuples of the members of the\n\ + struct_seq object.\n\ + : Number of fields that are required.\n\ + -1 evaluates to len(fields).\n\ + : Optional docstring to describe this struct_seq type."); static PyMethodDef builtin_methods[] = { {"__import__", builtin___import__, METH_VARARGS, import_doc}, *************** *** 2057,2062 **** --- 2089,2095 ---- {"repr", builtin_repr, METH_O, repr_doc}, {"round", builtin_round, METH_VARARGS, round_doc}, {"setattr", builtin_setattr, METH_VARARGS, setattr_doc}, + {"struct_seq", (PyCFunction)builtin_struct_seq, METH_VARARGS|METH_KEYWORDS, struct_seq_doc}, {"sum", builtin_sum, METH_VARARGS, sum_doc}, #ifdef Py_USING_UNICODE {"unichr", builtin_unichr, METH_VARARGS, unichr_doc},