blob: c3b9a72989a797a0b0e44e535fc6428ed890a92e [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,
Antoine Pitrou4b3c7842012-02-15 02:52:58 +0100106 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
107 type->tp_name, min_len, len);
108 Py_DECREF(arg);
109 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000110 }
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,
Antoine Pitrou4b3c7842012-02-15 02:52:58 +0100114 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
115 type->tp_name, max_len, len);
116 Py_DECREF(arg);
117 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000118 }
119 }
120 else {
121 if (len != min_len) {
122 PyErr_Format(PyExc_TypeError,
Antoine Pitrou4b3c7842012-02-15 02:52:58 +0100123 "%.500s() takes a %zd-sequence (%zd-sequence given)",
124 type->tp_name, min_len, len);
125 Py_DECREF(arg);
126 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000127 }
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) {
Antoine Pitrou37784ba2012-02-15 02:51:43 +0100132 Py_DECREF(arg);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000133 return NULL;
134 }
135 for (i = 0; i < len; ++i) {
136 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
137 Py_INCREF(v);
138 res->ob_item[i] = v;
139 }
140 for (; i < max_len; ++i) {
141 if (dict && (ob = PyDict_GetItemString(
142 dict, type->tp_members[i-n_unnamed_fields].name))) {
143 }
144 else {
145 ob = Py_None;
146 }
147 Py_INCREF(ob);
148 res->ob_item[i] = ob;
149 }
150
151 Py_DECREF(arg);
152 return (PyObject*) res;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000153}
154
Guido van Rossume82f75a2001-10-18 20:47:51 +0000155
156static PyObject *
157structseq_repr(PyStructSequence *obj)
158{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000159 /* buffer and type size were chosen well considered. */
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000160#define REPR_BUFFER_SIZE 512
161#define TYPE_MAXSIZE 100
162
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000163 PyTypeObject *typ = Py_TYPE(obj);
164 int i, removelast = 0;
165 Py_ssize_t len;
166 char buf[REPR_BUFFER_SIZE];
167 char *endofbuf, *pbuf = buf;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000168
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000169 /* pointer to end of writeable buffer; safes space for "...)\0" */
170 endofbuf= &buf[REPR_BUFFER_SIZE-5];
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000171
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000172 /* "typename(", limited to TYPE_MAXSIZE */
173 len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
174 strlen(typ->tp_name);
175 strncpy(pbuf, typ->tp_name, len);
176 pbuf += len;
177 *pbuf++ = '(';
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000178
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000179 for (i=0; i < VISIBLE_SIZE(obj); i++) {
180 PyObject *val, *repr;
181 char *cname, *crepr;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000182
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000183 cname = typ->tp_members[i].name;
Benjamin Petersond02441e2010-07-08 22:33:03 +0000184 if (cname == NULL) {
185 PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL"
186 " for type %.500s", i, typ->tp_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000187 return NULL;
Benjamin Petersond02441e2010-07-08 22:33:03 +0000188 }
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000189 val = PyStructSequence_GET_ITEM(obj, i);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 repr = PyObject_Repr(val);
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000191 if (repr == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000192 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000193 crepr = _PyUnicode_AsString(repr);
194 if (crepr == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000195 Py_DECREF(repr);
196 return NULL;
197 }
198
199 /* + 3: keep space for "=" and ", " */
200 len = strlen(cname) + strlen(crepr) + 3;
201 if ((pbuf+len) <= endofbuf) {
202 strcpy(pbuf, cname);
203 pbuf += strlen(cname);
204 *pbuf++ = '=';
205 strcpy(pbuf, crepr);
206 pbuf += strlen(crepr);
207 *pbuf++ = ',';
208 *pbuf++ = ' ';
209 removelast = 1;
210 Py_DECREF(repr);
211 }
212 else {
213 strcpy(pbuf, "...");
214 pbuf += 3;
215 removelast = 0;
216 Py_DECREF(repr);
217 break;
218 }
219 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000220 if (removelast) {
221 /* overwrite last ", " */
222 pbuf-=2;
223 }
224 *pbuf++ = ')';
225 *pbuf = '\0';
226
227 return PyUnicode_FromString(buf);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000228}
229
230static PyObject *
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000231structseq_reduce(PyStructSequence* self)
232{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000233 PyObject* tup;
234 PyObject* dict;
235 PyObject* result;
236 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
237 int i;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000238
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000239 n_fields = REAL_SIZE(self);
240 n_visible_fields = VISIBLE_SIZE(self);
241 n_unnamed_fields = UNNAMED_FIELDS(self);
242 tup = PyTuple_New(n_visible_fields);
243 if (!tup) {
244 return NULL;
245 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000246
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000247 dict = PyDict_New();
248 if (!dict) {
249 Py_DECREF(tup);
250 return NULL;
251 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000252
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 for (i = 0; i < n_visible_fields; i++) {
254 Py_INCREF(self->ob_item[i]);
255 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
256 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000257
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000258 for (; i < n_fields; i++) {
259 char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
260 PyDict_SetItemString(dict, n,
261 self->ob_item[i]);
262 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000263
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000264 result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
265
266 Py_DECREF(tup);
267 Py_DECREF(dict);
268
269 return result;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000270}
271
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000272static PyMethodDef structseq_methods[] = {
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000273 {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000274 {NULL, NULL}
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000275};
276
Guido van Rossume82f75a2001-10-18 20:47:51 +0000277static PyTypeObject _struct_sequence_template = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000278 PyVarObject_HEAD_INIT(&PyType_Type, 0)
279 NULL, /* tp_name */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000280 sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
281 sizeof(PyObject *), /* tp_itemsize */
Benjamin Petersond02441e2010-07-08 22:33:03 +0000282 (destructor)structseq_dealloc, /* tp_dealloc */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000283 0, /* tp_print */
284 0, /* tp_getattr */
285 0, /* tp_setattr */
286 0, /* tp_reserved */
287 (reprfunc)structseq_repr, /* tp_repr */
288 0, /* tp_as_number */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000289 0, /* tp_as_sequence */
290 0, /* tp_as_mapping */
291 0, /* tp_hash */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000292 0, /* tp_call */
293 0, /* tp_str */
294 0, /* tp_getattro */
295 0, /* tp_setattro */
296 0, /* tp_as_buffer */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000297 Py_TPFLAGS_DEFAULT, /* tp_flags */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000298 NULL, /* tp_doc */
299 0, /* tp_traverse */
300 0, /* tp_clear */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000301 0, /* tp_richcompare */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000302 0, /* tp_weaklistoffset */
303 0, /* tp_iter */
304 0, /* tp_iternext */
305 structseq_methods, /* tp_methods */
306 NULL, /* tp_members */
307 0, /* tp_getset */
308 0, /* tp_base */
309 0, /* tp_dict */
310 0, /* tp_descr_get */
311 0, /* tp_descr_set */
312 0, /* tp_dictoffset */
313 0, /* tp_init */
314 0, /* tp_alloc */
315 structseq_new, /* tp_new */
Guido van Rossume82f75a2001-10-18 20:47:51 +0000316};
317
318void
319PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
320{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000321 PyObject *dict;
322 PyMemberDef* members;
323 int n_members, n_unnamed_members, i, k;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000324
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000325#ifdef Py_TRACE_REFS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000326 /* if the type object was chained, unchain it first
327 before overwriting its storage */
328 if (type->ob_base.ob_base._ob_next) {
329 _Py_ForgetReference((PyObject*)type);
330 }
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000331#endif
332
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 n_unnamed_members = 0;
334 for (i = 0; desc->fields[i].name != NULL; ++i)
335 if (desc->fields[i].name == PyStructSequence_UnnamedField)
336 n_unnamed_members++;
337 n_members = i;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000338
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000339 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000340 type->tp_base = &PyTuple_Type;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000341 type->tp_name = desc->name;
342 type->tp_doc = desc->doc;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000343
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000344 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
345 if (members == NULL)
346 return;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000347
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000348 for (i = k = 0; i < n_members; ++i) {
349 if (desc->fields[i].name == PyStructSequence_UnnamedField)
350 continue;
351 members[k].name = desc->fields[i].name;
352 members[k].type = T_OBJECT;
353 members[k].offset = offsetof(PyStructSequence, ob_item)
354 + i * sizeof(PyObject*);
355 members[k].flags = READONLY;
356 members[k].doc = desc->fields[i].doc;
357 k++;
358 }
359 members[k].name = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000360
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000361 type->tp_members = members;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000362
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000363 if (PyType_Ready(type) < 0)
364 return;
365 Py_INCREF(type);
Neal Norwitz2f99b242008-08-24 05:48:10 +0000366
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000367 dict = type->tp_dict;
368#define SET_DICT_FROM_INT(key, value) \
369 do { \
370 PyObject *v = PyLong_FromLong((long) value); \
371 if (v != NULL) { \
372 PyDict_SetItemString(dict, key, v); \
373 Py_DECREF(v); \
374 } \
375 } while (0)
376
377 SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
378 SET_DICT_FROM_INT(real_length_key, n_members);
379 SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000380}
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000381
382PyTypeObject*
383PyStructSequence_NewType(PyStructSequence_Desc *desc)
384{
385 PyTypeObject *result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
Stefan Krah6b962862012-08-19 11:20:41 +0200386 if (result != NULL) {
387 PyStructSequence_InitType(result, desc);
388 }
Martin v. Löwis4d0d4712010-12-03 20:14:31 +0000389 return result;
390}