blob: 52ff301ff6dd5e4ae86be58f1c51c3b63d9f1e61 [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
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000012/* Fields with this name have only a field index, not a field name.
Martin v. Löwisf607bda2002-10-16 18:27:39 +000013 They are only allowed for indices < n_visible_fields. */
14char *PyStructSequence_UnnamedField = "unnamed field";
15
Christian Heimes90aa7642007-12-19 02:45:37 +000016#define VISIBLE_SIZE(op) Py_SIZE(op)
Christian Heimes217cfd12007-12-02 14:31:20 +000017#define VISIBLE_SIZE_TP(tp) PyLong_AsLong( \
Guido van Rossume82f75a2001-10-18 20:47:51 +000018 PyDict_GetItemString((tp)->tp_dict, visible_length_key))
19
Christian Heimes217cfd12007-12-02 14:31:20 +000020#define REAL_SIZE_TP(tp) PyLong_AsLong( \
Guido van Rossume82f75a2001-10-18 20:47:51 +000021 PyDict_GetItemString((tp)->tp_dict, real_length_key))
Christian Heimes90aa7642007-12-19 02:45:37 +000022#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
Guido van Rossume82f75a2001-10-18 20:47:51 +000023
Christian Heimes217cfd12007-12-02 14:31:20 +000024#define UNNAMED_FIELDS_TP(tp) PyLong_AsLong( \
Martin v. Löwisceaa77c2002-10-16 19:10:03 +000025 PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))
Christian Heimes90aa7642007-12-19 02:45:37 +000026#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
Martin v. Löwisceaa77c2002-10-16 19:10:03 +000027
Guido van Rossume82f75a2001-10-18 20:47:51 +000028
29PyObject *
30PyStructSequence_New(PyTypeObject *type)
31{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000032 PyStructSequence *obj;
Benjamin Petersonccabcd42010-07-07 20:54:01 +000033 Py_ssize_t size = REAL_SIZE_TP(type), i;
Christian Heimesd32ed6f2008-01-14 18:49:24 +000034
Benjamin Petersonccabcd42010-07-07 20:54:01 +000035 obj = PyObject_GC_NewVar(PyStructSequence, type, size);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000036 if (obj == NULL)
37 return NULL;
Benjamin Petersond02441e2010-07-08 22:33:03 +000038 /* Hack the size of the variable object, so invisible fields don't appear
39 to Python code. */
40 Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
Benjamin Petersonccabcd42010-07-07 20:54:01 +000041 for (i = 0; i < size; i++)
42 obj->ob_item[i] = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +000043
Benjamin Petersonccabcd42010-07-07 20:54:01 +000044 return (PyObject*)obj;
Thomas Woutersed03b412007-08-28 21:37:11 +000045}
46
Benjamin Petersond02441e2010-07-08 22:33:03 +000047static void
48structseq_dealloc(PyStructSequence *obj)
49{
50 Py_ssize_t i, size;
51
52 size = REAL_SIZE(obj);
53 for (i = 0; i < size; ++i) {
54 Py_XDECREF(obj->ob_item[i]);
55 }
56 PyObject_GC_Del(obj);
57}
58
Thomas Woutersed03b412007-08-28 21:37:11 +000059static PyObject *
Guido van Rossume82f75a2001-10-18 20:47:51 +000060structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
61{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000062 PyObject *arg = NULL;
63 PyObject *dict = NULL;
64 PyObject *ob;
65 PyStructSequence *res = NULL;
66 Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
67 static char *kwlist[] = {"sequence", "dict", 0};
Guido van Rossume82f75a2001-10-18 20:47:51 +000068
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000069 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
70 kwlist, &arg, &dict))
71 return NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +000072
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000073 arg = PySequence_Fast(arg, "constructor requires a sequence");
Michael W. Hudsonce358e32002-03-06 17:07:49 +000074
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000075 if (!arg) {
76 return NULL;
77 }
Guido van Rossume82f75a2001-10-18 20:47:51 +000078
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000079 if (dict && !PyDict_Check(dict)) {
80 PyErr_Format(PyExc_TypeError,
81 "%.500s() takes a dict as second arg, if any",
82 type->tp_name);
83 Py_DECREF(arg);
84 return NULL;
85 }
Guido van Rossume82f75a2001-10-18 20:47:51 +000086
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000087 len = PySequence_Fast_GET_SIZE(arg);
88 min_len = VISIBLE_SIZE_TP(type);
89 max_len = REAL_SIZE_TP(type);
90 n_unnamed_fields = UNNAMED_FIELDS_TP(type);
Michael W. Hudsonce358e32002-03-06 17:07:49 +000091
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000092 if (min_len != max_len) {
93 if (len < min_len) {
94 PyErr_Format(PyExc_TypeError,
95 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
96 type->tp_name, min_len, len);
97 Py_DECREF(arg);
98 return NULL;
99 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000100
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000101 if (len > max_len) {
102 PyErr_Format(PyExc_TypeError,
103 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
104 type->tp_name, max_len, len);
105 Py_DECREF(arg);
106 return NULL;
107 }
108 }
109 else {
110 if (len != min_len) {
111 PyErr_Format(PyExc_TypeError,
112 "%.500s() takes a %zd-sequence (%zd-sequence given)",
113 type->tp_name, min_len, len);
114 Py_DECREF(arg);
115 return NULL;
116 }
117 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000118
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000119 res = (PyStructSequence*) PyStructSequence_New(type);
120 if (res == NULL) {
121 return NULL;
122 }
123 for (i = 0; i < len; ++i) {
124 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
125 Py_INCREF(v);
126 res->ob_item[i] = v;
127 }
128 for (; i < max_len; ++i) {
129 if (dict && (ob = PyDict_GetItemString(
130 dict, type->tp_members[i-n_unnamed_fields].name))) {
131 }
132 else {
133 ob = Py_None;
134 }
135 Py_INCREF(ob);
136 res->ob_item[i] = ob;
137 }
138
139 Py_DECREF(arg);
140 return (PyObject*) res;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000141}
142
Guido van Rossume82f75a2001-10-18 20:47:51 +0000143
144static PyObject *
145structseq_repr(PyStructSequence *obj)
146{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000147 /* buffer and type size were chosen well considered. */
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000148#define REPR_BUFFER_SIZE 512
149#define TYPE_MAXSIZE 100
150
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000151 PyTypeObject *typ = Py_TYPE(obj);
152 int i, removelast = 0;
153 Py_ssize_t len;
154 char buf[REPR_BUFFER_SIZE];
155 char *endofbuf, *pbuf = buf;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000156
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000157 /* pointer to end of writeable buffer; safes space for "...)\0" */
158 endofbuf= &buf[REPR_BUFFER_SIZE-5];
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000159
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000160 /* "typename(", limited to TYPE_MAXSIZE */
161 len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
162 strlen(typ->tp_name);
163 strncpy(pbuf, typ->tp_name, len);
164 pbuf += len;
165 *pbuf++ = '(';
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000166
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000167 for (i=0; i < VISIBLE_SIZE(obj); i++) {
168 PyObject *val, *repr;
169 char *cname, *crepr;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000170
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000171 cname = typ->tp_members[i].name;
Benjamin Petersond02441e2010-07-08 22:33:03 +0000172 if (cname == NULL) {
173 PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL"
174 " for type %.500s", i, typ->tp_name);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000175 return NULL;
Benjamin Petersond02441e2010-07-08 22:33:03 +0000176 }
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000177 val = PyStructSequence_GET_ITEM(obj, i);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000178 repr = PyObject_Repr(val);
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000179 if (repr == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000180 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000181 crepr = _PyUnicode_AsString(repr);
182 if (crepr == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000183 Py_DECREF(repr);
184 return NULL;
185 }
186
187 /* + 3: keep space for "=" and ", " */
188 len = strlen(cname) + strlen(crepr) + 3;
189 if ((pbuf+len) <= endofbuf) {
190 strcpy(pbuf, cname);
191 pbuf += strlen(cname);
192 *pbuf++ = '=';
193 strcpy(pbuf, crepr);
194 pbuf += strlen(crepr);
195 *pbuf++ = ',';
196 *pbuf++ = ' ';
197 removelast = 1;
198 Py_DECREF(repr);
199 }
200 else {
201 strcpy(pbuf, "...");
202 pbuf += 3;
203 removelast = 0;
204 Py_DECREF(repr);
205 break;
206 }
207 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000208 if (removelast) {
209 /* overwrite last ", " */
210 pbuf-=2;
211 }
212 *pbuf++ = ')';
213 *pbuf = '\0';
214
215 return PyUnicode_FromString(buf);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000216}
217
218static PyObject *
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000219structseq_reduce(PyStructSequence* self)
220{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000221 PyObject* tup;
222 PyObject* dict;
223 PyObject* result;
224 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
225 int i;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000226
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000227 n_fields = REAL_SIZE(self);
228 n_visible_fields = VISIBLE_SIZE(self);
229 n_unnamed_fields = UNNAMED_FIELDS(self);
230 tup = PyTuple_New(n_visible_fields);
231 if (!tup) {
232 return NULL;
233 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000234
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000235 dict = PyDict_New();
236 if (!dict) {
237 Py_DECREF(tup);
238 return NULL;
239 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000240
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000241 for (i = 0; i < n_visible_fields; i++) {
242 Py_INCREF(self->ob_item[i]);
243 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
244 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000245
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000246 for (; i < n_fields; i++) {
247 char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
248 PyDict_SetItemString(dict, n,
249 self->ob_item[i]);
250 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000251
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000252 result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
253
254 Py_DECREF(tup);
255 Py_DECREF(dict);
256
257 return result;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000258}
259
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000260static PyMethodDef structseq_methods[] = {
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000261 {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 {NULL, NULL}
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000263};
264
Guido van Rossume82f75a2001-10-18 20:47:51 +0000265static PyTypeObject _struct_sequence_template = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000266 PyVarObject_HEAD_INIT(&PyType_Type, 0)
267 NULL, /* tp_name */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000268 sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
269 sizeof(PyObject *), /* tp_itemsize */
Benjamin Petersond02441e2010-07-08 22:33:03 +0000270 (destructor)structseq_dealloc, /* tp_dealloc */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000271 0, /* tp_print */
272 0, /* tp_getattr */
273 0, /* tp_setattr */
274 0, /* tp_reserved */
275 (reprfunc)structseq_repr, /* tp_repr */
276 0, /* tp_as_number */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000277 0, /* tp_as_sequence */
278 0, /* tp_as_mapping */
279 0, /* tp_hash */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000280 0, /* tp_call */
281 0, /* tp_str */
282 0, /* tp_getattro */
283 0, /* tp_setattro */
284 0, /* tp_as_buffer */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000285 Py_TPFLAGS_DEFAULT, /* tp_flags */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000286 NULL, /* tp_doc */
287 0, /* tp_traverse */
288 0, /* tp_clear */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000289 0, /* tp_richcompare */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000290 0, /* tp_weaklistoffset */
291 0, /* tp_iter */
292 0, /* tp_iternext */
293 structseq_methods, /* tp_methods */
294 NULL, /* tp_members */
295 0, /* tp_getset */
296 0, /* tp_base */
297 0, /* tp_dict */
298 0, /* tp_descr_get */
299 0, /* tp_descr_set */
300 0, /* tp_dictoffset */
301 0, /* tp_init */
302 0, /* tp_alloc */
303 structseq_new, /* tp_new */
Guido van Rossume82f75a2001-10-18 20:47:51 +0000304};
305
306void
307PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
308{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 PyObject *dict;
310 PyMemberDef* members;
311 int n_members, n_unnamed_members, i, k;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000312
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000313#ifdef Py_TRACE_REFS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000314 /* if the type object was chained, unchain it first
315 before overwriting its storage */
316 if (type->ob_base.ob_base._ob_next) {
317 _Py_ForgetReference((PyObject*)type);
318 }
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000319#endif
320
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000321 n_unnamed_members = 0;
322 for (i = 0; desc->fields[i].name != NULL; ++i)
323 if (desc->fields[i].name == PyStructSequence_UnnamedField)
324 n_unnamed_members++;
325 n_members = i;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000326
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000327 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000328 type->tp_base = &PyTuple_Type;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000329 type->tp_name = desc->name;
330 type->tp_doc = desc->doc;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000331
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000332 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
333 if (members == NULL)
334 return;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000335
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000336 for (i = k = 0; i < n_members; ++i) {
337 if (desc->fields[i].name == PyStructSequence_UnnamedField)
338 continue;
339 members[k].name = desc->fields[i].name;
340 members[k].type = T_OBJECT;
341 members[k].offset = offsetof(PyStructSequence, ob_item)
342 + i * sizeof(PyObject*);
343 members[k].flags = READONLY;
344 members[k].doc = desc->fields[i].doc;
345 k++;
346 }
347 members[k].name = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000348
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000349 type->tp_members = members;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000350
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000351 if (PyType_Ready(type) < 0)
352 return;
353 Py_INCREF(type);
Neal Norwitz2f99b242008-08-24 05:48:10 +0000354
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000355 dict = type->tp_dict;
356#define SET_DICT_FROM_INT(key, value) \
357 do { \
358 PyObject *v = PyLong_FromLong((long) value); \
359 if (v != NULL) { \
360 PyDict_SetItemString(dict, key, v); \
361 Py_DECREF(v); \
362 } \
363 } while (0)
364
365 SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
366 SET_DICT_FROM_INT(real_length_key, n_members);
367 SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000368}