PageRenderTime 45ms CodeModel.GetById 2ms app.highlight 37ms RepoModel.GetById 1ms app.codeStats 0ms

/Objects/structseq.c

http://unladen-swallow.googlecode.com/
C | 539 lines | 460 code | 68 blank | 11 comment | 78 complexity | 87a37fbb71cd4f4dbe8993efa84c8f91 MD5 | raw file
  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#include "structseq.h"
  7
  8static char visible_length_key[] = "n_sequence_fields";
  9static char real_length_key[] = "n_fields";
 10static char unnamed_fields_key[] = "n_unnamed_fields";
 11
 12/* Fields with this name have only a field index, not a field name. 
 13   They are only allowed for indices < n_visible_fields. */
 14char *PyStructSequence_UnnamedField = "unnamed field";
 15
 16#define VISIBLE_SIZE(op) Py_SIZE(op)
 17#define VISIBLE_SIZE_TP(tp) PyInt_AsLong( \
 18                      PyDict_GetItemString((tp)->tp_dict, visible_length_key))
 19
 20#define REAL_SIZE_TP(tp) PyInt_AsLong( \
 21                      PyDict_GetItemString((tp)->tp_dict, real_length_key))
 22#define REAL_SIZE(op) REAL_SIZE_TP(Py_TYPE(op))
 23
 24#define UNNAMED_FIELDS_TP(tp) PyInt_AsLong( \
 25                      PyDict_GetItemString((tp)->tp_dict, unnamed_fields_key))
 26#define UNNAMED_FIELDS(op) UNNAMED_FIELDS_TP(Py_TYPE(op))
 27
 28
 29PyObject *
 30PyStructSequence_New(PyTypeObject *type)
 31{
 32	PyStructSequence *obj;
 33
 34	obj = PyObject_New(PyStructSequence, type);
 35	if (obj == NULL)
 36		return NULL;
 37	Py_SIZE(obj) = VISIBLE_SIZE_TP(type);
 38
 39	return (PyObject*) obj;
 40}
 41
 42static void
 43structseq_dealloc(PyStructSequence *obj)
 44{
 45	Py_ssize_t i, size;
 46
 47	size = REAL_SIZE(obj);
 48	for (i = 0; i < size; ++i) {
 49		Py_XDECREF(obj->ob_item[i]);
 50	}
 51	PyObject_Del(obj);
 52}
 53
 54static Py_ssize_t
 55structseq_length(PyStructSequence *obj)
 56{
 57	return VISIBLE_SIZE(obj);
 58}
 59
 60static PyObject*
 61structseq_item(PyStructSequence *obj, Py_ssize_t i)
 62{
 63	if (i < 0 || i >= VISIBLE_SIZE(obj)) {
 64		PyErr_SetString(PyExc_IndexError, "tuple index out of range");
 65		return NULL;
 66	}
 67	Py_INCREF(obj->ob_item[i]);
 68	return obj->ob_item[i];
 69}
 70
 71static PyObject*
 72structseq_slice(PyStructSequence *obj, Py_ssize_t low, Py_ssize_t high)
 73{
 74	PyTupleObject *np;
 75	Py_ssize_t i;
 76
 77	if (low < 0)
 78		low = 0;
 79	if (high > VISIBLE_SIZE(obj))
 80		high = VISIBLE_SIZE(obj);
 81	if (high < low)
 82		high = low;
 83	np = (PyTupleObject *)PyTuple_New(high-low);
 84	if (np == NULL)
 85		return NULL;
 86	for(i = low; i < high; ++i) {
 87		PyObject *v = obj->ob_item[i];
 88		Py_INCREF(v);
 89		PyTuple_SET_ITEM(np, i-low, v);
 90	}
 91	return (PyObject *) np;
 92}
 93
 94static PyObject *
 95structseq_subscript(PyStructSequence *self, PyObject *item)
 96{
 97	if (PyIndex_Check(item)) {
 98		Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
 99		if (i == -1 && PyErr_Occurred())
100			return NULL;
101
102		if (i < 0)
103			i += VISIBLE_SIZE(self);
104
105		if (i < 0 || i >= VISIBLE_SIZE(self)) {
106			PyErr_SetString(PyExc_IndexError,
107				"tuple index out of range");
108			return NULL;
109		}
110		Py_INCREF(self->ob_item[i]);
111		return self->ob_item[i];
112	}
113	else if (PySlice_Check(item)) {
114		Py_ssize_t start, stop, step, slicelen, cur, i;
115		PyObject *result;
116		
117		if (PySlice_GetIndicesEx((PySliceObject *)item,
118					 VISIBLE_SIZE(self), &start, &stop,
119					 &step, &slicelen) < 0) {
120			return NULL;
121		}
122		if (slicelen <= 0)
123			return PyTuple_New(0);
124		result = PyTuple_New(slicelen);
125		if (result == NULL)
126			return NULL;
127		for (cur = start, i = 0; i < slicelen;
128		     cur += step, i++) {
129			PyObject *v = self->ob_item[cur];
130			Py_INCREF(v);
131			PyTuple_SET_ITEM(result, i, v);
132		}
133		return result;
134	}
135	else {
136		PyErr_SetString(PyExc_TypeError,
137				"structseq index must be integer");
138		return NULL;
139	}
140}
141
142static PyObject *
143structseq_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
144{
145	PyObject *arg = NULL;
146	PyObject *dict = NULL;
147	PyObject *ob;
148	PyStructSequence *res = NULL;
149	Py_ssize_t len, min_len, max_len, i, n_unnamed_fields;
150	static char *kwlist[] = {"sequence", "dict", 0};
151
152	if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:structseq", 
153					 kwlist, &arg, &dict))
154		return NULL;
155
156	arg = PySequence_Fast(arg, "constructor requires a sequence");
157
158	if (!arg) {				
159		return NULL;
160	}
161
162	if (dict && !PyDict_Check(dict)) {
163		PyErr_Format(PyExc_TypeError, 
164			     "%.500s() takes a dict as second arg, if any",
165			     type->tp_name);
166		Py_DECREF(arg);
167		return NULL;
168	}
169
170	len = PySequence_Fast_GET_SIZE(arg);
171	min_len = VISIBLE_SIZE_TP(type);
172	max_len = REAL_SIZE_TP(type);
173	n_unnamed_fields = UNNAMED_FIELDS_TP(type);
174
175	if (min_len != max_len) {
176		if (len < min_len) {
177			PyErr_Format(PyExc_TypeError, 
178	       "%.500s() takes an at least %zd-sequence (%zd-sequence given)",
179				     type->tp_name, min_len, len);
180			Py_DECREF(arg);
181			return NULL;
182		}
183
184		if (len > max_len) {
185			PyErr_Format(PyExc_TypeError, 
186	       "%.500s() takes an at most %zd-sequence (%zd-sequence given)",
187				     type->tp_name, max_len, len);
188			Py_DECREF(arg);
189			return NULL;
190		}
191	} 
192	else {
193		if (len != min_len) {
194			PyErr_Format(PyExc_TypeError, 
195	       "%.500s() takes a %zd-sequence (%zd-sequence given)",
196				     type->tp_name, min_len, len);
197			Py_DECREF(arg);
198			return NULL;
199		}
200	}
201
202	res = (PyStructSequence*) PyStructSequence_New(type);
203	if (res == NULL) {
204		return NULL;
205	}
206	for (i = 0; i < len; ++i) {
207		PyObject *v = PySequence_Fast_GET_ITEM(arg, i);
208		Py_INCREF(v);
209		res->ob_item[i] = v;
210	}
211	for (; i < max_len; ++i) {
212		if (dict && (ob = PyDict_GetItemString(
213			dict, type->tp_members[i-n_unnamed_fields].name))) {
214		}
215		else {
216			ob = Py_None;
217		}
218		Py_INCREF(ob);
219		res->ob_item[i] = ob;
220	}
221	
222	Py_DECREF(arg);
223	return (PyObject*) res;
224}
225
226static PyObject *
227make_tuple(PyStructSequence *obj)
228{
229	return structseq_slice(obj, 0, VISIBLE_SIZE(obj));
230}
231
232static PyObject *
233structseq_repr(PyStructSequence *obj)
234{
235	/* buffer and type size were chosen well considered. */
236#define REPR_BUFFER_SIZE 512
237#define TYPE_MAXSIZE 100
238
239	PyObject *tup;
240	PyTypeObject *typ = Py_TYPE(obj);
241	int i, removelast = 0;
242	Py_ssize_t len;
243	char buf[REPR_BUFFER_SIZE];
244	char *endofbuf, *pbuf = buf;
245
246	/* pointer to end of writeable buffer; safes space for "...)\0" */
247	endofbuf= &buf[REPR_BUFFER_SIZE-5];
248
249	if ((tup = make_tuple(obj)) == NULL) {
250		return NULL;
251	}
252
253	/* "typename(", limited to  TYPE_MAXSIZE */
254	len = strlen(typ->tp_name) > TYPE_MAXSIZE ? TYPE_MAXSIZE :
255						    strlen(typ->tp_name);
256	strncpy(pbuf, typ->tp_name, len);
257	pbuf += len;
258	*pbuf++ = '(';
259
260	for (i=0; i < VISIBLE_SIZE(obj); i++) {
261		PyObject *val, *repr;
262		char *cname, *crepr;
263
264		cname = typ->tp_members[i].name;
265		
266		val = PyTuple_GetItem(tup, i);
267		if (cname == NULL || val == NULL) {
268			return NULL;
269		}
270		repr = PyObject_Repr(val);
271		if (repr == NULL) {
272			Py_DECREF(tup);
273			return NULL;
274		}
275		crepr = PyString_AsString(repr);
276		if (crepr == NULL) {
277			Py_DECREF(tup);
278			Py_DECREF(repr);
279			return NULL;
280		}
281		
282		/* + 3: keep space for "=" and ", " */
283 		len = strlen(cname) + strlen(crepr) + 3;
284		if ((pbuf+len) <= endofbuf) {
285			strcpy(pbuf, cname);
286			pbuf += strlen(cname);
287			*pbuf++ = '=';
288			strcpy(pbuf, crepr);
289			pbuf += strlen(crepr);
290			*pbuf++ = ',';
291			*pbuf++ = ' ';
292			removelast = 1;
293			Py_DECREF(repr);
294		}
295		else {
296			strcpy(pbuf, "...");
297			pbuf += 3;
298			removelast = 0;
299			Py_DECREF(repr);
300			break;
301		}
302	}
303	Py_DECREF(tup);
304	if (removelast) {
305		/* overwrite last ", " */
306		pbuf-=2;
307	}
308	*pbuf++ = ')';
309	*pbuf = '\0';
310
311	return PyString_FromString(buf);
312}
313
314static PyObject *
315structseq_concat(PyStructSequence *obj, PyObject *b)
316{
317	PyObject *tup, *result;
318	tup = make_tuple(obj);
319	result = PySequence_Concat(tup, b);
320	Py_DECREF(tup);
321	return result;
322}
323
324static PyObject *
325structseq_repeat(PyStructSequence *obj, Py_ssize_t n)
326{
327	PyObject *tup, *result;
328	tup = make_tuple(obj);
329	result = PySequence_Repeat(tup, n);
330	Py_DECREF(tup);
331	return result;
332}
333
334static int
335structseq_contains(PyStructSequence *obj, PyObject *o)
336{
337	PyObject *tup;
338	int result;
339	tup = make_tuple(obj);
340	if (!tup)
341		return -1;
342	result = PySequence_Contains(tup, o);
343	Py_DECREF(tup);
344	return result;
345}
346
347static long
348structseq_hash(PyObject *obj)
349{
350	PyObject *tup;
351	long result;
352	tup = make_tuple((PyStructSequence*) obj);
353	if (!tup)
354		return -1;
355	result = PyObject_Hash(tup);
356	Py_DECREF(tup);
357	return result;
358}
359
360static PyObject *
361structseq_richcompare(PyObject *obj, PyObject *o2, int op)
362{
363	PyObject *tup, *result;
364	tup = make_tuple((PyStructSequence*) obj);
365	result = PyObject_RichCompare(tup, o2, op);
366	Py_DECREF(tup);
367	return result;
368}
369
370static PyObject *
371structseq_reduce(PyStructSequence* self)
372{
373	PyObject* tup;
374	PyObject* dict;
375	PyObject* result;
376	Py_ssize_t n_fields, n_visible_fields, n_unnamed_fields;
377	int i;
378	
379	n_fields = REAL_SIZE(self);
380	n_visible_fields = VISIBLE_SIZE(self);
381	n_unnamed_fields = UNNAMED_FIELDS(self);
382	tup = PyTuple_New(n_visible_fields);
383	if (!tup) {
384		return NULL;
385	}
386
387	dict = PyDict_New();
388	if (!dict) {
389		Py_DECREF(tup);
390		return NULL;
391	}
392
393	for (i = 0; i < n_visible_fields; i++) {
394		Py_INCREF(self->ob_item[i]);
395		PyTuple_SET_ITEM(tup, i, self->ob_item[i]);
396	}
397	
398	for (; i < n_fields; i++) {
399		char *n = Py_TYPE(self)->tp_members[i-n_unnamed_fields].name;
400		PyDict_SetItemString(dict, n,
401				     self->ob_item[i]);
402	}
403
404	result = Py_BuildValue("(O(OO))", Py_TYPE(self), tup, dict);
405
406	Py_DECREF(tup);
407	Py_DECREF(dict);
408
409	return result;
410}
411
412static PySequenceMethods structseq_as_sequence = {
413	(lenfunc)structseq_length,
414	(binaryfunc)structseq_concat,           /* sq_concat */
415	(ssizeargfunc)structseq_repeat,         /* sq_repeat */
416	(ssizeargfunc)structseq_item,		/* sq_item */
417	(ssizessizeargfunc)structseq_slice,	/* sq_slice */
418	0,					/* sq_ass_item */
419	0,					/* sq_ass_slice */
420	(objobjproc)structseq_contains,	        /* sq_contains */
421};
422
423static PyMappingMethods structseq_as_mapping = {
424	(lenfunc)structseq_length,
425	(binaryfunc)structseq_subscript,
426};
427
428static PyMethodDef structseq_methods[] = {
429	{"__reduce__", (PyCFunction)structseq_reduce, 
430	 METH_NOARGS, NULL},
431	{NULL, NULL}
432};
433
434static PyTypeObject _struct_sequence_template = {
435	PyVarObject_HEAD_INIT(&PyType_Type, 0)
436	NULL,	                     		/* tp_name */
437        0,		                        /* tp_basicsize */
438	0,	                      		/* tp_itemsize */
439	(destructor)structseq_dealloc,	        /* tp_dealloc */
440	0,                        	        /* tp_print */
441	0,			 		/* tp_getattr */
442	0,					/* tp_setattr */
443	0,               			/* tp_compare */
444	(reprfunc)structseq_repr,             	/* tp_repr */
445	0,					/* tp_as_number */
446	&structseq_as_sequence,			/* tp_as_sequence */
447	&structseq_as_mapping,			/* tp_as_mapping */
448	structseq_hash,				/* tp_hash */
449	0,              			/* tp_call */
450	0,					/* tp_str */
451	0,                       		/* tp_getattro */
452	0,	                           	/* tp_setattro */
453	0,					/* tp_as_buffer */
454	Py_TPFLAGS_DEFAULT,                     /* tp_flags */
455	NULL,	 		         	/* tp_doc */
456	0,					/* tp_traverse */
457	0,					/* tp_clear */
458	structseq_richcompare,			/* tp_richcompare */
459	0,					/* tp_weaklistoffset */
460	0,					/* tp_iter */
461	0,					/* tp_iternext */
462	structseq_methods,      		/* tp_methods */
463        NULL,			             	/* tp_members */
464	0,			          	/* tp_getset */
465	0,					/* tp_base */
466	0,					/* tp_dict */
467	0,					/* tp_descr_get */
468	0,					/* tp_descr_set */
469	0,	                                /* tp_dictoffset */
470	0,					/* tp_init */
471	0,					/* tp_alloc */
472	structseq_new,				/* tp_new */
473};
474
475void
476PyStructSequence_InitType(PyTypeObject *type, PyStructSequence_Desc *desc)
477{
478	PyObject *dict;
479	PyMemberDef* members;
480	int n_members, n_unnamed_members, i, k;
481
482#ifdef Py_TRACE_REFS
483	/* if the type object was chained, unchain it first
484	   before overwriting its storage */
485	if (type->_ob_next) {
486		_Py_ForgetReference((PyObject*)type);
487	}
488#endif
489
490	n_unnamed_members = 0;
491	for (i = 0; desc->fields[i].name != NULL; ++i)
492		if (desc->fields[i].name == PyStructSequence_UnnamedField)
493			n_unnamed_members++;
494	n_members = i;
495
496	memcpy(type, &_struct_sequence_template, sizeof(PyTypeObject));
497	type->tp_name = desc->name;
498	type->tp_doc = desc->doc;
499	type->tp_basicsize = sizeof(PyStructSequence)+
500		sizeof(PyObject*)*(n_members-1);
501	type->tp_itemsize = 0;
502
503	members = PyMem_NEW(PyMemberDef, n_members-n_unnamed_members+1);
504	if (members == NULL)
505		return;
506	
507	for (i = k = 0; i < n_members; ++i) {
508		if (desc->fields[i].name == PyStructSequence_UnnamedField)
509			continue;
510		members[k].name = desc->fields[i].name;
511		members[k].type = T_OBJECT;
512		members[k].offset = offsetof(PyStructSequence, ob_item)
513		  + i * sizeof(PyObject*);
514		members[k].flags = READONLY;
515		members[k].doc = desc->fields[i].doc;
516		k++;
517	}
518	members[k].name = NULL;
519
520	type->tp_members = members;
521
522	if (PyType_Ready(type) < 0)
523		return;
524	Py_INCREF(type);
525
526	dict = type->tp_dict;
527#define SET_DICT_FROM_INT(key, value)				\
528	do {							\
529		PyObject *v = PyInt_FromLong((long) value);	\
530		if (v != NULL) {				\
531			PyDict_SetItemString(dict, key, v);	\
532			Py_DECREF(v);				\
533		}						\
534	} while (0)
535
536	SET_DICT_FROM_INT(visible_length_key, desc->n_in_sequence);
537	SET_DICT_FROM_INT(real_length_key, n_members);
538	SET_DICT_FROM_INT(unnamed_fields_key, n_unnamed_members);
539}