mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	Finish-up the struct module optimizations started at the Iceland NFS sprint.
This commit is contained in:
		
							parent
							
								
									076d9eef7b
								
							
						
					
					
						commit
						2f6621cce7
					
				
					 2 changed files with 206 additions and 100 deletions
				
			
		
							
								
								
									
										100
									
								
								Lib/struct.py
									
										
									
									
									
								
							
							
						
						
									
										100
									
								
								Lib/struct.py
									
										
									
									
									
								
							|  | @ -1,99 +1 @@ | ||||||
| """ | from _struct import * | ||||||
| Functions to convert between Python values and C structs. |  | ||||||
| Python strings are used to hold the data representing the C struct |  | ||||||
| and also as format strings to describe the layout of data in the C struct. |  | ||||||
| 
 |  | ||||||
| The optional first format char indicates byte order, size and alignment: |  | ||||||
|  @: native order, size & alignment (default) |  | ||||||
|  =: native order, std. size & alignment |  | ||||||
|  <: little-endian, std. size & alignment |  | ||||||
|  >: big-endian, std. size & alignment |  | ||||||
|  !: same as > |  | ||||||
| 
 |  | ||||||
| The remaining chars indicate types of args and must match exactly; |  | ||||||
| these can be preceded by a decimal repeat count: |  | ||||||
|  x: pad byte (no data); c:char; b:signed byte; B:unsigned byte; |  | ||||||
|  h:short; H:unsigned short; i:int; I:unsigned int; |  | ||||||
|  l:long; L:unsigned long; f:float; d:double. |  | ||||||
| Special cases (preceding decimal count indicates length): |  | ||||||
|  s:string (array of char); p: pascal string (with count byte). |  | ||||||
| Special case (only available in native format): |  | ||||||
|  P:an integer type that is wide enough to hold a pointer. |  | ||||||
| Special case (not in native mode unless 'long long' in platform C): |  | ||||||
|  q:long long; Q:unsigned long long |  | ||||||
| Whitespace between formats is ignored. |  | ||||||
| 
 |  | ||||||
| The variable struct.error is an exception raised on errors. |  | ||||||
| """ |  | ||||||
| __version__ = '0.1' |  | ||||||
| 
 |  | ||||||
| from _struct import Struct, error |  | ||||||
| 
 |  | ||||||
| _MAXCACHE = 100 |  | ||||||
| _cache = {} |  | ||||||
| 
 |  | ||||||
| def _compile(fmt): |  | ||||||
|     # Internal: compile struct pattern |  | ||||||
|     if len(_cache) >= _MAXCACHE: |  | ||||||
|         _cache.clear() |  | ||||||
|     s = Struct(fmt) |  | ||||||
|     _cache[fmt] = s |  | ||||||
|     return s |  | ||||||
| 
 |  | ||||||
| def calcsize(fmt): |  | ||||||
|     """ |  | ||||||
|     Return size of C struct described by format string fmt. |  | ||||||
|     See struct.__doc__ for more on format strings. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         o = _cache[fmt] |  | ||||||
|     except KeyError: |  | ||||||
|         o = _compile(fmt) |  | ||||||
|     return o.size |  | ||||||
| 
 |  | ||||||
| def pack(fmt, *args): |  | ||||||
|     """ |  | ||||||
|     Return string containing values v1, v2, ... packed according to fmt. |  | ||||||
|     See struct.__doc__ for more on format strings. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         o = _cache[fmt] |  | ||||||
|     except KeyError: |  | ||||||
|         o = _compile(fmt) |  | ||||||
|     return o.pack(*args) |  | ||||||
| 
 |  | ||||||
