1 /* Implementation helper: a struct that looks like a tuple. See timemodule
2 and posixmodule for example uses. */
5 #include "structmember.h"
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";
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";
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))
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))
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))
30 PyStructSequence_New(PyTypeObject
*type
)
32 PyStructSequence
*obj
;
34 obj
= PyObject_New(PyStructSequence
, type
);
37 Py_SIZE(obj
) = VISIBLE_SIZE_TP(type
);
39 return (PyObject
*) obj
;
43 structseq_dealloc(PyStructSequence
*obj
)
47 size
= REAL_SIZE(obj
);
48 for (i
= 0; i
< size
; ++i
) {
49 Py_XDECREF(obj
->ob_item
[i
]);
55 structseq_length(PyStructSequence
*obj
)
57 return VISIBLE_SIZE(obj
);
61 structseq_item(PyStructSequence
*obj
, Py_ssize_t i
)
63 if (i
< 0 || i
>= VISIBLE_SIZE(obj
)) {
64 PyErr_SetString(PyExc_IndexError
, "tuple index out of range");
67 Py_INCREF(obj
->ob_item
[i
]);
68 return obj
->ob_item
[i
];
72 structseq_slice(PyStructSequence
*obj
, Py_ssize_t low
, Py_ssize_t high
)
79 if (high
> VISIBLE_SIZE(obj
))
80 high
= VISIBLE_SIZE(obj
);
83 np
= (PyTupleObject
*)PyTuple_New(high
-low
);
86 for(i
= low
; i
< high
; ++i
) {
87 PyObject
*v
= obj
->ob_item
[i
];
89 PyTuple_SET_ITEM(np
, i
-low
, v
);
91 return (PyObject
*) np
;
95 structseq_subscript(PyStructSequence
*self
, PyObject
*item
)
97 if (PyIndex_Check(item
)) {
98 Py_ssize_t i
= PyNumber_AsSsize_t(item
, PyExc_IndexError
);
99 if (i
== -1 && PyErr_Occurred())
103 i
+= VISIBLE_SIZE(self
);
105 if (i
< 0 || i
>= VISIBLE_SIZE(self
)) {
106 PyErr_SetString(PyExc_IndexError
,
107 "tuple index out of range");
110 Py_INCREF(self
->ob_item
[i
]);
111 return self
->ob_item
[i
];
113 else if (PySlice_Check(item
)) {
114 Py_ssize_t start
, stop
, step
, slicelen
, cur
, i
;
117 if (PySlice_GetIndicesEx((PySliceObject
*)item
,
118 VISIBLE_SIZE(self
), &start
, &stop
,
119 &step
, &slicelen
) < 0) {
123 return PyTuple_New(0);
124 result
= PyTuple_New(slicelen
);
127 for (cur
= start
, i
= 0; i
< slicelen
;
129 PyObject
*v
= self
->ob_item
[cur
];
131 PyTuple_SET_ITEM(result
, i
, v
);
136 PyErr_SetString(PyExc_TypeError
,
137 "structseq index must be integer");
143 structseq_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
145 PyObject
*arg
= NULL
;
146 PyObject
*dict
= NULL
;
148 PyStructSequence
*res
= NULL
;
149 Py_ssize_t len
, min_len
, max_len
, i
, n_unnamed_fields
;
150 static char *kwlist
[] = {"sequence", "dict", 0};
152 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|O:structseq",
153 kwlist
, &arg
, &dict
))
156 arg
= PySequence_Fast(arg
, "constructor requires a sequence");
162 if (dict
&& !PyDict_Check(dict
)) {
163 PyErr_Format(PyExc_TypeError
,
164 "%.500s() takes a dict as second arg, if any",
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
);
175 if (min_len
!= max_len
) {
177 PyErr_Format(PyExc_TypeError
,
178 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
179 type
->tp_name
, min_len
, len
);
185 PyErr_Format(PyExc_TypeError
,
186 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
187 type
->tp_name
, max_len
, len
);
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
);
202 res
= (PyStructSequence
*) PyStructSequence_New(type
);
206 for (i
= 0; i
< len
; ++i
) {
207 PyObject
*v
= PySequence_Fast_GET_ITEM(arg
, i
);
211 for (; i
< max_len
; ++i
) {
212 if (dict
&& (ob
= PyDict_GetItemString(
213 dict
, type
->tp_members
[i
-n_unnamed_fields
].name
))) {
219 res
->ob_item
[i
] = ob
;
223 return (PyObject
*) res
;
227 make_tuple(PyStructSequence
*obj
)
229 return structseq_slice(obj
, 0, VISIBLE_SIZE(obj
));
233 structseq_repr(PyStructSequence
*obj
)
235 /* buffer and type size were chosen well considered. */
236 #define REPR_BUFFER_SIZE 512
237 #define TYPE_MAXSIZE 100
240 PyTypeObject
*typ
= Py_TYPE(obj
);
241 int i
, removelast
= 0;
243 char buf
[REPR_BUFFER_SIZE
];
244 char *endofbuf
, *pbuf
= buf
;
246 /* pointer to end of writeable buffer; safes space for "...)\0" */
247 endofbuf
= &buf
[REPR_BUFFER_SIZE
-5];
249 if ((tup
= make_tuple(obj
)) == NULL
) {
253 /* "typename(", limited to TYPE_MAXSIZE */
254 len
= strlen(typ
->tp_name
) > TYPE_MAXSIZE
? TYPE_MAXSIZE
:
255 strlen(typ
->tp_name
);
256 strncpy(pbuf
, typ
->tp_name
, len
);
260 for (i
=0; i
< VISIBLE_SIZE(obj
); i
++) {
261 PyObject
*val
, *repr
;
264 cname
= typ
->tp_members
[i
].name
;
266 val
= PyTuple_GetItem(tup
, i
);
267 if (cname
== NULL
|| val
== NULL
) {
270 repr
= PyObject_Repr(val
);
275 crepr
= PyString_AsString(repr
);
282 /* + 3: keep space for "=" and ", " */
283 len
= strlen(cname
) + strlen(crepr
) + 3;
284 if ((pbuf
+len
) <= endofbuf
) {
286 pbuf
+= strlen(cname
);
289 pbuf
+= strlen(crepr
);
305 /* overwrite last ", " */
311 return PyString_FromString(buf
);
315 structseq_concat(PyStructSequence
*obj
, PyObject
*b
)
317 PyObject
*tup
, *result
;
318 tup
= make_tuple(obj
);
319 result
= PySequence_Concat(tup
, b
);
325 structseq_repeat(PyStructSequence
*obj
, Py_ssize_t n
)
327 PyObject
*tup
, *result
;
328 tup
= make_tuple(obj
);
329 result
= PySequence_Repeat(tup
, n
);
335 structseq_contains(PyStructSequence
*obj
, PyObject
*o
)
339 tup
= make_tuple(obj
);
342 result
= PySequence_Contains(tup
, o
);
348 structseq_hash(PyObject
*obj
)
352 tup
= make_tuple((PyStructSequence
*) obj
);
355 result
= PyObject_Hash(tup
);
361 structseq_richcompare(PyObject
*obj
, PyObject
*o2
, int op
)
363 PyObject
*tup
, *result
;
364 tup
= make_tuple((PyStructSequence
*) obj
);
365 result
= PyObject_RichCompare(tup
, o2
, op
);
371 structseq_reduce(PyStructSequence
* self
)
376 Py_ssize_t n_fields
, n_visible_fields
, n_unnamed_fields
;
379 n_fields
= REAL_SIZE(self
);
380 n_visible_fields
= VISIBLE_SIZE(self
);
381 n_unnamed_fields
= UNNAMED_FIELDS(self
);
382 tup
= PyTuple_New(n_visible_fields
);
393 for (i
= 0; i
< n_visible_fields
; i
++) {
394 Py_INCREF(self
->ob_item
[i
]);
395 PyTuple_SET_ITEM(tup
, i
, self
->ob_item
[i
]);
398 for (; i
< n_fields
; i
++) {
399 char *n
= Py_TYPE(self
)->tp_members
[i
-n_unnamed_fields
].name
;
400 PyDict_SetItemString(dict
, n
,
404 result
= Py_BuildValue("(O(OO))", Py_TYPE(self
), tup
, dict
);
412 static PySequenceMethods structseq_as_sequence
= {
413 (lenfunc
)structseq_length
,
414 (binaryfunc
)structseq_concat
, /* sq_concat */
415 (ssizeargfunc
)structseq_repeat
, /* sq_repeat */
416 (ssizeargfunc
)structseq_item
, /* sq_item */
417 (ssizessizeargfunc
)structseq_slice
, /* sq_slice */
419 0, /* sq_ass_slice */
420 (objobjproc
)structseq_contains
, /* sq_contains */
423 static PyMappingMethods structseq_as_mapping
= {
424 (lenfunc
)structseq_length
,
425 (binaryfunc
)structseq_subscript
,
428 static PyMethodDef structseq_methods
[] = {
429 {"__reduce__", (PyCFunction
)structseq_reduce
,
434 static PyTypeObject _struct_sequence_template
= {
435 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
437 0, /* tp_basicsize */
439 (destructor
)structseq_dealloc
, /* tp_dealloc */
444 (reprfunc
)structseq_repr
, /* tp_repr */
445 0, /* tp_as_number */
446 &structseq_as_sequence
, /* tp_as_sequence */
447 &structseq_as_mapping
, /* tp_as_mapping */
448 structseq_hash
, /* tp_hash */
453 0, /* tp_as_buffer */
454 Py_TPFLAGS_DEFAULT
, /* tp_flags */
458 structseq_richcompare
, /* tp_richcompare */
459 0, /* tp_weaklistoffset */
462 structseq_methods
, /* tp_methods */
463 NULL
, /* tp_members */
467 0, /* tp_descr_get */
468 0, /* tp_descr_set */
469 0, /* tp_dictoffset */
472 structseq_new
, /* tp_new */
476 PyStructSequence_InitType(PyTypeObject
*type
, PyStructSequence_Desc
*desc
)
479 PyMemberDef
* members
;
480 int n_members
, n_unnamed_members
, i
, k
;
483 /* if the type object was chained, unchain it first
484 before overwriting its storage */
485 if (type
->_ob_next
) {
486 _Py_ForgetReference((PyObject
*)type
);
490 n_unnamed_members
= 0;
491 for (i
= 0; desc
->fields
[i
].name
!= NULL
; ++i
)
492 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
496 memcpy(type
, &_struct_sequence_template
, sizeof(PyTypeObject
));
497 type
->tp_name
= desc
->name
;
498 type
->tp_doc
= desc
->doc
;
499 type
->tp_basicsize
= sizeof(PyStructSequence
)+
500 sizeof(PyObject
*)*(n_members
-1);
501 type
->tp_itemsize
= 0;
503 members
= PyMem_NEW(PyMemberDef
, n_members
-n_unnamed_members
+1);
507 for (i
= k
= 0; i
< n_members
; ++i
) {
508 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
510 members
[k
].name
= desc
->fields
[i
].name
;
511 members
[k
].type
= T_OBJECT
;
512 members
[k
].offset
= offsetof(PyStructSequence
, ob_item
)
513 + i
* sizeof(PyObject
*);
514 members
[k
].flags
= READONLY
;
515 members
[k
].doc
= desc
->fields
[i
].doc
;
518 members
[k
].name
= NULL
;
520 type
->tp_members
= members
;
522 if (PyType_Ready(type
) < 0)
526 dict
= type
->tp_dict
;
527 #define SET_DICT_FROM_INT(key, value) \
529 PyObject *v = PyInt_FromLong((long) value); \
531 PyDict_SetItemString(dict, key, v); \
536 SET_DICT_FROM_INT(visible_length_key
, desc
->n_in_sequence
);
537 SET_DICT_FROM_INT(real_length_key
, n_members
);
538 SET_DICT_FROM_INT(unnamed_fields_key
, n_unnamed_members
);