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
)
234 tup
= make_tuple(obj
);
235 str
= PyObject_Repr(tup
);
241 structseq_concat(PyStructSequence
*obj
, PyObject
*b
)
243 PyObject
*tup
, *result
;
244 tup
= make_tuple(obj
);
245 result
= PySequence_Concat(tup
, b
);
251 structseq_repeat(PyStructSequence
*obj
, Py_ssize_t n
)
253 PyObject
*tup
, *result
;
254 tup
= make_tuple(obj
);
255 result
= PySequence_Repeat(tup
, n
);
261 structseq_contains(PyStructSequence
*obj
, PyObject
*o
)
265 tup
= make_tuple(obj
);
268 result
= PySequence_Contains(tup
, o
);
274 structseq_hash(PyObject
*obj
)
278 tup
= make_tuple((PyStructSequence
*) obj
);
281 result
= PyObject_Hash(tup
);
287 structseq_richcompare(PyObject
*obj
, PyObject
*o2
, int op
)
289 PyObject
*tup
, *result
;
290 tup
= make_tuple((PyStructSequence
*) obj
);
291 result
= PyObject_RichCompare(tup
, o2
, op
);
297 structseq_reduce(PyStructSequence
* self
)
302 Py_ssize_t n_fields
, n_visible_fields
, n_unnamed_fields
;
305 n_fields
= REAL_SIZE(self
);
306 n_visible_fields
= VISIBLE_SIZE(self
);
307 n_unnamed_fields
= UNNAMED_FIELDS(self
);
308 tup
= PyTuple_New(n_visible_fields
);
319 for (i
= 0; i
< n_visible_fields
; i
++) {
320 Py_INCREF(self
->ob_item
[i
]);
321 PyTuple_SET_ITEM(tup
, i
, self
->ob_item
[i
]);
324 for (; i
< n_fields
; i
++) {
325 char *n
= Py_Type(self
)->tp_members
[i
-n_unnamed_fields
].name
;
326 PyDict_SetItemString(dict
, n
,
330 result
= Py_BuildValue("(O(OO))", Py_Type(self
), tup
, dict
);
338 static PySequenceMethods structseq_as_sequence
= {
339 (lenfunc
)structseq_length
,
340 (binaryfunc
)structseq_concat
, /* sq_concat */
341 (ssizeargfunc
)structseq_repeat
, /* sq_repeat */
342 (ssizeargfunc
)structseq_item
, /* sq_item */
343 (ssizessizeargfunc
)structseq_slice
, /* sq_slice */
345 0, /* sq_ass_slice */
346 (objobjproc
)structseq_contains
, /* sq_contains */
349 static PyMappingMethods structseq_as_mapping
= {
350 (lenfunc
)structseq_length
,
351 (binaryfunc
)structseq_subscript
,
354 static PyMethodDef structseq_methods
[] = {
355 {"__reduce__", (PyCFunction
)structseq_reduce
,
360 static PyTypeObject _struct_sequence_template
= {
361 PyVarObject_HEAD_INIT(&PyType_Type
, 0)
363 0, /* tp_basicsize */
365 (destructor
)structseq_dealloc
, /* tp_dealloc */
370 (reprfunc
)structseq_repr
, /* tp_repr */
371 0, /* tp_as_number */
372 &structseq_as_sequence
, /* tp_as_sequence */
373 &structseq_as_mapping
, /* tp_as_mapping */
374 structseq_hash
, /* tp_hash */
379 0, /* tp_as_buffer */
380 Py_TPFLAGS_DEFAULT
, /* tp_flags */
384 structseq_richcompare
, /* tp_richcompare */
385 0, /* tp_weaklistoffset */
388 structseq_methods
, /* tp_methods */
389 NULL
, /* tp_members */
393 0, /* tp_descr_get */
394 0, /* tp_descr_set */
395 0, /* tp_dictoffset */
398 structseq_new
, /* tp_new */
402 PyStructSequence_InitType(PyTypeObject
*type
, PyStructSequence_Desc
*desc
)
405 PyMemberDef
* members
;
406 int n_members
, n_unnamed_members
, i
, k
;
409 /* if the type object was chained, unchain it first
410 before overwriting its storage */
411 if (type
->_ob_next
) {
412 _Py_ForgetReference((PyObject
*)type
);
416 n_unnamed_members
= 0;
417 for (i
= 0; desc
->fields
[i
].name
!= NULL
; ++i
)
418 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
422 memcpy(type
, &_struct_sequence_template
, sizeof(PyTypeObject
));
423 type
->tp_name
= desc
->name
;
424 type
->tp_doc
= desc
->doc
;
425 type
->tp_basicsize
= sizeof(PyStructSequence
)+
426 sizeof(PyObject
*)*(n_members
-1);
427 type
->tp_itemsize
= 0;
429 members
= PyMem_NEW(PyMemberDef
, n_members
-n_unnamed_members
+1);
433 for (i
= k
= 0; i
< n_members
; ++i
) {
434 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
436 members
[k
].name
= desc
->fields
[i
].name
;
437 members
[k
].type
= T_OBJECT
;
438 members
[k
].offset
= offsetof(PyStructSequence
, ob_item
)
439 + i
* sizeof(PyObject
*);
440 members
[k
].flags
= READONLY
;
441 members
[k
].doc
= desc
->fields
[i
].doc
;
444 members
[k
].name
= NULL
;
446 type
->tp_members
= members
;
448 if (PyType_Ready(type
) < 0)
452 dict
= type
->tp_dict
;
453 PyDict_SetItemString(dict
, visible_length_key
,
454 PyInt_FromLong((long) desc
->n_in_sequence
));
455 PyDict_SetItemString(dict
, real_length_key
,
456 PyInt_FromLong((long) n_members
));
457 PyDict_SetItemString(dict
, unnamed_fields_key
,
458 PyInt_FromLong((long) n_unnamed_members
));