blob: 0f5a0123b9d844b93042903d9c59f84df566a28f [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";
10
Martin v. Löwisf607bda2002-10-16 18:27:39 +000011/* Fields with this name have only a field index, not a field name.
12 They are only allowed for indices < n_visible_fields. */
13char *PyStructSequence_UnnamedField = "unnamed field";
14
Guido van Rossume82f75a2001-10-18 20:47:51 +000015#define VISIBLE_SIZE(op) ((op)->ob_size)
16#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \
17 PyDict_GetItemString((tp)->tp_dict, visible_length_key))
18
19#define REAL_SIZE_TP(tp) PyInt_AsLong( \
20 PyDict_GetItemString((tp)->tp_dict, real_length_key))
21#define REAL_SIZE(op) REAL_SIZE_TP((op)->ob_type)
22
23
24PyObject *
25PyStructSequence_New(PyTypeObject *type)
26{
27 PyStructSequence *obj;
28
Neil Schemenauer7465ad22002-04-12 03:05:37 +000029 obj = PyObject_New(PyStructSequence, type);
Guido van Rossume82f75a2001-10-18 20:47:51 +000030 obj->ob_size = VISIBLE_SIZE_TP(type);
31
32 return (PyObject*) obj;
33}
34
35static void
36structseq_dealloc(PyStructSequence *obj)
37{
38 int i, size;
39
40 size = REAL_SIZE(obj);
41 for (i = 0; i < size; ++i) {
42 Py_XDECREF(obj->ob_item[i]);
43 }
Neil Schemenauer7465ad22002-04-12 03:05:37 +000044 PyObject_Del(obj);
Guido van Rossume82f75a2001-10-18 20:47:51 +000045}
46
47static int
48structseq_length(PyStructSequence *obj)
49{
50 return VISIBLE_SIZE(obj);
51}
52
53static PyObject*
54structseq_item(PyStructSequence *obj, int i)
55{
56 if (i < 0 || i >= VISIBLE_SIZE(obj)) {
57 PyErr_SetString(PyExc_IndexError, "tuple index out of range");
58 return NULL;
59 }
60 Py_INCREF(obj->ob_item[i]);
61 return obj->ob_item[i];
62}
63
64static PyObject*
65structseq_slice(PyStructSequence *obj, int low, int high)
66{
67 PyTupleObject *np;
68 int i;
69
70 if (low < 0)
71 low = 0;
72 if (high > VISIBLE_SIZE(obj))
73 high = VISIBLE_SIZE(obj);
74 if (high < low)
75 high = low;
76 np = (PyTupleObject *)PyTuple_New(high-low);
77 if (np == NULL)
78 return NULL;
79 for(i = low; i < high; ++i) {
80 PyObject *v = obj->ob_item[i];
81 Py_INCREF(v);
Tim Petersc2fe6182001-10-30 23:20:46 +000082 PyTuple_SET_ITEM(np, i-low, v);
Guido van Rossume82f75a2001-10-18 20:47:51 +000083 }
84 return (PyObject *) np;
85}
86
87static PyObject *
88structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
89{
90 PyObject *arg = NULL;
Michael W. Hudsonce358e32002-03-06 17:07:49 +000091 PyObject *dict = NULL;
92 PyObject *ob;
Guido van Rossume82f75a2001-10-18 20:47:51 +000093 PyStructSequence *res = NULL;
Michael W. Hudsonce358e32002-03-06 17:07:49 +000094 int len, min_len, max_len, i;
95 static char *kwlist[] = {"sequence", "dict", 0};
Guido van Rossume82f75a2001-10-18 20:47:51 +000096
Michael W. Hudsonce358e32002-03-06 17:07:49 +000097 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
98 kwlist, &arg, &dict))
Guido van Rossume82f75a2001-10-18 20:47:51 +000099 return NULL;
100
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000101 arg = PySequence_Fast(arg, "constructor requires a sequence");
102
103 if (!arg) {
Guido van Rossume82f75a2001-10-18 20:47:51 +0000104 return NULL;
105 }
106
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000107 if (dict && !PyDict_Check(dict)) {
108 PyErr_Format(PyExc_TypeError,
109 "%.500s() takes a dict as second arg, if any",
110 type->tp_name);
111 Py_DECREF(arg);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000112 return NULL;
113 }
114
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000115 len = PySequence_Fast_GET_SIZE(arg);
116 min_len = VISIBLE_SIZE_TP(type);
117 max_len = REAL_SIZE_TP(type);
118
119 if (min_len != max_len) {
120 if (len < min_len) {
121 PyErr_Format(PyExc_TypeError,
122 "%.500s() takes an at least %d-sequence (%d-sequence given)",
123 type->tp_name, min_len, len);
124 Py_DECREF(arg);
125 return NULL;
126 }
127
128 if (len > max_len) {
129 PyErr_Format(PyExc_TypeError,
130 "%.500s() takes an at most %d-sequence (%d-sequence given)",
131 type->tp_name, max_len, len);
132 Py_DECREF(arg);
133 return NULL;
134 }
135 }
136 else {
137 if (len != min_len) {
138 PyErr_Format(PyExc_TypeError,
139 "%.500s() takes a %d-sequence (%d-sequence given)",
140 type->tp_name, min_len, len);
141 Py_DECREF(arg);
142 return NULL;
143 }
144 }
145
Guido van Rossume82f75a2001-10-18 20:47:51 +0000146 res = (PyStructSequence*) PyStructSequence_New(type);
147 for (i = 0; i < len; ++i) {
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000148 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
149 Py_INCREF(v);
150 res->ob_item[i] = v;
151 }
152 for (; i < max_len; ++i) {
153 if (dict && (ob = PyDict_GetItemString(
154 dict, type->tp_members[i].name))) {
155 }
156 else {
157 ob = Py_None;
158 }
159 Py_INCREF(ob);
160 res->ob_item[i] = ob;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000161 }
162
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000163 Py_DECREF(arg);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000164 return (PyObject*) res;
165}
166
167static PyObject *
168make_tuple(PyStructSequence *obj)
169{
170 return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
171}
172
173static PyObject *
174structseq_repr(PyStructSequence *obj)
175{
176 PyObject *tup, *str;
177 tup = make_tuple(obj);
178 str = PyObject_Repr(tup);
179 Py_DECREF(tup);
180 return str;
181}
182
183static PyObject *
184structseq_concat(PyStructSequence *obj, PyObject *b)
185{
186 PyObject *tup, *result;
187 tup = make_tuple(obj);
188 result = PySequence_Concat(tup, b);
189 Py_DECREF(tup);
190 return result;
191}
192
193static PyObject *
194structseq_repeat(PyStructSequence *obj, int n)
195{
196 PyObject *tup, *result;
197 tup = make_tuple(obj);
198 result = PySequence_Repeat(tup, n);
199 Py_DECREF(tup);
200 return result;
201}
202
203static int
204structseq_contains(PyStructSequence *obj, PyObject *o)
205{
206 PyObject *tup;
207 int result;
208 tup = make_tuple(obj);
209 result = PySequence_Contains(tup, o);
210 Py_DECREF(tup);
211 return result;
212}
213
214static long
215structseq_hash(PyObject *obj)
216{
217 PyObject *tup;
218 long result;
219 tup = make_tuple((PyStructSequence*) obj);
220 result = PyObject_Hash(tup);
221 Py_DECREF(tup);
222 return result;
223}
224
225static PyObject *
226structseq_richcompare(PyObject *obj, PyObject *o2, int op)
227{
228 PyObject *tup, *result;
229 tup = make_tuple((PyStructSequence*) obj);
230 result = PyObject_RichCompare(tup, o2, op);
231 Py_DECREF(tup);
232 return result;
233}
234
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000235static PyObject *
236structseq_reduce(PyStructSequence* self)
237{
238 PyObject* tup;
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000239 PyObject* dict;
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000240 PyObject* result;
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000241 long n_fields, n_visible_fields;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000242 int i;
243
244 n_fields = REAL_SIZE(self);
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000245 n_visible_fields = VISIBLE_SIZE(self);
246 tup = PyTuple_New(n_visible_fields);
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000247 if (!tup) {
248 return NULL;
249 }
250
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000251 dict = PyDict_New();
252 if (!dict) {
253 Py_DECREF(tup);
254 return NULL;
255 }
256
257 for (i = 0; i < n_visible_fields; i++) {
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000258 Py_INCREF(self->ob_item[i]);
259 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
260 }
261
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000262 for (; i < n_fields; i++) {
263 PyDict_SetItemString(dict, self->ob_type->tp_members[i].name,
264 self->ob_item[i]);
265 }
266
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000267 result = Py_BuildValue("(O(OO))", self->ob_type, tup, dict);
268
269 Py_DECREF(tup);
270 Py_DECREF(dict);
271
272 return result;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000273}
274
Guido van Rossume82f75a2001-10-18 20:47:51 +0000275static PySequenceMethods structseq_as_sequence = {
276 (inquiry)structseq_length,
277 (binaryfunc)structseq_concat, /* sq_concat */
278 (intargfunc)structseq_repeat, /* sq_repeat */
279 (intargfunc)structseq_item, /* sq_item */
280 (intintargfunc)structseq_slice, /* sq_slice */
281 0, /* sq_ass_item */
282 0, /* sq_ass_slice */
283 (objobjproc)structseq_contains, /* sq_contains */
284};
285
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000286static PyMethodDef structseq_methods[] = {
287 {"__reduce__", (PyCFunction)structseq_reduce,
288 METH_NOARGS, NULL},
289 {NULL, NULL}
290};
291
Guido van Rossume82f75a2001-10-18 20:47:51 +0000292static PyTypeObject _struct_sequence_template = {
293 PyObject_HEAD_INIT(&PyType_Type)
294 0, /* ob_size */
295 NULL, /* tp_name */
296 0, /* tp_basicsize */
297 0, /* tp_itemsize */
298 (destructor)structseq_dealloc, /* tp_dealloc */
299 0, /* tp_print */
300 0, /* tp_getattr */
301 0, /* tp_setattr */
302 0, /* tp_compare */
303 (reprfunc)structseq_repr, /* tp_repr */
304 0, /* tp_as_number */
305 &structseq_as_sequence, /* tp_as_sequence */
306 0, /* tp_as_mapping */
307 (hashfunc)structseq_hash, /* tp_hash */
308 0, /* tp_call */
309 0, /* tp_str */
310 0, /* tp_getattro */
311 0, /* tp_setattro */
312 0, /* tp_as_buffer */
313 Py_TPFLAGS_DEFAULT, /* tp_flags */
314 NULL, /* tp_doc */
315 0, /* tp_traverse */
316 0, /* tp_clear */
317 structseq_richcompare, /* tp_richcompare */
318 0, /* tp_weaklistoffset */
319 0, /* tp_iter */
320 0, /* tp_iternext */
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000321 structseq_methods, /* tp_methods */
Guido van Rossume82f75a2001-10-18 20:47:51 +0000322 NULL, /* tp_members */
323 0, /* tp_getset */
324 0, /* tp_base */
325 0, /* tp_dict */
326 0, /* tp_descr_get */
327 0, /* tp_descr_set */
328 0, /* tp_dictoffset */
329 0, /* tp_init */
330 0, /* tp_alloc */
331 structseq_new, /* tp_new */
332};
333
334void
335PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
336{
337 PyObject *dict;
338 PyMemberDef* members;
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000339 int n_members, n_unnamed_members, i, k;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000340
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000341 n_unnamed_members = 0;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000342 for (i = 0; desc->fields[i].name != NULL; ++i)
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000343 if (desc->fields[0].name == PyStructSequence_UnnamedField)
344 n_unnamed_members++;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000345 n_members = i;
346
347 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
348 type->tp_name = desc->name;
349 type->tp_doc = desc->doc;
350 type->tp_basicsize = sizeof(PyStructSequence)+
351 sizeof(PyObject*)*(n_members-1);
352 type->tp_itemsize = 0;
353
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000354 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000355
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000356 for (i = k = 0; i < n_members; ++i) {
357 if (desc->fields[i].name == PyStructSequence_UnnamedField)
358 continue;
359 members[k].name = desc->fields[i].name;
360 members[k].type = T_OBJECT;
361 members[k].offset = offsetof(PyStructSequence, ob_item)
Guido van Rossume82f75a2001-10-18 20:47:51 +0000362 + i * sizeof(PyObject*);
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000363 members[k].flags = READONLY;
364 members[k].doc = desc->fields[i].doc;
365 k++;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000366 }
Martin v. Löwisf607bda2002-10-16 18:27:39 +0000367 members[k].name = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000368
369 type->tp_members = members;
370
371 if (PyType_Ready(type) < 0)
372 return;
373 Py_INCREF(type);
374
375 dict = type->tp_dict;
376 PyDict_SetItemString(dict, visible_length_key,
377 PyInt_FromLong((long) desc->n_in_sequence));
378 PyDict_SetItemString(dict, real_length_key,
379 PyInt_FromLong((long) n_members));
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000380 PyDict_SetItemString(dict, "__safe_for_unpickling__",
381 PyInt_FromLong(1));
Guido van Rossume82f75a2001-10-18 20:47:51 +0000382}