| def pack_into(fmt, buf, offset, *args): |  | ||||||
|     """ |  | ||||||
|     Pack the values v1, v2, ... according to fmt, write |  | ||||||
|     the packed bytes into the writable buffer buf starting at offset. |  | ||||||
|     See struct.__doc__ for more on format strings. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         o = _cache[fmt] |  | ||||||
|     except KeyError: |  | ||||||
|         o = _compile(fmt) |  | ||||||
|     return o.pack_into(buf, offset, *args) |  | ||||||
| 
 |  | ||||||
| def unpack(fmt, s): |  | ||||||
|     """ |  | ||||||
|     Unpack the string, containing packed C structure data, according |  | ||||||
|     to fmt.  Requires len(string)==calcsize(fmt). |  | ||||||
|     See struct.__doc__ for more on format strings. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         o = _cache[fmt] |  | ||||||
|     except KeyError: |  | ||||||
|         o = _compile(fmt) |  | ||||||
|     return o.unpack(s) |  | ||||||
| 
 |  | ||||||
| def unpack_from(fmt, buf, offset=0): |  | ||||||
|     """ |  | ||||||
|     Unpack the buffer, containing packed C structure data, according to |  | ||||||
|     fmt starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt). |  | ||||||
|     See struct.__doc__ for more on format strings. |  | ||||||
|     """ |  | ||||||
|     try: |  | ||||||
|         o = _cache[fmt] |  | ||||||
|     except KeyError: |  | ||||||
|         o = _compile(fmt) |  | ||||||
|     return o.unpack_from(buf, offset) |  | ||||||
|  |  | ||||||
|  | @ -1847,12 +1847,214 @@ PyTypeObject PyStructType = { | ||||||
| 	PyObject_Del,		/* tp_free */ | 	PyObject_Del,		/* tp_free */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
|  | /* ---- Standalone functions  ---- */ | ||||||
|  | 
 | ||||||
|  | #define MAXCACHE 100 | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | cache_struct(PyObject *fmt) | ||||||
|  | { | ||||||
|  | 	static PyObject *cache = NULL; | ||||||
|  | 	PyObject * s_object; | ||||||
|  | 
 | ||||||
|  | 	if (cache == NULL) { | ||||||
|  | 		cache = PyDict_New(); | ||||||
|  | 		if (cache == NULL) | ||||||
|  | 			return NULL; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	s_object = PyDict_GetItem(cache, fmt); | ||||||
|  | 	if (s_object != NULL) { | ||||||
|  | 		Py_INCREF(s_object); | ||||||
|  | 		return s_object; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	s_object = PyObject_CallFunctionObjArgs((PyObject *)(&PyStructType), fmt, NULL); | ||||||
|  | 	if (s_object != NULL) { | ||||||
|  | 		if (PyDict_Size(cache) >= MAXCACHE) | ||||||
|  | 			PyDict_Clear(cache); | ||||||
|  | 		/* Attempt to cache the result */ | ||||||
|  | 		if (PyDict_SetItem(cache, fmt, s_object) == -1) | ||||||
|  | 			PyErr_Clear(); | ||||||
|  | 	} | ||||||
|  | 	return s_object; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(calcsize_doc, | ||||||
|  | "Return size of C struct described by format string fmt."); | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | calcsize(PyObject *self, PyObject *fmt) | ||||||
|  | { | ||||||
|  | 	Py_ssize_t n; | ||||||
|  | 	PyObject *s_object = cache_struct(fmt); | ||||||
|  | 	if (s_object == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 	n = ((PyStructObject *)s_object)->s_size; | ||||||
|  | 	Py_DECREF(s_object); | ||||||
|  |     	return PyInt_FromSsize_t(n); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(pack_doc, | ||||||
|  | "Return string containing values v1, v2, ... packed according to fmt."); | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | pack(PyObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  | 	PyObject *s_object, *fmt, *newargs, *result; | ||||||
|  | 	Py_ssize_t n = PyTuple_GET_SIZE(args); | ||||||
|  | 
 | ||||||
|  | 	if (n == 0) { | ||||||
|  | 		PyErr_SetString(PyExc_TypeError, "missing format argument"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	fmt = PyTuple_GET_ITEM(args, 0); | ||||||
|  | 	newargs = PyTuple_GetSlice(args, 1, n); | ||||||
|  | 	if (newargs == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	s_object = cache_struct(fmt); | ||||||
|  | 	if (s_object == NULL) { | ||||||
|  | 		Py_DECREF(newargs); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |     	result = s_pack(s_object, newargs); | ||||||
|  | 	Py_DECREF(newargs); | ||||||
|  | 	Py_DECREF(s_object); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(pack_into_doc, | ||||||
|  | "Pack the values v1, v2, ... according to fmt.\n\
 | ||||||
|  | Write the packed bytes into the writable buffer buf starting at offset."); | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | pack_into(PyObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  | 	PyObject *s_object, *fmt, *newargs, *result; | ||||||
|  | 	Py_ssize_t n = PyTuple_GET_SIZE(args); | ||||||
|  | 
 | ||||||
|  | 	if (n == 0) { | ||||||
|  | 		PyErr_SetString(PyExc_TypeError, "missing format argument"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	fmt = PyTuple_GET_ITEM(args, 0); | ||||||
|  | 	newargs = PyTuple_GetSlice(args, 1, n); | ||||||
|  | 	if (newargs == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	s_object = cache_struct(fmt); | ||||||
|  | 	if (s_object == NULL) { | ||||||
|  | 		Py_DECREF(newargs); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |     	result = s_pack_into(s_object, newargs); | ||||||
|  | 	Py_DECREF(newargs); | ||||||
|  | 	Py_DECREF(s_object); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(unpack_doc, | ||||||
|  | "Unpack the string containing packed C structure data, according to fmt.\n\
 | ||||||
|  | Requires len(string) == calcsize(fmt)."); | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | unpack(PyObject *self, PyObject *args) | ||||||
|  | { | ||||||
|  | 	PyObject *s_object, *fmt, *inputstr, *result; | ||||||
|  | 
 | ||||||
|  | 	if (!PyArg_UnpackTuple(args, "unpack", 2, 2, &fmt, &inputstr)) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	s_object = cache_struct(fmt); | ||||||
|  | 	if (s_object == NULL) | ||||||
|  | 		return NULL; | ||||||
|  |     	result = s_unpack(s_object, inputstr); | ||||||
|  | 	Py_DECREF(s_object); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | PyDoc_STRVAR(unpack_from_doc, | ||||||
|  | "Unpack the buffer, containing packed C structure data, according to\n\
 | ||||||
|  | fmt, starting at offset. Requires len(buffer[offset:]) >= calcsize(fmt)."); | ||||||
|  | 
 | ||||||
|  | static PyObject * | ||||||
|  | unpack_from(PyObject *self, PyObject *args, PyObject *kwds) | ||||||
|  | { | ||||||
|  | 	PyObject *s_object, *fmt, *newargs, *result; | ||||||
|  | 	Py_ssize_t n = PyTuple_GET_SIZE(args); | ||||||
|  | 
 | ||||||
|  | 	if (n == 0) { | ||||||
|  | 		PyErr_SetString(PyExc_TypeError, "missing format argument"); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  | 	fmt = PyTuple_GET_ITEM(args, 0); | ||||||
|  | 	newargs = PyTuple_GetSlice(args, 1, n); | ||||||
|  | 	if (newargs == NULL) | ||||||
|  | 		return NULL; | ||||||
|  | 
 | ||||||
|  | 	s_object = cache_struct(fmt); | ||||||
|  | 	if (s_object == NULL) { | ||||||
|  | 		Py_DECREF(newargs); | ||||||
|  | 		return NULL; | ||||||
|  | 	} | ||||||
|  |     	result = s_unpack_from(s_object, newargs, kwds); | ||||||
|  | 	Py_DECREF(newargs); | ||||||
|  | 	Py_DECREF(s_object); | ||||||
|  | 	return result; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static struct PyMethodDef module_functions[] = { | ||||||
|  | 	{"calcsize",	calcsize,	METH_O, 	calcsize_doc}, | ||||||
|  | 	{"pack",	pack,		METH_VARARGS, 	pack_doc}, | ||||||
|  | 	{"pack_into",	pack_into,	METH_VARARGS, 	pack_into_doc}, | ||||||
|  | 	{"unpack",	unpack,       	METH_VARARGS, 	unpack_doc}, | ||||||
|  | 	{"unpack_from",	(PyCFunction)unpack_from, 	 | ||||||
|  | 			METH_VARARGS|METH_KEYWORDS, 	unpack_from_doc}, | ||||||
|  | 	{NULL,	 NULL}		/* sentinel */ | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| /* Module initialization */ | /* Module initialization */ | ||||||
| 
 | 
 | ||||||
|  | PyDoc_STRVAR(module_doc, | ||||||
|  | "Functions to convert between Python values and C structs.\n\
 | ||||||
|  | Python strings are used to hold the data representing the C struct\n\ | ||||||
|  | and also as format strings to describe the layout of data in the C struct.\n\ | ||||||
|  | \n\ | ||||||
|  | The optional first format char indicates byte order, size and alignment:\n\ | ||||||
|  |  @: native order, size & alignment (default)\n\ | ||||||
|  |  =: native order, std. size & alignment\n\ | ||||||
|  |  <: little-endian, std. size & alignment\n\ | ||||||
|  |  >: big-endian, std. size & alignment\n\ | ||||||
|  |  !: same as >\n\ | ||||||
|  | \n\ | ||||||
|  | The remaining chars indicate types of args and must match exactly;\n\ | ||||||
|  | these can be preceded by a decimal repeat count:\n\ | ||||||
|  |   x: pad byte (no data); c:char; b:signed byte; B:unsigned byte;\n\ | ||||||
|  |   h:short; H:unsigned short; i:int; I:unsigned int;\n\ | ||||||
|  |   l:long; L:unsigned long; f:float; d:double.\n\ | ||||||
|  | Special cases (preceding decimal count indicates length):\n\ | ||||||
|  |   s:string (array of char); p: pascal string (with count byte).\n\ | ||||||
|  | Special case (only available in native format):\n\ | ||||||
|  |   P:an integer type that is wide enough to hold a pointer.\n\ | ||||||
|  | Special case (not in native mode unless 'long long' in platform C):\n\ | ||||||
|  |   q:long long; Q:unsigned long long\n\ | ||||||
|  | Whitespace between formats is ignored.\n\ | ||||||
|  | \n\ | ||||||
|  | The variable struct.error is an exception raised on errors.\n"); | ||||||
|  | 
 | ||||||
| PyMODINIT_FUNC | PyMODINIT_FUNC | ||||||
| init_struct(void) | init_struct(void) | ||||||
| { | { | ||||||
| 	PyObject *m = Py_InitModule("_struct", NULL); | 	PyObject *ver, *m; | ||||||
|  | 
 | ||||||
|  | 	ver = PyString_FromString("0.2"); | ||||||
|  | 	if (ver == NULL) | ||||||
|  | 		return; | ||||||
|  | 
 | ||||||
|  | 	m = Py_InitModule3("_struct", module_functions, module_doc); | ||||||
| 	if (m == NULL) | 	if (m == NULL) | ||||||
| 		return; | 		return; | ||||||
| 
 | 
 | ||||||
|  | @ -1933,6 +2135,8 @@ init_struct(void) | ||||||
| 	Py_INCREF((PyObject*)&PyStructType); | 	Py_INCREF((PyObject*)&PyStructType); | ||||||
| 	PyModule_AddObject(m, "Struct", (PyObject*)&PyStructType); | 	PyModule_AddObject(m, "Struct", (PyObject*)&PyStructType); | ||||||
| 
 | 
 | ||||||
|  | 	PyModule_AddObject(m, "__version__", ver); | ||||||
|  | 
 | ||||||
| 	PyModule_AddIntConstant(m, "_PY_STRUCT_RANGE_CHECKING", 1); | 	PyModule_AddIntConstant(m, "_PY_STRUCT_RANGE_CHECKING", 1); | ||||||
| #ifdef PY_STRUCT_OVERFLOW_MASKING | #ifdef PY_STRUCT_OVERFLOW_MASKING | ||||||
| 	PyModule_AddIntConstant(m, "_PY_STRUCT_OVERFLOW_MASKING", 1); | 	PyModule_AddIntConstant(m, "_PY_STRUCT_OVERFLOW_MASKING", 1); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Raymond Hettinger
						Raymond Hettinger