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) ((op)->ob_size)
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((op)->ob_type)
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((op)->ob_type)
30 PyStructSequence_New(PyTypeObject
*type
)
32 PyStructSequence
*obj
;
34 obj
= PyObject_New(PyStructSequence
, type
);
35 obj
->ob_size
= 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_new(PyTypeObject
*type
, PyObject
*args
, PyObject
*kwds
)
96 PyObject
*dict
= NULL
;
98 PyStructSequence
*res
= NULL
;
99 Py_ssize_t len
, min_len
, max_len
, i
, n_unnamed_fields
;
100 static char *kwlist
[] = {"sequence", "dict", 0};
102 if (!PyArg_ParseTupleAndKeywords(args
, kwds
, "O|O:structseq",
103 kwlist
, &arg
, &dict
))
106 arg
= PySequence_Fast(arg
, "constructor requires a sequence");
112 if (dict
&& !PyDict_Check(dict
)) {
113 PyErr_Format(PyExc_TypeError
,
114 "%.500s() takes a dict as second arg, if any",
120 len
= PySequence_Fast_GET_SIZE(arg
);
121 min_len
= VISIBLE_SIZE_TP(type
);
122 max_len
= REAL_SIZE_TP(type
);
123 n_unnamed_fields
= UNNAMED_FIELDS_TP(type
);
125 if (min_len
!= max_len
) {
127 PyErr_Format(PyExc_TypeError
,
128 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
129 type
->tp_name
, min_len
, len
);
135 PyErr_Format(PyExc_TypeError
,
136 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
137 type
->tp_name
, max_len
, len
);
143 if (len
!= min_len
) {
144 PyErr_Format(PyExc_TypeError
,
145 "%.500s() takes a %zd-sequence (%zd-sequence given)",
146 type
->tp_name
, min_len
, len
);
152 res
= (PyStructSequence
*) PyStructSequence_New(type
);
156 for (i
= 0; i
< len
; ++i
) {
157 PyObject
*v
= PySequence_Fast_GET_ITEM(arg
, i
);
161 for (; i
< max_len
; ++i
) {
162 if (dict
&& (ob
= PyDict_GetItemString(
163 dict
, type
->tp_members
[i
-n_unnamed_fields
].name
))) {
169 res
->ob_item
[i
] = ob
;
173 return (PyObject
*) res
;
177 make_tuple(PyStructSequence
*obj
)
179 return structseq_slice(obj
, 0, VISIBLE_SIZE(obj
));
183 structseq_repr(PyStructSequence
*obj
)
186 tup
= make_tuple(obj
);
187 str
= PyObject_Repr(tup
);
193 structseq_concat(PyStructSequence
*obj
, PyObject
*b
)
195 PyObject
*tup
, *result
;
196 tup
= make_tuple(obj
);
197 result
= PySequence_Concat(tup
, b
);
203 structseq_repeat(PyStructSequence
*obj
, Py_ssize_t n
)
205 PyObject
*tup
, *result
;
206 tup
= make_tuple(obj
);
207 result
= PySequence_Repeat(tup
, n
);
213 structseq_contains(PyStructSequence
*obj
, PyObject
*o
)
217 tup
= make_tuple(obj
);
218 result
= PySequence_Contains(tup
, o
);
224 structseq_hash(PyObject
*obj
)
228 tup
= make_tuple((PyStructSequence
*) obj
);
229 result
= PyObject_Hash(tup
);
235 structseq_richcompare(PyObject
*obj
, PyObject
*o2
, int op
)
237 PyObject
*tup
, *result
;
238 tup
= make_tuple((PyStructSequence
*) obj
);
239 result
= PyObject_RichCompare(tup
, o2
, op
);
245 structseq_reduce(PyStructSequence
* self
)
250 Py_ssize_t n_fields
, n_visible_fields
, n_unnamed_fields
;
253 n_fields
= REAL_SIZE(self
);
254 n_visible_fields
= VISIBLE_SIZE(self
);
255 n_unnamed_fields
= UNNAMED_FIELDS(self
);
256 tup
= PyTuple_New(n_visible_fields
);
267 for (i
= 0; i
< n_visible_fields
; i
++) {
268 Py_INCREF(self
->ob_item
[i
]);
269 PyTuple_SET_ITEM(tup
, i
, self
->ob_item
[i
]);
272 for (; i
< n_fields
; i
++) {
273 char *n
= self
->ob_type
->tp_members
[i
-n_unnamed_fields
].name
;
274 PyDict_SetItemString(dict
, n
,
278 result
= Py_BuildValue("(O(OO))", self
->ob_type
, tup
, dict
);
286 static PySequenceMethods structseq_as_sequence
= {
287 (lenfunc
)structseq_length
,
288 (binaryfunc
)structseq_concat
, /* sq_concat */
289 (ssizeargfunc
)structseq_repeat
, /* sq_repeat */
290 (ssizeargfunc
)structseq_item
, /* sq_item */
291 (ssizessizeargfunc
)structseq_slice
, /* sq_slice */
293 0, /* sq_ass_slice */
294 (objobjproc
)structseq_contains
, /* sq_contains */
297 static PyMethodDef structseq_methods
[] = {
298 {"__reduce__", (PyCFunction
)structseq_reduce
,
303 static PyTypeObject _struct_sequence_template
= {
304 PyObject_HEAD_INIT(&PyType_Type
)
307 0, /* tp_basicsize */
309 (destructor
)structseq_dealloc
, /* tp_dealloc */
314 (reprfunc
)structseq_repr
, /* tp_repr */
315 0, /* tp_as_number */
316 &structseq_as_sequence
, /* tp_as_sequence */
317 0, /* tp_as_mapping */
318 structseq_hash
, /* tp_hash */
323 0, /* tp_as_buffer */
324 Py_TPFLAGS_DEFAULT
, /* tp_flags */
328 structseq_richcompare
, /* tp_richcompare */
329 0, /* tp_weaklistoffset */
332 structseq_methods
, /* tp_methods */
333 NULL
, /* tp_members */
337 0, /* tp_descr_get */
338 0, /* tp_descr_set */
339 0, /* tp_dictoffset */
342 structseq_new
, /* tp_new */
346 PyStructSequence_InitType(PyTypeObject
*type
, PyStructSequence_Desc
*desc
)
349 PyMemberDef
* members
;
350 int n_members
, n_unnamed_members
, i
, k
;
353 /* if the type object was chained, unchain it first
354 before overwriting its storage */
355 if (type
->_ob_next
) {
356 _Py_ForgetReference((PyObject
*)type
);
360 n_unnamed_members
= 0;
361 for (i
= 0; desc
->fields
[i
].name
!= NULL
; ++i
)
362 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
366 memcpy(type
, &_struct_sequence_template
, sizeof(PyTypeObject
));
367 type
->tp_name
= desc
->name
;
368 type
->tp_doc
= desc
->doc
;
369 type
->tp_basicsize
= sizeof(PyStructSequence
)+
370 sizeof(PyObject
*)*(n_members
-1);
371 type
->tp_itemsize
= 0;
373 members
= PyMem_NEW(PyMemberDef
, n_members
-n_unnamed_members
+1);
377 for (i
= k
= 0; i
< n_members
; ++i
) {
378 if (desc
->fields
[i
].name
== PyStructSequence_UnnamedField
)
380 members
[k
].name
= desc
->fields
[i
].name
;
381 members
[k
].type
= T_OBJECT
;
382 members
[k
].offset
= offsetof(PyStructSequence
, ob_item
)
383 + i
* sizeof(PyObject
*);
384 members
[k
].flags
= READONLY
;
385 members
[k
].doc
= desc
->fields
[i
].doc
;
388 members
[k
].name
= NULL
;
390 type
->tp_members
= members
;
392 if (PyType_Ready(type
) < 0)
396 dict
= type
->tp_dict
;
397 PyDict_SetItemString(dict
, visible_length_key
,
398 PyInt_FromLong((long) desc
->n_in_sequence
));
399 PyDict_SetItemString(dict
, real_length_key
,
400 PyInt_FromLong((long) n_members
));
401 PyDict_SetItemString(dict
, unnamed_fields_key
,
402 PyInt_FromLong((long) n_unnamed_members
));