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
);
35 Py_SIZE(obj
) = VISIBLE_SIZE_TP(type
);
37 return (PyObject
*) obj
;
41 structseq_dealloc(PyStructSequence
*obj
)
45 size
= REAL_SIZE(obj
);
46 for (i
= 0; i
< size
; ++i
) {
47 Py_XDECREF(obj
->ob_item
[i
]);
53 structseq_length(PyStructSequence
*obj
)
55 return VISIBLE_SIZE(obj
);
59 structseq_item(PyStructSequence
*obj
, Py_ssize_t i
)
61 if (i
< 0 || i
>= VISIBLE_SIZE(obj
)) {
62 PyErr_SetString(PyExc_IndexError
, "tuple index out of range");
65 Py_INCREF(obj
->ob_item
[i
]);
66 return obj
->ob_item
[i
];
70 structseq_slice(PyStructSequence
*obj
, Py_ssize_t low
, Py_ssize_t high
)
77 if (high
> VISIBLE_SIZE(obj
))
78 high
= VISIBLE_SIZE(obj
);
81 np
= (PyTupleObject
*)PyTuple_New(high
-low
);
84 for(i
= low
; i
< high
; ++i
) {
85 PyObject
*v
= obj
->ob_item
[i
];
87 PyTuple_SET_ITEM(np
, i
-low
, v
);
89 return (PyObject
*) np
;
93 structseq_subscript(PyStructSequence
*self
, PyObject
*item
)
95 if (PyIndex_Check(item
)) {
96 Py_ssize_t i
= PyNumber_AsSsize_t(item
, PyExc_IndexError
);
97 if (i
== -1 && PyErr_Occurred())
101 i
+= VISIBLE_SIZE(self
);
103 if (i
< 0 || i
>= VISIBLE_SIZE(self
)) {
104 PyErr_SetString(PyExc_IndexError
,
105 "tuple index out of range");
108 Py_INCREF(self
->ob_item
[i
]);
109 return self
->ob_item
[i
];
111 else if (PySlice_Check(item
)) {
112 Py_ssize_t start
, stop
, step
, slicelen
, cur
, i
;
115 if (PySlice_GetIndicesEx((PySliceObject
*)item
,
116 VISIBLE_SIZE(self
), &start
, &stop
,
117 &step
, &slicelen
) < 0) {
121 return PyTuple_New(0);
122 result
= PyTuple_New(slicelen
);
125 for (cur
= start
, i
= 0; i
< slicelen
;
127 PyObject
*v
= self
->ob_item
[cur
];
129 PyTuple_SET_ITEM(result
, i
, v
);
134 PyErr_SetString(PyExc_TypeError
,
135 "structseq index must be integer");
141 structseq_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
143 PyObject
*arg
= NULL
;
144 PyObject
*dict
= NULL
;
146 PyStructSequence
*res
= NULL
;
147 Py_ssize_t len
, min_len
, max_len
, i
, n_unnamed_fields
;
148 static char *kwlist
[] = {"sequence", "dict", 0};
150 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|O:structseq",
151 kwlist
, &arg
, &dict
))
154 arg
= PySequence_Fast(arg
, "constructor requires a sequence");
160 if (dict
&& !PyDict_Check(dict
)) {
161 PyErr_Format(PyExc_TypeError
,
162 "%.500s() takes a dict as second arg, if any",
168 len
= PySequence_Fast_GET_SIZE(arg
);
169 min_len
= VISIBLE_SIZE_TP(type
);
170 max_len
= REAL_SIZE_TP(type
);
171 n_unnamed_fields
= UNNAMED_FIELDS_TP(type
);
173 if (min_len
!= max_len
) {
175 PyErr_Format(PyExc_TypeError
,
176 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
177 type
->tp_name
, min_len
, len
);
183 PyErr_Format(PyExc_TypeError
,
184 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
185 type
->tp_name
, max_len
, len
);
191 if (len
!= min_len
) {
192 PyErr_Format(PyExc_TypeError
,
193 "%.500s() takes a %zd-sequence (%zd-sequence given)",
194 type
->tp_name
, min_len
, len
);
200 res
= (PyStructSequence
*) PyStructSequence_New(type
);
204 for (i
= 0; i
< len
; ++i
) {
205 PyObject
*v
= PySequence_Fast_GET_ITEM(arg
, i
);
209 for (; i
< max_len
; ++i
) {
210 if (dict
&& (ob
= PyDict_GetItemString(
211 dict
, type
->tp_members
[i
-n_unnamed_fields
].name
))) {
217 res
->ob_item
[i
] = ob
;
221 return (PyObject
*) res
;
225 make_tuple(PyStructSequence
*obj
)
227 return structseq_slice(obj
, 0, VISIBLE_SIZE(obj
));
231 structseq_repr(PyStructSequence
*obj
)
233 /* buffer and type size were chosen well considered. */
234 #define REPR_BUFFER_SIZE 512
235 #define TYPE_MAXSIZE 100
238 PyTypeObject
*typ
= Py_TYPE(obj
);
239 int i
, removelast
= 0;
241 char buf
[REPR_BUFFER_SIZE
];
242 char *endofbuf
, *pbuf
= buf
;
244 /* pointer to end of writeable buffer; safes space for "...)\0" */
245 endofbuf
= &buf
[REPR_BUFFER_SIZE
-5];
247 if ((tup
= make_tuple(obj
)) == NULL
) {
251 /* "typename(", limited to TYPE_MAXSIZE */
252 len
= strlen(typ
->tp_name
) > TYPE_MAXSIZE
? TYPE_MAXSIZE
:
253 strlen(typ
->tp_name
);
254 strncpy(pbuf
, typ
->tp_name
, len
);
258 for (i
=0; i
< VISIBLE_SIZE(obj
); i
++) {
259 PyObject
*val
, *repr
;
262 cname
= typ
->tp_members
[i
].name
;
264 val
= PyTuple_GetItem(tup
, i
);
265 if (cname
== NULL
|| val
== NULL
) {
268 repr
= PyObject_Repr(val
);
273 crepr
= PyString_AsString(repr
);
280 /* + 3: keep space for "=" and ", " */
281 len
= strlen(cname
) + strlen(crepr
) + 3;
282 if ((pbuf
+len
) <= endofbuf
) {
284 pbuf
+= strlen(cname
);
287 pbuf
+= strlen(crepr
);
303 /* overwrite last ", " */
309 return PyString_FromString(buf
);
313 structseq_concat(PyStructSequence
*obj
, PyObject
*b
)
315 PyObject
*tup
, *result
;
316 tup
= make_tuple(obj
);
317 result
= PySequence_Concat(tup
, b
);
323 structseq_repeat(PyStructSequence
*obj
, Py_ssize_t n
)
325 PyObject
*tup
, *result
;
326 tup
= make_tuple(obj
);
327 result
= PySequence_Repeat(tup
, n
);
333 structseq_contains(PyStructSequence
*obj
, PyObject
*o
)
337 tup
= make_tuple(obj
);
340 result
= PySequence_Contains(tup
, o
);
346 structseq_hash(PyObject
*obj
)
350 tup
= make_tuple((PyStructSequence
*) obj
);
353 result
= PyObject_Hash(tup
);
359 structseq_richcompare(PyObject
*obj
, PyObject
*o2
, int op
)
361 PyObject
*tup
, *result
;
362 tup
= make_tuple((PyStructSequence
*) obj
);
363 result
= PyObject_RichCompare(tup
, o2
, op
);
369 structseq_reduce(PyStructSequence
* self
)
374 Py_ssize_t n_fields
, n_visible_fields
, n_unnamed_fields
;
377 n_fields
= REAL_SIZE(self
);
378 n_visible_fields
= VISIBLE_SIZE(self
);
379 n_unnamed_fields
= UNNAMED_FIELDS(self
);
380 tup
= PyTuple_New(n_visible_fields
);
391 for (i
= 0; i
< n_visible_fields
; i
++) {
392 Py_INCREF(self
->ob_item
[i
]);
393 PyTuple_SET_ITEM(tup
, i
, self
->ob_item
[i
]);
396 for (; i
< n_fields
; i
++) {
397 char *n
= Py_TYPE(self
)->tp_members
[i
-n_unnamed_fields
].name
;
398 PyDict_SetItemString(dict
, n
,
402 result
= Py_BuildValue("(O(OO))", Py_TYPE(self
), tup
, dict
);
410 static PySequenceMethods structseq_as_sequence
= {
411 (lenfunc
)structseq_length
,
412 (binaryfunc
)structseq_concat
, /* sq_concat */
413 (ssizeargfunc
)structseq_repeat
, /* sq_repeat */
414 (ssizeargfunc
)structseq_item
, /* sq_item */
415 (ssizessizeargfunc
)structseq_slice
, /* sq_slice */
417 0, /* sq_ass_slice */
418 (objobjproc
)structseq_contains
, /* sq_contains */
421 static PyMappingMethods structseq_as_mapping
= {
422 (lenfunc
)structseq_length
,
423 (binaryfunc
)structseq_subscript
,
426 static PyMethodDef structseq_methods
[] = {
427 {"__reduce__", (PyCFunction
)structseq_reduce
,
432 static PyTypeObject _struct_sequence_template
= {
433 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
435 0, /* tp_basicsize */
437 (destructor
)structseq_dealloc
, /* tp_dealloc */
442 (reprfunc
)structseq_repr
, /* tp_repr */
443 0, /* tp_as_number */
444 &structseq_as_sequence
, /* tp_as_sequence */
445 &structseq_as_mapping
, /* tp_as_mapping */
446 structseq_hash
, /* tp_hash */
451 0, /* tp_as_buffer */
452 Py_TPFLAGS_DEFAULT
, /* tp_flags */
456 structseq_richcompare
, /* tp_richcompare */
457 0, /* tp_weaklistoffset */
460 structseq_methods
, /* tp_methods */
461 NULL
, /* tp_members */
465 0, /* tp_descr_get */
466 0, /* tp_descr_set */
467 0, /* tp_dictoffset */
470 structseq_new
, /* tp_new */
474 PyStructSequence_InitType(PyTypeObject
*type
, PyStructSequence_Desc
*desc
)
477 PyMemberDef
* members
;
478 int n_members
, n_unnamed_members
, i
, k
;
481 /* if the type object was chained, unchain it first
482 before overwriting its storage */
483 if (type
->_ob_next
) {
484 _Py_ForgetReference((PyObject
*)type
);
488 n_unnamed_members
= 0;
489 for (i
= 0; desc
->fields
[i
].name
!= NULL
; ++i
)
490 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
494 memcpy(type
, &_struct_sequence_template
, sizeof(PyTypeObject
));
495 type
->tp_name
= desc
->name
;
496 type
->tp_doc
= desc
->doc
;
497 type
->tp_basicsize
= sizeof(PyStructSequence
)+
498 sizeof(PyObject
*)*(n_members
-1);
499 type
->tp_itemsize
= 0;
501 members
= PyMem_NEW(PyMemberDef
, n_members
-n_unnamed_members
+1);
505 for (i
= k
= 0; i
< n_members
; ++i
) {
506 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
508 members
[k
].name
= desc
->fields
[i
].name
;
509 members
[k
].type
= T_OBJECT
;
510 members
[k
].offset
= offsetof(PyStructSequence
, ob_item
)
511 + i
* sizeof(PyObject
*);
512 members
[k
].flags
= READONLY
;
513 members
[k
].doc
= desc
->fields
[i
].doc
;
516 members
[k
].name
= NULL
;
518 type
->tp_members
= members
;
520 if (PyType_Ready(type
) < 0)
524 dict
= type
->tp_dict
;
525 PyDict_SetItemString(dict
, visible_length_key
,
526 PyInt_FromLong((long) desc
->n_in_sequence
));
527 PyDict_SetItemString(dict
, real_length_key
,
528 PyInt_FromLong((long) n_members
));
529 PyDict_SetItemString(dict
, unnamed_fields_key
,
530 PyInt_FromLong((long) n_unnamed_members
));