Line data Source code
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 char visible_length_key[] = "n_sequence_fields";
8 : static char real_length_key[] = "n_fields";
9 : static 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 :
15 : #define VISIBLE_SIZE(op) Py_SIZE(op)
16 : #define VISIBLE_SIZE_TP(tp) PyLong_AsLong( \
17 : PyDict_GetItemString((tp)->tp_dict, visible_length_key))
18 :
19 : #define REAL_SIZE_TP(tp) PyLong_AsLong( \
20 : PyDict_GetItemString((tp)->tp_dict, real_length_key))
21 : #define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
22 :
23 : #define UNNAMED_FIELDS_TP(tp) PyLong_AsLong( \
24 : PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))
25 : #define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
26 :
27 :
28 : PyObject *
29 330 : PyStructSequence_New(PyTypeObject *type)
30 : {
31 : PyStructSequence *obj;
32 330 : Py_ssize_t size = REAL_SIZE_TP(type), i;
33 :
34 330 : obj = PyObject_GC_NewVar(PyStructSequence, type, size);
35 330 : if (obj == NULL)
36 0 : return NULL;
37 : /* Hack the size of the variable object, so invisible fields don't appear
38 : to Python code. */
39 330 : Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
40 6524 : for (i = 0; i < size; i++)
41 6194 : obj->ob_item[i] = NULL;
42 :
43 330 : return (PyObject*)obj;
44 : }
45 :
46 : void
47 0 : PyStructSequence_SetItem(PyObject* op, Py_ssize_t i, PyObject* v)
48 : {
49 0 : PyStructSequence_SET_ITEM(op, i, v);
50 0 : }
51 :
52 : PyObject*
53 0 : PyStructSequence_GetItem(PyObject* op, Py_ssize_t i)
54 : {
55 0 : return PyStructSequence_GET_ITEM(op, i);
56 : }
57 :
58 : static void
59 324 : structseq_dealloc(PyStructSequence *obj)
60 : {
61 : Py_ssize_t i, size;
62 :
63 324 : size = REAL_SIZE(obj);
64 6480 : for (i = 0; i < size; ++i) {
65 6156 : Py_XDECREF(obj->ob_item[i]);
66 : }
67 324 : PyObject_GC_Del(obj);
68 324 : }
69 :
70 : static PyObject *
71 0 : structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
72 : {
73 0 : PyObject *arg = NULL;
74 0 : PyObject *dict = NULL;
75 : PyObject *ob;
76 0 : PyStructSequence *res = NULL;
77 : Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
78 : static char *kwlist[] = {"sequence", "dict", 0};
79 :
80 0 : if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq",
81 : kwlist, &arg, &dict))
82 0 : return NULL;
83 :
84 0 : arg = PySequence_Fast(arg, "constructor requires a sequence");
85 :
86 0 : if (!arg) {
87 0 : return NULL;
88 : }
89 :
90 0 : if (dict && !PyDict_Check(dict)) {
91 0 : PyErr_Format(PyExc_TypeError,
92 : "%.500s() takes a dict as second arg, if any",
93 : type->tp_name);
94 0 : Py_DECREF(arg);
95 0 : return NULL;
96 : }
97 :
98 0 : len = PySequence_Fast_GET_SIZE(arg);
99 0 : min_len = VISIBLE_SIZE_TP(type);
100 0 : max_len = REAL_SIZE_TP(type);
101 0 : n_unnamed_fields = UNNAMED_FIELDS_TP(type);
102 :
103 0 : if (min_len != max_len) {
104 0 : if (len < min_len) {
105 0 : PyErr_Format(PyExc_TypeError,
106 : "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
107 : type->tp_name, min_len, len);
108 0 : Py_DECREF(arg);
109 0 : return NULL;
110 : }
111 :
112 0 : if (len > max_len) {
113 0 : PyErr_Format(PyExc_TypeError,
114 : "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
115 : type->tp_name, max_len, len);
116 0 : Py_DECREF(arg);
117 0 : return NULL;
118 : }
119 : }
120 : else {
121 0 : if (len != min_len) {
122 0 : PyErr_Format(PyExc_TypeError,
123 : "%.500s() takes a %zd-sequence (%zd-sequence given)",
124 : type->tp_name, min_len, len);
125 0 : Py_DECREF(arg);
126 0 : return NULL;
127 : }
128 : }
129 :
130 0 : res = (PyStructSequence*) PyStructSequence_New(type);
131 0 : if (res == NULL) {
132 0 : Py_DECREF(arg);
133 0 : return NULL;
134 : }
135 0 : for (i = 0; i < len; ++i) {
136 0 : PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
137 0 : Py_INCREF(v);
138 0 : res->ob_item[i] = v;
139 : }
140 0 : for (; i < max_len; ++i) {
141 0 : if (dict && (ob = PyDict_GetItemString(
142 0 : dict, type->tp_members[i-n_unnamed_fields].name))) {
143 : }
144 : else {
145 0 : ob = Py_None;
146 : }
147 0 : Py_INCREF(ob);
148 0 : res->ob_item[i] = ob;
149 : }
150 :
151 0 : Py_DECREF(arg);
152 0 : return (PyObject*) res;
153 : }
154 :
155 :
156 : static PyObject *
157 0 : structseq_repr(PyStructSequence *obj)
158 : {
159 : /* buffer and type size were chosen well considered. */
160 : #define REPR_BUFFER_SIZE 512
161 : #define TYPE_MAXSIZE 100
162 :
163 0 : PyTypeObject *typ = Py_TYPE(obj);
164 0 : int i, removelast = 0;
165 : Py_ssize_t len;
166 : char buf[REPR_BUFFER_SIZE];
167 0 : char *endofbuf, *pbuf = buf;
168 :
169 : /* pointer to end of writeable buffer; safes space for "...)\0" */
170 0 : endofbuf= &buf[REPR_BUFFER_SIZE-5];
171 :
172 : /* "typename(", limited to TYPE_MAXSIZE */
173 0 : len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
174 0 : strlen(typ->tp_name);
175 0 : strncpy(pbuf, typ->tp_name, len);
176 0 : pbuf += len;
177 0 : *pbuf++ = '(';
178 :
179 0 : for (i=0; i < VISIBLE_SIZE(obj); i++) {
180 : PyObject *val, *repr;
181 : char *cname, *crepr;
182 :
183 0 : cname = typ->tp_members[i].name;
184 0 : if (cname == NULL) {
185 0 : PyErr_Format(PyExc_SystemError, "In structseq_repr(), member %d name is NULL"
186 : " for type %.500s", i, typ->tp_name);
187 0 : return NULL;
188 : }
189 0 : val = PyStructSequence_GET_ITEM(obj, i);
190 0 : repr = PyObject_Repr(val);
191 0 : if (repr == NULL)
192 0 : return NULL;
193 0 : crepr = _PyUnicode_AsString(repr);
194 0 : if (crepr == NULL) {
195 0 : Py_DECREF(repr);
196 0 : return NULL;
197 : }
198 :
199 : /* + 3: keep space for "=" and ", " */
200 0 : len = strlen(cname) + strlen(crepr) + 3;
201 0 : if ((pbuf+len) <= endofbuf) {
202 0 : strcpy(pbuf, cname);
203 0 : pbuf += strlen(cname);
204 0 : *pbuf++ = '=';
205 0 : strcpy(pbuf, crepr);
206 0 : pbuf += strlen(crepr);
207 0 : *pbuf++ = ',';
208 0 : *pbuf++ = ' ';
209 0 : removelast = 1;
210 0 : Py_DECREF(repr);
211 : }
212 : else {
213 0 : strcpy(pbuf, "...");
214 0 : pbuf += 3;
215 0 : removelast = 0;
216 0 : Py_DECREF(repr);
217 0 : break;
218 : }
219 : }
220 0 : if (removelast) {
221 : /* overwrite last ", " */
222 0 : pbuf-=2;
223 : }
224 0 : *pbuf++ = ')';
225 0 : *pbuf = '\0';
226 :
227 0 : return PyUnicode_FromString(buf);
228 : }
229 :
230 : static PyObject *
231 0 : structseq_reduce(PyStructSequence* self)
232 : {
233 : PyObject* tup;
234 : PyObject* dict;
235 : PyObject* result;
236 : Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
237 : int i;
238 :
239 0 : n_fields = REAL_SIZE(self);
240 0 : n_visible_fields = VISIBLE_SIZE(self);
241 0 : n_unnamed_fields = UNNAMED_FIELDS(self);
242 0 : tup = PyTuple_New(n_visible_fields);
243 0 : if (!tup) {
244 0 : return NULL;
245 : }
246 :
247 0 : dict = PyDict_New();
248 0 : if (!dict) {
249 0 : Py_DECREF(tup);
250 0 : return NULL;
251 : }
252 :
253 0 : for (i = 0; i < n_visible_fields; i++) {
254 0 : Py_INCREF(self->ob_item[i]);
255 0 : PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
256 : }
257 :
258 0 : for (; i < n_fields; i++) {
259 0 : char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
260 0 : PyDict_SetItemString(dict, n,
261 : self->ob_item[i]);
262 : }
263 :
264 0 : result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
265 :
266 0 : Py_DECREF(tup);
267 0 : Py_DECREF(dict);
268 :
269 0 : return result;
270 : }
271 :
272 : static PyMethodDef structseq_methods[] = {
273 : {"__reduce__", (PyCFunction)structseq_reduce, METH_NOARGS, NULL},
274 : {NULL, NULL}
275 : };
276 :
277 : static PyTypeObject _struct_sequence_template = {
278 : PyVarObject_HEAD_INIT(&PyType_Type, 0)
279 : NULL, /* tp_name */
280 : sizeof(PyStructSequence) - sizeof(PyObject *), /* tp_basicsize */
281 : sizeof(PyObject *), /* tp_itemsize */
282 : (destructor)structseq_dealloc, /* tp_dealloc */
283 : 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 */
289 : 0, /* tp_as_sequence */
290 : 0, /* tp_as_mapping */
291 : 0, /* tp_hash */
292 : 0, /* tp_call */
293 : 0, /* tp_str */
294 : 0, /* tp_getattro */
295 : 0, /* tp_setattro */
296 : 0, /* tp_as_buffer */
297 : Py_TPFLAGS_DEFAULT, /* tp_flags */
298 : NULL, /* tp_doc */
299 : 0, /* tp_traverse */
300 : 0, /* tp_clear */
301 : 0, /* tp_richcompare */
302 : 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 */
316 : };
317 :
318 : void
319 14 : PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
320 : {
321 : PyObject *dict;
322 : PyMemberDef* members;
323 : int n_members, n_unnamed_members, i, k;
324 :
325 : #ifdef Py_TRACE_REFS
326 : /* 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 : }
331 : #endif
332 :
333 14 : n_unnamed_members = 0;
334 106 : for (i = 0; desc->fields[i].name != NULL; ++i)
335 92 : if (desc->fields[i].name == PyStructSequence_UnnamedField)
336 3 : n_unnamed_members++;
337 14 : n_members = i;
338 :
339 14 : memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
340 14 : type->tp_base = &PyTuple_Type;
341 14 : type->tp_name = desc->name;
342 14 : type->tp_doc = desc->doc;
343 :
344 14 : members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
345 14 : if (members == NULL)
346 0 : return;
347 :
348 106 : for (i = k = 0; i < n_members; ++i) {
349 92 : if (desc->fields[i].name == PyStructSequence_UnnamedField)
350 3 : continue;
351 89 : members[k].name = desc->fields[i].name;
352 89 : members[k].type = T_OBJECT;
353 178 : members[k].offset = offsetof(PyStructSequence, ob_item)
354 89 : + i * sizeof(PyObject*);
355 89 : members[k].flags = READONLY;
356 89 : members[k].doc = desc->fields[i].doc;
357 89 : k++;
358 : }
359 14 : members[k].name = NULL;
360 :
361 14 : type->tp_members = members;
362 :
363 14 : if (PyType_Ready(type) < 0)
364 0 : return;
365 14 : Py_INCREF(type);
366 :
367 14 : 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 14 : SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
378 14 : SET_DICT_FROM_INT(real_length_key, n_members);
379 14 : SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
380 : }
381 :
382 : PyTypeObject*
383 0 : PyStructSequence_NewType(PyStructSequence_Desc *desc)
384 : {
385 0 : PyTypeObject *result = (PyTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
386 0 : if (result != NULL) {
387 0 : PyStructSequence_InitType(result, desc);
388 : }
389 0 : return result;
390 : }
|