1 /* 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
7 static const char visible_length_key[] = "n_sequence_fields";
8 static const char real_length_key[] = "n_fields";
9 static const char unnamed_fields_key[] = "n_unnamed_fields";
10
11 /* Fields with this name have only a field index, not a field name.
12 They are only allowed for indices < n_visible_fields. */
13 char *PyStructSequence_UnnamedField = "unnamed field";
14 _Py_IDENTIFIER(n_sequence_fields);
15 _Py_IDENTIFIER(n_fields);
16 _Py_IDENTIFIER(n_unnamed_fields);
17
18 #define VISIBLE_SIZE(op) Py_SIZE(op)
19 #define VISIBLE_SIZE_TP(tp) PyLong_AsSsize_t( \
20 _PyDict_GetItemId((tp)->tp_dict, &PyId_n_sequence_fields))
21
22 #define REAL_SIZE_TP(tp) PyLong_AsSsize_t( \
23 _PyDict_GetItemId((tp)->tp_dict, &PyId_n_fields))
24 #define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
25
26 #define UNNAMED_FIELDS_TP(tp) PyLong_AsSsize_t( \
27 _PyDict_GetItemId((tp)->tp_dict, &PyId_n_unnamed_fields))
28 #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
29
30
31 PyObject *
PyStructSequence_New(PyTypeObject * type)32 PyStructSequence_New(PyTypeObject *type)
33 {
34 PyStructSequence *obj;
35 Py_ssize_t size = REAL_SIZE_TP(type), i;
36
37 obj = PyObject_GC_NewVar(PyStructSequence, type, size);
38 if (obj == NULL)
39 return NULL;
40 /* Hack the size of the variable object, so invisible fields don't appear
41 to Python code. */
42 Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
43 for (i = 0; i < size; i++)
44 obj->ob_item[i] = NULL;
45
46 return (PyObject*)obj;
47 }
48
49 void
PyStructSequence_SetItem(PyObject * op,Py_ssize_t i,PyObject * v)50 PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
51 {
52 PyStructSequence_SET_ITEM(op, i, v);
53 }
54
55 PyObject*
PyStructSequence_GetItem(PyObject * op,Py_ssize_t i)56 PyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
57 {
58 return PyStructSequence_GET_ITEM(op, i);
59 }
60
61 static void
structseq_dealloc(PyStructSequence * obj)62 structseq_dealloc(PyStructSequence *obj)
63 {
64 Py_ssize_t i, size;
65
66 size = REAL_SIZE(obj);
67 for (i = 0; i < size; ++i) {
68 Py_XDECREF(obj->ob_item[i]);
69 }
70 PyObject_GC_Del(obj);
71 }
72
73 /*[clinic input]
74 class structseq "PyStructSequence *" "NULL"
75 [clinic start generated code]*/
76 /*[clinic end generated code: output=da39a3ee5e6b4b0d input=9d781c6922c77752]*/
77
78 #include "clinic/structseq.c.h"
79
80 /*[clinic input]
81 @classmethod
82 structseq.__new__ as structseq_new
83 sequence as arg: object
84 dict: object = NULL
85 [clinic start generated code]*/
86
87 static PyObject *
structseq_new_impl(PyTypeObject * type,PyObject * arg,PyObject * dict)88 structseq_new_impl(PyTypeObject *type, PyObject *arg, PyObject *dict)
89 /*[clinic end generated code: output=baa082e788b171da input=9b44810243907377]*/
90 {
91 PyObject *ob;
92 PyStructSequence *res = NULL;
93 Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
94
95 arg = PySequence_Fast(arg, "constructor requires a sequence");
96
97 if (!arg) {
98 return NULL;
99 }
100
101 if (dict && !PyDict_Check(dict)) {
102 PyErr_Format(PyExc_TypeError,
103 "%.500s() takes a dict as second arg, if any",
104 type->tp_name);
105 Py_DECREF(arg);
106 return NULL;
107 }
108
109 len = PySequence_Fast_GET_SIZE(arg);
110 min_len = VISIBLE_SIZE_TP(type);
111 max_len = REAL_SIZE_TP(type);
112 n_unnamed_fields = UNNAMED_FIELDS_TP(type);
113
114 if (min_len != max_len) {
115 if (len < min_len) {
116 PyErr_Format(PyExc_TypeError,
117 "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
118 type->tp_name, min_len, len);
119 Py_DECREF(arg);
120 return NULL;
121 }
122
123 if (len > max_len) {
124 PyErr_Format(PyExc_TypeError,
125 "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
126 type->tp_name, max_len, len);
127 Py_DECREF(arg);
128 return NULL;
129 }
130 }
131 else {
132 if (len != min_len) {
133 PyErr_Format(PyExc_TypeError,
134 "%.500s() takes a %zd-sequence (%zd-sequence given)",
135 type->tp_name, min_len, len);
136 Py_DECREF(arg);
137 return NULL;
138 }
139 }
140
141 res = (PyStructSequence*) PyStructSequence_New(type);
142 if (res == NULL) {
143 Py_DECREF(arg);
144 return NULL;
145 }
146 for (i = 0; i < len; ++i) {
147 PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
148 Py_INCREF(v);
149 res->ob_item[i] = v;
150 }
151 for (; i < max_len; ++i) {
152 if (dict && (ob = PyDict_GetItemString(
153 dict, type->tp_members[i-n_unnamed_fields].name))) {
154 }
155 else {
156 ob = Py_None;
157 }
158 Py_INCREF(ob);
159 res->ob_item[i] = ob;
160 }
161
162 Py_DECREF(arg);
163 return (PyObject*) res;
164 }
165
166
167 static PyObject *
structseq_repr(PyStructSequence * obj)168 structseq_repr(PyStructSequence *obj)
169 {
170 /* buffer and type size were chosen well considered. */
171 #define REPR_BUFFER_SIZE 512
172 #define TYPE_MAXSIZE 100
173
174 PyTypeObject *typ = Py_TYPE(obj);
175 Py_ssize_t i;
176 int removelast = 0;
177 Py_ssize_t len;
178 char buf[REPR_BUFFER_SIZE];
179 char *endofbuf, *pbuf = buf;
180
181 /* pointer to end of writeable buffer; safes space for "...)\0" */
182 endofbuf= &buf[REPR_BUFFER_SIZE-5];
183
184 /* "typename(", limited to TYPE_MAXSIZE */
185 len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
186 strlen(typ->tp_name);
187 strncpy(pbuf, typ->tp_name, len);
188 pbuf += len;
189 *pbuf++ = '(';
190
191 for (i=0; i < VISIBLE_SIZE(obj); i++) {
192 PyObject *val, *repr;
193 const char *cname, *crepr;
194
195 cname = typ->tp_members[i].name;
196 if (cname == NULL) {
197 PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL"
198 " for type %.500s", i, typ->tp_name);
199 return NULL;
200 }
201 val = PyStructSequence_GET_ITEM(obj, i);
202 repr = PyObject_Repr(val);
203 if (repr == NULL)
204 return NULL;
205 crepr = PyUnicode_AsUTF8(repr);
206 if (crepr == NULL) {
207 Py_DECREF(repr);
208 return NULL;
209 }
210
211 /* + 3: keep space for "=" and ", " */
212 len = strlen(cname) + strlen(crepr) + 3;
213 if ((pbuf+len) <= endofbuf) {
214 strcpy(pbuf, cname);
215 pbuf += strlen(cname);
216 *pbuf++ = '=';
217 strcpy(pbuf, crepr);
218 pbuf += strlen(crepr);
219 *pbuf++ = ',';
220 *pbuf++ = ' ';
221 removelast = 1;
222 Py_DECREF(repr);
223 }
224 else {
225 strcpy(pbuf, "...");
226 pbuf += 3;
227 removelast = 0;
228 Py_DECREF(repr);
229 break;
230 }
231 }
232 if (removelast) {
233 /* overwrite last ", " */
234 pbuf-=2;
235 }
236 *pbuf++ = ')';
237 *pbuf = '\0';
238
239 return PyUnicode_FromString(buf);
240 }
241
242 static PyObject *
structseq_reduce(PyStructSequence * self)243 structseq_reduce(PyStructSequence* self)
244 {
245 PyObject* tup = NULL;
246 PyObject* dict = NULL;
247 PyObject* result;
248 Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields, i;
249
250 n_fields = REAL_SIZE(self);
251 n_visible_fields = VISIBLE_SIZE(self);
252 n_unnamed_fields = UNNAMED_FIELDS(self);
253 tup = PyTuple_New(n_visible_fields);
254 if (!tup)
255 goto error;
256
257 dict = PyDict_New();
258 if (!dict)
259 goto error;
260
261 for (i = 0; i < n_visible_fields; i++) {
262 Py_INCREF(self->ob_item[i]);
263 PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
264 }
265
266 for (; i < n_fields; i++) {
267 const char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
268 if (PyDict_SetItemString(dict, n, self->ob_item[i]) < 0)
269 goto error;
270 }
271
272 result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
273
274 Py_DECREF(tup);
275 Py_DECREF(dict);
276
277 return result;
278
279 error:
280 Py_XDECREF(tup);
281 Py_XDECREF(dict);
282 return NULL;
283 }
284
285 static PyMethodDef structseq_methods[] = {
286 {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
287 {NULL, NULL}
288 };
289
290 static PyTypeObject _struct_sequence_template = {
291 PyVarObject_HEAD_INIT(&PyType_Type, 0)
292 NULL, /* tp_name */
293 sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
294 sizeof(PyObject *), /* tp_itemsize */
295 (destructor)structseq_dealloc, /* tp_dealloc */
296 0, /* tp_print */
297 0, /* tp_getattr */
298 0, /* tp_setattr */
299 0, /* tp_reserved */
300 (reprfunc)structseq_repr, /* tp_repr */
301 0, /* tp_as_number */
302 0, /* tp_as_sequence */
303 0, /* tp_as_mapping */
304 0, /* tp_hash */
305 0, /* tp_call */
306 0, /* tp_str */
307 0, /* tp_getattro */
308 0, /* tp_setattro */
309 0, /* tp_as_buffer */
310 Py_TPFLAGS_DEFAULT, /* tp_flags */
311 NULL, /* tp_doc */
312 0, /* tp_traverse */
313 0, /* tp_clear */
314 0, /* tp_richcompare */
315 0, /* tp_weaklistoffset */
316 0, /* tp_iter */
317 0, /* tp_iternext */
318 structseq_methods, /* tp_methods */
319 NULL, /* tp_members */
320 0, /* tp_getset */
321 0, /* tp_base */
322 0, /* tp_dict */
323 0, /* tp_descr_get */
324 0, /* tp_descr_set */
325 0, /* tp_dictoffset */
326 0, /* tp_init */
327 0, /* tp_alloc */
328 structseq_new, /* tp_new */
329 };
330
331 int
PyStructSequence_InitType2(PyTypeObject * type,PyStructSequence_Desc * desc)332 PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc)
333 {
334 PyObject *dict;
335 PyMemberDef* members;
336 Py_ssize_t n_members, n_unnamed_members, i, k;
337 PyObject *v;
338
339 #ifdef Py_TRACE_REFS
340 /* if the type object was chained, unchain it first
341 before overwriting its storage */
342 if (type->ob_base.ob_base._ob_next) {
343 _Py_ForgetReference((PyObject*)type);
344 }
345 #endif
346
347 n_unnamed_members = 0;
348 for (i = 0; desc->fields[i].name != NULL; ++i)
349 if (desc->fields[i].name == PyStructSequence_UnnamedField)
350 n_unnamed_members++;
351 n_members = i;
352
353 memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
354 type->tp_base = &PyTuple_Type;
355 type->tp_name = desc->name;
356 type->tp_doc = desc->doc;
357
358 members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
359 if (members == NULL) {
360 PyErr_NoMemory();
361 return -1;
362 }
363
364 for (i = k = 0; i < n_members; ++i) {
365 if (desc->fields[i].name == PyStructSequence_UnnamedField)
366 continue;
367 members[k].name = desc->fields[i].name;
368 members[k].type = T_OBJECT;
369 members[k].offset = offsetof(PyStructSequence, ob_item)
370 + i * sizeof(PyObject*);
371 members[k].flags = READONLY;
372 members[k].doc = desc->fields[i].doc;
373 k++;
374 }
375 members[k].name = NULL;
376
377 type->tp_members = members;
378
379 if (PyType_Ready(type) < 0)
380 return -1;
381 Py_INCREF(type);
382
383 dict = type->tp_dict;
384 #define SET_DICT_FROM_SIZE(key, value) \
385 do { \
386 v = PyLong_FromSsize_t(value); \
387 if (v == NULL) \
388 return -1; \
389 if (PyDict_SetItemString(dict, key, v) < 0) { \
390 Py_DECREF(v); \
391 return -1; \
392 } \
393 Py_DECREF(v); \
394 } while (0)
395
396 SET_DICT_FROM_SIZE(visible_length_key, desc->n_in_sequence);
397 SET_DICT_FROM_SIZE(real_length_key, n_members);
398 SET_DICT_FROM_SIZE(unnamed_fields_key, n_unnamed_members);
399
400 return 0;
401 }
402
403 void
PyStructSequence_InitType(PyTypeObject * type,PyStructSequence_Desc * desc)404 PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
405 {
406 (void)PyStructSequence_InitType2(type, desc);
407 }
408
409 PyTypeObject*
PyStructSequence_NewType(PyStructSequence_Desc * desc)410 PyStructSequence_NewType(PyStructSequence_Desc *desc)
411 {
412 PyTypeObject *result;
413
414 result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
415 if (result == NULL)
416 return NULL;
417 if (PyStructSequence_InitType2(result, desc) < 0) {
418 Py_DECREF(result);
419 return NULL;
420 }
421 return result;
422 }
423
_PyStructSequence_Init(void)424 int _PyStructSequence_Init(void)
425 {
426 if (_PyUnicode_FromId(&PyId_n_sequence_fields) == NULL
427 || _PyUnicode_FromId(&PyId_n_fields) == NULL
428 || _PyUnicode_FromId(&PyId_n_unnamed_fields) == NULL)
429 return -1;
430
431 return 0;
432 }
433