blob: ef17f49a31400eac6af35a7539c528510005cc0e [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"
Guido van Rossume82f75a2001-10-18 20:47:51 +00006
7static char visible_length_key[] = "n_sequence_fields";
8static char real_length_key[] = "n_fields";
Martin v. Löwisceaa77c2002-10-16 19:10:03 +00009static char unnamed_fields_key[] = "n_unnamed_fields";
Guido van Rossume82f75a2001-10-18 20:47:51 +000010
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000011/* Fields with this name have only a field index, not a field name.
Martin v. Löwisf607bda2002-10-16 18:27:39 +000012 They are only allowed for indices < n_visible_fields. */
13char *PyStructSequence_UnnamedField = "unnamed field";
14
Christian Heimes90aa7642007-12-19 02:45:37 +000015#define VISIBLE_SIZE(op) Py_SIZE(op)
Christian Heimes217cfd12007-12-02 14:31:20 +000016#define VISIBLE_SIZE_TP(tp) PyLong_AsLong( \
Guido van Rossume82f75a2001-10-18 20:47:51 +000017 PyDict_GetItemString((tp)->tp_dict, visible_length_key))
18
Christian Heimes217cfd12007-12-02 14:31:20 +000019#define REAL_SIZE_TP(tp) PyLong_AsLong( \
Guido van Rossume82f75a2001-10-18 20:47:51 +000020 PyDict_GetItemString((tp)->tp_dict, real_length_key))
Christian Heimes90aa7642007-12-19 02:45:37 +000021#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
Guido van Rossume82f75a2001-10-18 20:47:51 +000022
Christian Heimes217cfd12007-12-02 14:31:20 +000023#define UNNAMED_FIELDS_TP(tp) PyLong_AsLong( \
Martin v. Löwisceaa77c2002-10-16 19:10:03 +000024 PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))
Christian Heimes90aa7642007-12-19 02:45:37 +000025#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
Martin v. Löwisceaa77c2002-10-16 19:10:03 +000026
Guido van Rossume82f75a2001-10-18 20:47:51 +000027
28PyObject *
29PyStructSequence_New(PyTypeObject *type)
30{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000031 PyStructSequence *obj;
Benjamin Petersonccabcd42010-07-07 20:54:01 +000032 Py_ssize_t size = REAL_SIZE_TP(type), i;
Christian Heimesd32ed6f2008-01-14 18:49:24 +000033
Benjamin Petersonccabcd42010-07-07 20:54:01 +000034 obj = PyObject_GC_NewVar(PyStructSequence, type, size);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000035 if (obj == NULL)
36 return NULL;
Benjamin Petersond02441e2010-07-08 22:33:03 +000037 /* Hack the size of the variable object, so invisible fields don't appear
38 to Python code. */
39 Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
Benjamin Petersonccabcd42010-07-07 20:54:01 +000040 for (i = 0; i < size; i++)
41 obj->ob_item[i] = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +000042
Benjamin Petersonccabcd42010-07-07 20:54:01 +000043 return (PyObject*)obj;
Thomas Woutersed03b412007-08-28 21:37:11 +000044}
45
Martin v. Löwis4d0d4712010-12-03 20:14:31 +000046void
47PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
48{
49 PyStructSequence_SET_ITEM(op, i, v);
50}
51
52PyObject*
53PyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
54{
55 return PyStructSequence_GET_ITEM(op, i);
56}
57
Benjamin Petersond02441e2010-07-08 22:33:03 +000058static void
59structseq_dealloc(PyStructSequence *obj)
60{
61 Py_ssize_t i, size;
62
63 size = REAL_SIZE(obj);
64 for (i = 0; i < size; ++i) {
65 Py_XDECREF(obj->ob_item[i]);
66 }
67 PyObject_GC_Del(obj);
68}
69
Thomas Woutersed03b412007-08-28 21:37:11 +000070static PyObject *
Guido van Rossume82f75a2001-10-18 20:47:51 +000071structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
72{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000073 PyObject *arg = NULL;
74 PyObject *dict = NULL;
75 PyObject *ob;
76 PyStructSequence *res = NULL;
77 Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
78 static char *kwlist[] = {"sequence", "dict", 0};
Guido van Rossume82f75a2001-10-18 20:47:51 +000079
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000080 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
81 kwlist, &arg, &dict))
82 return NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +000083
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000084 arg = PySequence_Fast(arg, "constructor requires a sequence");
Michael W. Hudsonce358e32002-03-06 17:07:49 +000085
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000086 if (!arg) {
87 return NULL;
88 }
Guido van Rossume82f75a2001-10-18 20:47:51 +000089
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000090 if (dict && !PyDict_Check(dict)) {
91 PyErr_Format(PyExc_TypeError,
92 "%.500s() takes a dict as second arg, if any",
93 type->tp_name);
94 Py_DECREF(arg);
95 return NULL;
96 }
Guido van Rossume82f75a2001-10-18 20:47:51 +000097
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000098 len = PySequence_Fast_GET_SIZE(arg);
99 min_len = VISIBLE_SIZE_TP(type);
100 max_len = REAL_SIZE_TP(type);
101 n_unnamed_fields = UNNAMED_FIELDS_TP(type);
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000102
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000103 if (min_len != max_len) {
104 if (len < min_len) {
105 PyErr_Format(PyExc_TypeError,
106 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
107 type->tp_name, min_len, len);
108 Py_DECREF(arg);
109 return NULL;
110 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000111
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000112 if (len > max_len) {
113 PyErr_Format(PyExc_TypeError,
114 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
115 type->tp_name, max_len, len);
116 Py_DECREF(arg);
117 return NULL;
118 }
119 }
120 else {
121 if (len != min_len) {
122 PyErr_Format(PyExc_TypeError,
123 "%.500s() takes a %zd-sequence (%zd-sequence given)",
124 type->tp_name, min_len, len);
125 Py_DECREF(arg);
126 return NULL;
127 }
128 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000129
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000130 res = (PyStructSequence*) PyStructSequence_New(type);
131 if (res == NULL) {
132 return NULL;
133 }
134 for (i = 0; i < len; ++i) {
135 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
136 Py_INCREF(v);
137 res->ob_item[i] = v;
138 }
139 for (; i < max_len; ++i) {
140 if (dict && (ob = PyDict_GetItemString(
141 dict, type->tp_members[i-n_unnamed_fields].name))) {
142 }
143 else {
144 ob = Py_None;
145 }
146 Py_INCREF(ob);
147 res->ob_item[i] = ob;
148 }
149
150 Py_DECREF(arg);
151 return (PyObject*) res;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000152}
153
Guido van Rossume82f75a2001-10-18 20:47:51 +0000154
155static PyObject *
156structseq_repr(PyStructSequence *obj)
157{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 /* buffer and type size were chosen well considered. */
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000159#define REPR_BUFFER_SIZE 512
160#define TYPE_MAXSIZE 100
161
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 PyTypeObject *typ = Py_TYPE(obj);
163 int i, removelast = 0;
164 Py_ssize_t len;
165 char buf[REPR_BUFFER_SIZE];
166 char *endofbuf, *pbuf = buf;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000167
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000168 /* pointer to end of writeable buffer; safes space for "...)\0" */
169 endofbuf= &buf[REPR_BUFFER_SIZE-5];
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000170
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 /* "typename(", limited to TYPE_MAXSIZE */
172 len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
173 strlen(typ->tp_name);
174 strncpy(pbuf, typ->tp_name, len);
175 pbuf += len;
176 *pbuf++ = '(';
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000177
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000178 for (i=0; i < VISIBLE_SIZE(obj); i++) {
179 PyObject *val, *repr;
180 char *cname, *crepr;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000181
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000182 cname = typ->tp_members[i].name;
Benjamin Petersond02441e2010-07-08 22:33:03 +0000183 if (cname == NULL) {
184 PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL"
185 " for type %.500s", i, typ->tp_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000186 return NULL;
Benjamin Petersond02441e2010-07-08 22:33:03 +0000187 }
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000188 val = PyStructSequence_GET_ITEM(obj, i);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000189 repr = PyObject_Repr(val);
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000190 if (repr == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000191 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 crepr = _PyUnicode_AsString(repr);
193 if (crepr == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000194 Py_DECREF(repr);
195 return NULL;
196 }
197
198 /* + 3: keep space for "=" and ", " */
199 len = strlen(cname) + strlen(crepr) + 3;
200 if ((pbuf+len) <= endofbuf) {
201 strcpy(pbuf, cname);
202 pbuf += strlen(cname);
203 *pbuf++ = '=';
204 strcpy(pbuf, crepr);
205 pbuf += strlen(crepr);
206 *pbuf++ = ',';
207 *pbuf++ = ' ';
208 removelast = 1;
209 Py_DECREF(repr);
210 }
211 else {
212 strcpy(pbuf, "...");
213 pbuf += 3;
214 removelast = 0;
215 Py_DECREF(repr);
216 break;
217 }
218 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000219 if (removelast) {
220 /* overwrite last ", " */
221 pbuf-=2;
222 }
223 *pbuf++ = ')';
224 *pbuf = '\0';
225
226 return PyUnicode_FromString(buf);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000227}
228
229static PyObject *
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000230structseq_reduce(PyStructSequence* self)
231{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000232 PyObject* tup;
233 PyObject* dict;
234 PyObject* result;
235 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
236 int i;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000237
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000238 n_fields = REAL_SIZE(self);
239 n_visible_fields = VISIBLE_SIZE(self);
240 n_unnamed_fields = UNNAMED_FIELDS(self);
241 tup = PyTuple_New(n_visible_fields);
242 if (!tup) {
243 return NULL;
244 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000245
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 dict = PyDict_New();
247 if (!dict) {
248 Py_DECREF(tup);
249 return NULL;
250 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000251
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 for (i = 0; i < n_visible_fields; i++) {
253 Py_INCREF(self->ob_item[i]);
254 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
255 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000256
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000257 for (; i < n_fields; i++) {
258 char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
259 PyDict_SetItemString(dict, n,
260 self->ob_item[i]);
261 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000262
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000263 result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
264
265 Py_DECREF(tup);
266 Py_DECREF(dict);
267
268 return result;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000269}
270
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000271static PyMethodDef structseq_methods[] = {
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000272 {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000273 {NULL, NULL}
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000274};
275
Guido van Rossume82f75a2001-10-18 20:47:51 +0000276static PyTypeObject _struct_sequence_template = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000277 PyVarObject_HEAD_INIT(&PyType_Type, 0)
278 NULL, /* tp_name */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000279 sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
280 sizeof(PyObject *), /* tp_itemsize */
Benjamin Petersond02441e2010-07-08 22:33:03 +0000281 (destructor)structseq_dealloc, /* tp_dealloc */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000282 0, /* tp_print */
283 0, /* tp_getattr */
284 0, /* tp_setattr */
285 0, /* tp_reserved */
286 (reprfunc)structseq_repr, /* tp_repr */
287 0, /* tp_as_number */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000288 0, /* tp_as_sequence */
289 0, /* tp_as_mapping */
290 0, /* tp_hash */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 0, /* tp_call */
292 0, /* tp_str */
293 0, /* tp_getattro */
294 0, /* tp_setattro */
295 0, /* tp_as_buffer */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000296 Py_TPFLAGS_DEFAULT, /* tp_flags */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000297 NULL, /* tp_doc */
298 0, /* tp_traverse */
299 0, /* tp_clear */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000300 0, /* tp_richcompare */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000301 0, /* tp_weaklistoffset */
302 0, /* tp_iter */
303 0, /* tp_iternext */
304 structseq_methods, /* tp_methods */
305 NULL, /* tp_members */
306 0, /* tp_getset */
307 0, /* tp_base */
308 0, /* tp_dict */
309 0, /* tp_descr_get */
310 0, /* tp_descr_set */
311 0, /* tp_dictoffset */
312 0, /* tp_init */
313 0, /* tp_alloc */
314 structseq_new, /* tp_new */
Guido van Rossume82f75a2001-10-18 20:47:51 +0000315};
316
317void
318PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
319{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000320 PyObject *dict;
321 PyMemberDef* members;
322 int n_members, n_unnamed_members, i, k;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000323
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000324#ifdef Py_TRACE_REFS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000325 /* if the type object was chained, unchain it first
326 before overwriting its storage */
327 if (type->ob_base.ob_base._ob_next) {
328 _Py_ForgetReference((PyObject*)type);
329 }
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000330#endif
331
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 n_unnamed_members = 0;
333 for (i = 0; desc->fields[i].name != NULL; ++i)
334 if (desc->fields[i].name == PyStructSequence_UnnamedField)
335 n_unnamed_members++;
336 n_members = i;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000337
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000338 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000339 type->tp_base = &PyTuple_Type;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000340 type->tp_name = desc->name;
341 type->tp_doc = desc->doc;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000342
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000343 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
344 if (members == NULL)
345 return;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000346
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000347 for (i = k = 0; i < n_members; ++i) {
348 if (desc->fields[i].name == PyStructSequence_UnnamedField)
349 continue;
350 members[k].name = desc->fields[i].name;
351 members[k].type = T_OBJECT;
352 members[k].offset = offsetof(PyStructSequence, ob_item)
353 + i * sizeof(PyObject*);
354 members[k].flags = READONLY;
355 members[k].doc = desc->fields[i].doc;
356 k++;
357 }
358 members[k].name = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000359
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000360 type->tp_members = members;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000361
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000362 if (PyType_Ready(type) < 0)
363 return;
364 Py_INCREF(type);
Neal Norwitz2f99b242008-08-24 05:48:10 +0000365
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000366 dict = type->tp_dict;
367#define SET_DICT_FROM_INT(key, value) \
368 do { \
369 PyObject *v = PyLong_FromLong((long) value); \
370 if (v != NULL) { \
371 PyDict_SetItemString(dict, key, v); \
372 Py_DECREF(v); \
373 } \
374 } while (0)
375
376 SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
377 SET_DICT_FROM_INT(real_length_key, n_members);
378 SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000379}
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000380
381PyTypeObject*
382PyStructSequence_NewType(PyStructSequence_Desc *desc)
383{
384 PyTypeObject *result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
385 PyStructSequence_InitType(result, desc);
386 return result;
387}