Change to flush and close logic to fix #1760556.
[python.git] / Objects / structseq.c
blobfb6b96d167391f0aa9d06173f1b3fd2524aafce4
1 /* Implementation helper: a struct that looks like a tuple. See timemodule
2 and posixmodule for example uses. */
4 #include "Python.h"
5 #include "structmember.h"
6 #include "structseq.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))
29 PyObject *
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;
40 static void
41 structseq_dealloc(PyStructSequence *obj)
43 Py_ssize_t i, size;
45 size = REAL_SIZE(obj);
46 for (i = 0; i < size; ++i) {
47 Py_XDECREF(obj->ob_item[i]);
49 PyObject_Del(obj);
52 static Py_ssize_t
53 structseq_length(PyStructSequence *obj)
55 return VISIBLE_SIZE(obj);
58 static PyObject*
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");
63 return NULL;
65 Py_INCREF(obj->ob_item[i]);
66 return obj->ob_item[i];
69 static PyObject*
70 structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high)
72 PyTupleObject *np;
73 Py_ssize_t i;
75 if (low < 0)
76 low = 0;
77 if (high > VISIBLE_SIZE(obj))
78 high = VISIBLE_SIZE(obj);
79 if (high < low)
80 high = low;
81 np = (PyTupleObject *)PyTuple_New(high-low);
82 if (np == NULL)
83 return NULL;
84 for(i = low; i < high; ++i) {
85 PyObject *v = obj->ob_item[i];
86 Py_INCREF(v);
87 PyTuple_SET_ITEM(np, i-low, v);
89 return (PyObject *) np;
92 static PyObject *
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())
98 return NULL;
100 if (i < 0)
101 i += VISIBLE_SIZE(self);
103 if (i < 0 || i >= VISIBLE_SIZE(self)) {
104 PyErr_SetString(PyExc_IndexError,
105 "tuple index out of range");
106 return NULL;
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;
113 PyObject *result;
115 if (PySlice_GetIndicesEx((PySliceObject *)item,
116 VISIBLE_SIZE(self), &start, &stop,
117 &step, &slicelen) < 0) {
118 return NULL;
120 if (slicelen <= 0)
121 return PyTuple_New(0);
122 result = PyTuple_New(slicelen);
123 if (result == NULL)
124 return NULL;
125 for (cur = start, i = 0; i < slicelen;
126 cur += step, i++) {
127 PyObject *v = self->ob_item[cur];
128 Py_INCREF(v);
129 PyTuple_SET_ITEM(result, i, v);
131 return result;
133 else {
134 PyErr_SetString(PyExc_TypeError,
135 "structseq index must be integer");
136 return NULL;
140 static PyObject *
141 structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
143 PyObject *arg = NULL;
144 PyObject *dict = NULL;
145 PyObject *ob;
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))
152 return NULL;
154 arg = PySequence_Fast(arg, "constructor requires a sequence");
156 if (!arg) {
157 return NULL;
160 if (dict && !PyDict_Check(dict)) {
161 PyErr_Format(PyExc_TypeError,
162 "%.500s() takes a dict as second arg, if any",
163 type->tp_name);
164 Py_DECREF(arg);
165 return NULL;
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) {
174 if (len < min_len) {
175 PyErr_Format(PyExc_TypeError,
176 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
177 type->tp_name, min_len, len);
178 Py_DECREF(arg);
179 return NULL;
182 if (len > max_len) {
183 PyErr_Format(PyExc_TypeError,
184 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
185 type->tp_name, max_len, len);
186 Py_DECREF(arg);
187 return NULL;
190 else {
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);
195 Py_DECREF(arg);
196 return NULL;
200 res = (PyStructSequence*) PyStructSequence_New(type);
201 if (res == NULL) {
202 return NULL;
204 for (i = 0; i < len; ++i) {
205 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
206 Py_INCREF(v);
207 res->ob_item[i] = v;
209 for (; i < max_len; ++i) {
210 if (dict && (ob = PyDict_GetItemString(
211 dict, type->tp_members[i-n_unnamed_fields].name))) {
213 else {
214 ob = Py_None;
216 Py_INCREF(ob);
217 res->ob_item[i] = ob;
220 Py_DECREF(arg);
221 return (PyObject*) res;
224 static PyObject *
225 make_tuple(PyStructSequence *obj)
227 return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
230 static PyObject *
231 structseq_repr(PyStructSequence *obj)
233 PyObject *tup, *str;
234 tup = make_tuple(obj);
235 str = PyObject_Repr(tup);
236 Py_DECREF(tup);
237 return str;
240 static PyObject *
241 structseq_concat(PyStructSequence *obj, PyObject *b)
243 PyObject *tup, *result;
244 tup = make_tuple(obj);
245 result = PySequence_Concat(tup, b);
246 Py_DECREF(tup);
247 return result;
250 static PyObject *
251 structseq_repeat(PyStructSequence *obj, Py_ssize_t n)
253 PyObject *tup, *result;
254 tup = make_tuple(obj);
255 result = PySequence_Repeat(tup, n);
256 Py_DECREF(tup);
257 return result;
260 static int
261 structseq_contains(PyStructSequence *obj, PyObject *o)
263 PyObject *tup;
264 int result;
265 tup = make_tuple(obj);
266 if (!tup)
267 return -1;
268 result = PySequence_Contains(tup, o);
269 Py_DECREF(tup);
270 return result;
273 static long
274 structseq_hash(PyObject *obj)
276 PyObject *tup;
277 long result;
278 tup = make_tuple((PyStructSequence*) obj);
279 if (!tup)
280 return -1;
281 result = PyObject_Hash(tup);
282 Py_DECREF(tup);
283 return result;
286 static PyObject *
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);
292 Py_DECREF(tup);
293 return result;
296 static PyObject *
297 structseq_reduce(PyStructSequence* self)
299 PyObject* tup;
300 PyObject* dict;
301 PyObject* result;
302 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
303 int i;
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);
309 if (!tup) {
310 return NULL;
313 dict = PyDict_New();
314 if (!dict) {
315 Py_DECREF(tup);
316 return NULL;
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,
327 self->ob_item[i]);
330 result = Py_BuildValue("(O(OO))", Py_Type(self), tup, dict);
332 Py_DECREF(tup);
333 Py_DECREF(dict);
335 return result;
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 */
344 0, /* sq_ass_item */
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,
356 METH_NOARGS, NULL},
357 {NULL, NULL}
360 static PyTypeObject _struct_sequence_template = {
361 PyVarObject_HEAD_INIT(&PyType_Type, 0)
362 NULL, /* tp_name */
363 0, /* tp_basicsize */
364 0, /* tp_itemsize */
365 (destructor)structseq_dealloc, /* tp_dealloc */
366 0, /* tp_print */
367 0, /* tp_getattr */
368 0, /* tp_setattr */
369 0, /* tp_compare */
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 */
375 0, /* tp_call */
376 0, /* tp_str */
377 0, /* tp_getattro */
378 0, /* tp_setattro */
379 0, /* tp_as_buffer */
380 Py_TPFLAGS_DEFAULT, /* tp_flags */
381 NULL, /* tp_doc */
382 0, /* tp_traverse */
383 0, /* tp_clear */
384 structseq_richcompare, /* tp_richcompare */
385 0, /* tp_weaklistoffset */
386 0, /* tp_iter */
387 0, /* tp_iternext */
388 structseq_methods, /* tp_methods */
389 NULL, /* tp_members */
390 0, /* tp_getset */
391 0, /* tp_base */
392 0, /* tp_dict */
393 0, /* tp_descr_get */
394 0, /* tp_descr_set */
395 0, /* tp_dictoffset */
396 0, /* tp_init */
397 0, /* tp_alloc */
398 structseq_new, /* tp_new */
401 void
402 PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
404 PyObject *dict;
405 PyMemberDef* members;
406 int n_members, n_unnamed_members, i, k;
408 #ifdef Py_TRACE_REFS
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);
414 #endif
416 n_unnamed_members = 0;
417 for (i = 0; desc->fields[i].name != NULL; ++i)
418 if (desc->fields[i].name == PyStructSequence_UnnamedField)
419 n_unnamed_members++;
420 n_members = i;
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);
430 if (members == NULL)
431 return;
433 for (i = k = 0; i < n_members; ++i) {
434 if (desc->fields[i].name == PyStructSequence_UnnamedField)
435 continue;
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;
442 k++;
444 members[k].name = NULL;
446 type->tp_members = members;
448 if (PyType_Ready(type) < 0)
449 return;
450 Py_INCREF(type);
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));