blob: 647586c4a4183266fa0e985f7c4d54710e02b35a [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 Petersonccabcd42010-07-07 20:54:01 +000038 for (i = 0; i < size; i++)
39 obj->ob_item[i] = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +000040
Benjamin Petersonccabcd42010-07-07 20:54:01 +000041 return (PyObject*)obj;
Thomas Woutersed03b412007-08-28 21:37:11 +000042}
43
44static PyObject *
Guido van Rossume82f75a2001-10-18 20:47:51 +000045structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
46{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000047 PyObject *arg = NULL;
48 PyObject *dict = NULL;
49 PyObject *ob;
50 PyStructSequence *res = NULL;
51 Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
52 static char *kwlist[] = {"sequence", "dict", 0};
Guido van Rossume82f75a2001-10-18 20:47:51 +000053
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000054 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
55 kwlist, &arg, &dict))
56 return NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +000057
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000058 arg = PySequence_Fast(arg, "constructor requires a sequence");
Michael W. Hudsonce358e32002-03-06 17:07:49 +000059
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000060 if (!arg) {
61 return NULL;
62 }
Guido van Rossume82f75a2001-10-18 20:47:51 +000063
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000064 if (dict && !PyDict_Check(dict)) {
65 PyErr_Format(PyExc_TypeError,
66 "%.500s() takes a dict as second arg, if any",
67 type->tp_name);
68 Py_DECREF(arg);
69 return NULL;
70 }
Guido van Rossume82f75a2001-10-18 20:47:51 +000071
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000072 len = PySequence_Fast_GET_SIZE(arg);
73 min_len = VISIBLE_SIZE_TP(type);
74 max_len = REAL_SIZE_TP(type);
75 n_unnamed_fields = UNNAMED_FIELDS_TP(type);
Michael W. Hudsonce358e32002-03-06 17:07:49 +000076
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000077 if (min_len != max_len) {
78 if (len < min_len) {
79 PyErr_Format(PyExc_TypeError,
80 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
81 type->tp_name, min_len, len);
82 Py_DECREF(arg);
83 return NULL;
84 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +000085
Antoine Pitrouf95a1b32010-05-09 15:52:27 +000086 if (len > max_len) {
87 PyErr_Format(PyExc_TypeError,
88 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
89 type->tp_name, max_len, len);
90 Py_DECREF(arg);
91 return NULL;
92 }
93 }
94 else {
95 if (len != min_len) {
96 PyErr_Format(PyExc_TypeError,
97 "%.500s() takes a %zd-sequence (%zd-sequence given)",
98 type->tp_name, min_len, len);
99 Py_DECREF(arg);
100 return NULL;
101 }
102 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000103
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000104 res = (PyStructSequence*) PyStructSequence_New(type);
105 if (res == NULL) {
106 return NULL;
107 }
108 for (i = 0; i < len; ++i) {
109 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
110 Py_INCREF(v);
111 res->ob_item[i] = v;
112 }
113 for (; i < max_len; ++i) {
114 if (dict && (ob = PyDict_GetItemString(
115 dict, type->tp_members[i-n_unnamed_fields].name))) {
116 }
117 else {
118 ob = Py_None;
119 }
120 Py_INCREF(ob);
121 res->ob_item[i] = ob;
122 }
123
124 Py_DECREF(arg);
125 return (PyObject*) res;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000126}
127
Guido van Rossume82f75a2001-10-18 20:47:51 +0000128
129static PyObject *
130structseq_repr(PyStructSequence *obj)
131{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000132 /* buffer and type size were chosen well considered. */
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000133#define REPR_BUFFER_SIZE 512
134#define TYPE_MAXSIZE 100
135
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000136 PyTypeObject *typ = Py_TYPE(obj);
137 int i, removelast = 0;
138 Py_ssize_t len;
139 char buf[REPR_BUFFER_SIZE];
140 char *endofbuf, *pbuf = buf;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000141
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000142 /* pointer to end of writeable buffer; safes space for "...)\0" */
143 endofbuf= &buf[REPR_BUFFER_SIZE-5];
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000144
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000145 /* "typename(", limited to TYPE_MAXSIZE */
146 len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
147 strlen(typ->tp_name);
148 strncpy(pbuf, typ->tp_name, len);
149 pbuf += len;
150 *pbuf++ = '(';
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000151
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000152 for (i=0; i < VISIBLE_SIZE(obj); i++) {
153 PyObject *val, *repr;
154 char *cname, *crepr;
Christian Heimesd32ed6f2008-01-14 18:49:24 +0000155
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000156 cname = typ->tp_members[i].name;
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000157 if (cname == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000158 return NULL;
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000159 val = PyStructSequence_GET_ITEM(obj, i);
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000160 repr = PyObject_Repr(val);
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000161 if (repr == NULL)
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000162 return NULL;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000163 crepr = _PyUnicode_AsString(repr);
164 if (crepr == NULL) {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000165 Py_DECREF(repr);
166 return NULL;
167 }
168
169 /* + 3: keep space for "=" and ", " */
170 len = strlen(cname) + strlen(crepr) + 3;
171 if ((pbuf+len) <= endofbuf) {
172 strcpy(pbuf, cname);
173 pbuf += strlen(cname);
174 *pbuf++ = '=';
175 strcpy(pbuf, crepr);
176 pbuf += strlen(crepr);
177 *pbuf++ = ',';
178 *pbuf++ = ' ';
179 removelast = 1;
180 Py_DECREF(repr);
181 }
182 else {
183 strcpy(pbuf, "...");
184 pbuf += 3;
185 removelast = 0;
186 Py_DECREF(repr);
187 break;
188 }
189 }
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000190 if (removelast) {
191 /* overwrite last ", " */
192 pbuf-=2;
193 }
194 *pbuf++ = ')';
195 *pbuf = '\0';
196
197 return PyUnicode_FromString(buf);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000198}
199
200static PyObject *
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000201structseq_reduce(PyStructSequence* self)
202{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000203 PyObject* tup;
204 PyObject* dict;
205 PyObject* result;
206 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
207 int i;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000208
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000209 n_fields = REAL_SIZE(self);
210 n_visible_fields = VISIBLE_SIZE(self);
211 n_unnamed_fields = UNNAMED_FIELDS(self);
212 tup = PyTuple_New(n_visible_fields);
213 if (!tup) {
214 return NULL;
215 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000216
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000217 dict = PyDict_New();
218 if (!dict) {
219 Py_DECREF(tup);
220 return NULL;
221 }
Michael W. Hudsonce358e32002-03-06 17:07:49 +0000222
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000223 for (i = 0; i < n_visible_fields; i++) {
224 Py_INCREF(self->ob_item[i]);
225 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
226 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000227
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000228 for (; i < n_fields; i++) {
229 char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
230 PyDict_SetItemString(dict, n,
231 self->ob_item[i]);
232 }
Michael W. Hudson70ffddf2002-03-07 15:13:40 +0000233
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000234 result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
235
236 Py_DECREF(tup);
237 Py_DECREF(dict);
238
239 return result;
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000240}
241
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000242static PyMethodDef structseq_methods[] = {
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000243 {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000244 {NULL, NULL}
Michael W. Hudson7bb466a2002-03-05 13:27:58 +0000245};
246
Guido van Rossume82f75a2001-10-18 20:47:51 +0000247static PyTypeObject _struct_sequence_template = {
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000248 PyVarObject_HEAD_INIT(&PyType_Type, 0)
249 NULL, /* tp_name */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000250 sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
251 sizeof(PyObject *), /* tp_itemsize */
252 0, /* tp_dealloc */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000253 0, /* tp_print */
254 0, /* tp_getattr */
255 0, /* tp_setattr */
256 0, /* tp_reserved */
257 (reprfunc)structseq_repr, /* tp_repr */
258 0, /* tp_as_number */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000259 0, /* tp_as_sequence */
260 0, /* tp_as_mapping */
261 0, /* tp_hash */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000262 0, /* tp_call */
263 0, /* tp_str */
264 0, /* tp_getattro */
265 0, /* tp_setattro */
266 0, /* tp_as_buffer */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000267 Py_TPFLAGS_DEFAULT, /* tp_flags */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000268 NULL, /* tp_doc */
269 0, /* tp_traverse */
270 0, /* tp_clear */
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000271 0, /* tp_richcompare */
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000272 0, /* tp_weaklistoffset */
273 0, /* tp_iter */
274 0, /* tp_iternext */
275 structseq_methods, /* tp_methods */
276 NULL, /* tp_members */
277 0, /* tp_getset */
278 0, /* tp_base */
279 0, /* tp_dict */
280 0, /* tp_descr_get */
281 0, /* tp_descr_set */
282 0, /* tp_dictoffset */
283 0, /* tp_init */
284 0, /* tp_alloc */
285 structseq_new, /* tp_new */
Guido van Rossume82f75a2001-10-18 20:47:51 +0000286};
287
288void
289PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
290{
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000291 PyObject *dict;
292 PyMemberDef* members;
293 int n_members, n_unnamed_members, i, k;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000294
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000295#ifdef Py_TRACE_REFS
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000296 /* if the type object was chained, unchain it first
297 before overwriting its storage */
298 if (type->ob_base.ob_base._ob_next) {
299 _Py_ForgetReference((PyObject*)type);
300 }
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000301#endif
302
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000303 n_unnamed_members = 0;
304 for (i = 0; desc->fields[i].name != NULL; ++i)
305 if (desc->fields[i].name == PyStructSequence_UnnamedField)
306 n_unnamed_members++;
307 n_members = i;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000308
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000309 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
Benjamin Petersonccabcd42010-07-07 20:54:01 +0000310 type->tp_base = &PyTuple_Type;
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000311 type->tp_name = desc->name;
312 type->tp_doc = desc->doc;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000313
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000314 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
315 if (members == NULL)
316 return;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000317
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000318 for (i = k = 0; i < n_members; ++i) {
319 if (desc->fields[i].name == PyStructSequence_UnnamedField)
320 continue;
321 members[k].name = desc->fields[i].name;
322 members[k].type = T_OBJECT;
323 members[k].offset = offsetof(PyStructSequence, ob_item)
324 + i * sizeof(PyObject*);
325 members[k].flags = READONLY;
326 members[k].doc = desc->fields[i].doc;
327 k++;
328 }
329 members[k].name = NULL;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000330
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000331 type->tp_members = members;
Guido van Rossume82f75a2001-10-18 20:47:51 +0000332
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000333 if (PyType_Ready(type) < 0)
334 return;
335 Py_INCREF(type);
Neal Norwitz2f99b242008-08-24 05:48:10 +0000336
Antoine Pitrouf95a1b32010-05-09 15:52:27 +0000337 dict = type->tp_dict;
338#define SET_DICT_FROM_INT(key, value) \
339 do { \
340 PyObject *v = PyLong_FromLong((long) value); \
341 if (v != NULL) { \
342 PyDict_SetItemString(dict, key, v); \
343 Py_DECREF(v); \
344 } \
345 } while (0)
346
347 SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
348 SET_DICT_FROM_INT(real_length_key, n_members);
349 SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
Guido van Rossume82f75a2001-10-18 20:47:51 +0000350}