blob: e14e4ca0f678c905c99423fe3f1e9ca76a081ec5 [file] [log] [blame]
Guido van Rossume82f75a2001-10-18 20:47:51 +00001/* Implementation helper: a struct that looks like a tuple. See timemodule
2 and posixmodule for example uses. */
3
4#include "Python.h"
5#include "structmember.h"
6#include "structseq.h"
7
8static char visible_length_key[] = "n_sequence_fields";
9static char real_length_key[] = "n_fields";
Martin v. Löwisceaa77c2002-10-16 19:10:03 +000010static char unnamed_fields_key[] = "n_unnamed_fields";
Guido van Rossume82f75a2001-10-18 20:47:51 +000011
Martin v. Löwisf607bda2002-10-16 18:27:39 +000012/* Fields with this name have only a field index, not a field name.
13 They are only allowed for indices < n_visible_fields. */
14char *PyStructSequence_UnnamedField = "unnamed field";
15
Guido van Rossume82f75a2001-10-18 20:47:51 +000016#define VISIBLE_SIZE(op) ((op)->ob_size)
17#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \
18 PyDict_GetItemString((tp)->tp_dict, visible_length_key))
19
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)
23
Martin v. Löwisceaa77c2002-10-16 19:10:03 +000024#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)
27
Guido van Rossume82f75a2001-10-18 20:47:51 +000028
29PyObject *
30PyStructSequence_New(PyTypeObject *type)
31{
32 PyStructSequence *obj;
33
Neil Schemenauer7465ad22002-04-12 03:05:37 +000034 obj = PyObject_New(PyStructSequence, type);
Guido van Rossume82f75a2001-10-18 20:47:51 +000035 obj->ob_size = VISIBLE_SIZE_TP(type);
36
37 return (PyObject*) obj;
38}
39
40static void
41structseq_dealloc(PyStructSequence *obj)
42{
43 int i, size;
44
45 size = REAL_SIZE(obj);
46 for (i = 0; i < size; ++i) {
47 Py_XDECREF(obj->ob_item[i]);
48 }
Neil Schemenauer7465ad22002-04-12 03:05:37 +000049 PyObject_Del(obj);
Guido van Rossume82f75a2001-10-18 20:47:51 +000050}
51
52static int
53structseq_length(PyStructSequence *obj)
54{
55 return VISIBLE_SIZE(obj);
56}
57
58static PyObject*
59structseq_item(PyStructSequence *obj, int i)
60{
61 if (i < 0 || i >= VISIBLE_SIZE(obj)) {
62 PyErr_SetString(PyExc_IndexError, "tuple index out of range");
63 return NULL;
64 }
65 Py_INCREF(obj->ob_item[i]);
66 return obj->ob_item[i];
67}
68
69static PyObject*
70structseq_slice(PyStructSequence *obj, int low, int high)
71{
72 PyTupleObject *np;
73 int i;
74
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);
Tim Petersc2fe6182001-10-30 23:20:46 +000087 PyTuple_SET_ITEM(np, i-low, v);
Guido van Rossume82f75a2001-10-18 20:47:51 +000088 }
89 return (PyObject *) np;
90}
91
92static PyObject *
93structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
94{
95 PyObject *arg = NULL;
Michael W. Hudsonce358e32002-03-06 17:07:49 +000096 PyObject *dict = NULL;
97 PyObject *ob;
Guido van Rossume82f75a2001-10-18 20:47:51 +000098 PyStructSequence *res = NULL;
Martin v. Löwisceaa77c2002-10-16 19:10:03 +000099 int len, min_len, max_len, i, n_unnamed_fields;
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000100 static char *kwlist[] = {"sequence", "dict", 0};
Guido van Rossume82f75a2001-10-18 20:47:51 +0000101
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000102 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
103 kwlist, &arg, &dict))
Guido van Rossume82f75a2001-10-18 20:47:51 +0000104 return NULL;
105
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000106 arg = PySequence_Fast(arg, "constructor requires a sequence");
107
108 if (!arg) {
Guido van Rossume82f75a2001-10-18 20:47:51 +0000109 return NULL;
110 }
111
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000112 if (dict && !PyDict_Check(dict)) {
113 PyErr_Format(PyExc_TypeError,
114 "%.500s() takes a dict as second arg, if any",
115 type->tp_name);
116 Py_DECREF(arg);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000117 return NULL;
118 }
119
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000120 len = PySequence_Fast_GET_SIZE(arg);
121 min_len = VISIBLE_SIZE_TP(type);
122 max_len = REAL_SIZE_TP(type);
Martin v. Löwisceaa77c2002-10-16 19:10:03 +0000123 n_unnamed_fields = UNNAMED_FIELDS_TP(type);
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000124
125 if (min_len != max_len) {
126 if (len < min_len) {
127 PyErr_Format(PyExc_TypeError,
128 "%.500s() takes an at least %d-sequence (%d-sequence given)",
129 type->tp_name, min_len, len);
130 Py_DECREF(arg);
131 return NULL;
132 }
133
134 if (len > max_len) {
135 PyErr_Format(PyExc_TypeError,
136 "%.500s() takes an at most %d-sequence (%d-sequence given)",
137 type->tp_name, max_len, len);
138 Py_DECREF(arg);
139 return NULL;
140 }
141 }
142 else {
143 if (len != min_len) {
144 PyErr_Format(PyExc_TypeError,
145 "%.500s() takes a %d-sequence (%d-sequence given)",
146 type->tp_name, min_len, len);
147 Py_DECREF(arg);
148 return NULL;
149 }
150 }
151
Guido van Rossume82f75a2001-10-18 20:47:51 +0000152 res = (PyStructSequence*) PyStructSequence_New(type);
153 for (i = 0; i < len; ++i) {
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000154 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
155 Py_INCREF(v);
156 res->ob_item[i] = v;
157 }
158 for (; i < max_len; ++i) {
159 if (dict && (ob = PyDict_GetItemString(
Martin v. Löwisceaa77c2002-10-16 19:10:03 +0000160 dict, type->tp_members[i-n_unnamed_fields].name))) {
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000161 }
162 else {
163 ob = Py_None;
164 }
165 Py_INCREF(ob);
166 res->ob_item[i] = ob;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000167 }
168
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000169 Py_DECREF(arg);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000170 return (PyObject*) res;
171}
172
173static PyObject *
174make_tuple(PyStructSequence *obj)
175{
176 return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
177}
178
179static PyObject *
180structseq_repr(PyStructSequence *obj)
181{
182 PyObject *tup, *str;
183 tup = make_tuple(obj);
184 str = PyObject_Repr(tup);
185 Py_DECREF(tup);
186 return str;
187}
188
189static PyObject *
190structseq_concat(PyStructSequence *obj, PyObject *b)
191{
192 PyObject *tup, *result;
193 tup = make_tuple(obj);
194 result = PySequence_Concat(tup, b);
195 Py_DECREF(tup);
196 return result;
197}
198
199static PyObject *
200structseq_repeat(PyStructSequence *obj, int n)
201{
202 PyObject *tup, *result;
203 tup = make_tuple(obj);
204 result = PySequence_Repeat(tup, n);
205 Py_DECREF(tup);
206 return result;
207}
208
209static int
210structseq_contains(PyStructSequence *obj, PyObject *o)
211{
212 PyObject *tup;
213 int result;
214 tup = make_tuple(obj);
215 result = PySequence_Contains(tup, o);
216 Py_DECREF(tup);
217 return result;
218}
219
220static long
221structseq_hash(PyObject *obj)
222{
223 PyObject *tup;
224 long result;
225 tup = make_tuple((PyStructSequence*) obj);
226 result = PyObject_Hash(tup);
227 Py_DECREF(tup);
228 return result;
229}
230
231static PyObject *
232structseq_richcompare(PyObject *obj, PyObject *o2, int op)
233{
234 PyObject *tup, *result;
235 tup = make_tuple((PyStructSequence*) obj);
236 result = PyObject_RichCompare(tup, o2, op);
237 Py_DECREF(tup);
238 return result;
239}
240
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000241static PyObject *
242structseq_reduce(PyStructSequence* self)
243{
244 PyObject* tup;
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000245 PyObject* dict;
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000246 PyObject* result;
Martin v. Löwisceaa77c2002-10-16 19:10:03 +0000247 long n_fields, n_visible_fields, n_unnamed_fields;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000248 int i;
249
250 n_fields = REAL_SIZE(self);
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000251 n_visible_fields = VISIBLE_SIZE(self);
Martin v. Löwisceaa77c2002-10-16 19:10:03 +0000252 n_unnamed_fields = UNNAMED_FIELDS(self);
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000253 tup = PyTuple_New(n_visible_fields);
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000254 if (!tup) {
255 return NULL;
256 }
257
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000258 dict = PyDict_New();
259 if (!dict) {
260 Py_DECREF(tup);
261 return NULL;
262 }
263
264 for (i = 0; i < n_visible_fields; i++) {
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000265 Py_INCREF(self->ob_item[i]);
266 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
267 }
268
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000269 for (; i < n_fields; i++) {
Martin v. Löwisceaa77c2002-10-16 19:10:03 +0000270 char *n = self->ob_type->tp_members[i-n_unnamed_fields].name;
271 PyDict_SetItemString(dict, n,
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000272 self->ob_item[i]);
273 }
274
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000275 result = Py_BuildValue("(O(OO))", self->ob_type, tup, dict);
276
277 Py_DECREF(tup);
278 Py_DECREF(dict);
279
280 return result;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000281}
282
Guido van Rossume82f75a2001-10-18 20:47:51 +0000283static PySequenceMethods structseq_as_sequence = {
284 (inquiry)structseq_length,
285 (binaryfunc)structseq_concat, /* sq_concat */
286 (intargfunc)structseq_repeat, /* sq_repeat */
287 (intargfunc)structseq_item, /* sq_item */
288 (intintargfunc)structseq_slice, /* sq_slice */
289 0, /* sq_ass_item */
290 0, /* sq_ass_slice */
291 (objobjproc)structseq_contains, /* sq_contains */
292};
293
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000294static PyMethodDef structseq_methods[] = {
295 {"__reduce__", (PyCFunction)structseq_reduce,
296 METH_NOARGS, NULL},
297 {NULL, NULL}
298};
299
Guido van Rossume82f75a2001-10-18 20:47:51 +0000300static PyTypeObject _struct_sequence_template = {
301 PyObject_HEAD_INIT(&PyType_Type)
302 0, /* ob_size */
303 NULL, /* tp_name */
304 0, /* tp_basicsize */
305 0, /* tp_itemsize */
306 (destructor)structseq_dealloc, /* tp_dealloc */
307 0, /* tp_print */
308 0, /* tp_getattr */
309 0, /* tp_setattr */
310 0, /* tp_compare */
311 (reprfunc)structseq_repr, /* tp_repr */
312 0, /* tp_as_number */
313 &structseq_as_sequence, /* tp_as_sequence */
314 0, /* tp_as_mapping */
315 (hashfunc)structseq_hash, /* tp_hash */
316 0, /* tp_call */
317 0, /* tp_str */
318 0, /* tp_getattro */
319 0, /* tp_setattro */
320 0, /* tp_as_buffer */
321 Py_TPFLAGS_DEFAULT, /* tp_flags */
322 NULL, /* tp_doc */
323 0, /* tp_traverse */
324 0, /* tp_clear */
325 structseq_richcompare, /* tp_richcompare */
326 0, /* tp_weaklistoffset */
327 0, /* tp_iter */
328 0, /* tp_iternext */
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000329 structseq_methods, /* tp_methods */
Guido van Rossume82f75a2001-10-18 20:47:51 +0000330 NULL, /* tp_members */
331 0, /* tp_getset */
332 0, /* tp_base */
333 0, /* tp_dict */
334 0, /* tp_descr_get */
335 0, /* tp_descr_set */
336 0, /* tp_dictoffset */
337 0, /* tp_init */
338 0, /* tp_alloc */
339 structseq_new, /* tp_new */
340};
341
342void
343PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
344{
345 PyObject *dict;
346 PyMemberDef* members;
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000347 int n_members, n_unnamed_members, i, k;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000348
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000349 n_unnamed_members = 0;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000350 for (i = 0; desc->fields[i].name != NULL; ++i)
Martin v. Löwisceaa77c2002-10-16 19:10:03 +0000351 if (desc->fields[i].name == PyStructSequence_UnnamedField)
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000352 n_unnamed_members++;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000353 n_members = i;
354
355 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
356 type->tp_name = desc->name;
357 type->tp_doc = desc->doc;
358 type->tp_basicsize = sizeof(PyStructSequence)+
359 sizeof(PyObject*)*(n_members-1);
360 type->tp_itemsize = 0;
361
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000362 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000363
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000364 for (i = k = 0; i < n_members; ++i) {
365 if (desc->fields[i].name == PyStructSequence_UnnamedField)
366 continue;
367 members[k].name = desc->fields[i].name;
368 members[k].type = T_OBJECT;
369 members[k].offset = offsetof(PyStructSequence, ob_item)
Guido van Rossume82f75a2001-10-18 20:47:51 +0000370 + i * sizeof(PyObject*);
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000371 members[k].flags = READONLY;
372 members[k].doc = desc->fields[i].doc;
373 k++;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000374 }
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000375 members[k].name = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000376
377 type->tp_members = members;
378
379 if (PyType_Ready(type) < 0)
380 return;
381 Py_INCREF(type);
382
383 dict = type->tp_dict;
384 PyDict_SetItemString(dict, visible_length_key,
385 PyInt_FromLong((long) desc->n_in_sequence));
386 PyDict_SetItemString(dict, real_length_key,
387 PyInt_FromLong((long) n_members));
Martin v. Löwisceaa77c2002-10-16 19:10:03 +0000388 PyDict_SetItemString(dict, unnamed_fields_key,
389 PyInt_FromLong((long) n_unnamed_members));
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000390 PyDict_SetItemString(dict, "__safe_for_unpickling__",
391 PyInt_FromLong(1));
Guido van Rossume82f75a2001-10-18 20:47:51 +0000392}