diff -r eccd94d4ee77 Include/sysmodule.h --- a/Include/sysmodule.h Thu Sep 20 20:51:14 2012 +0100 +++ b/Include/sysmodule.h Fri Sep 21 09:15:43 2012 +0300 @@ -22,6 +22,7 @@ #ifndef Py_LIMITED_API PyAPI_DATA(PyObject *) _PySys_TraceFunc, *_PySys_ProfileFunc; +PyAPI_DATA(size_t) _PySys_GetSizeOf(PyObject *); #endif PyAPI_FUNC(void) PySys_ResetWarnOptions(void); diff -r eccd94d4ee77 Lib/test/test_memoryio.py --- a/Lib/test/test_memoryio.py Thu Sep 20 20:51:14 2012 +0100 +++ b/Lib/test/test_memoryio.py Fri Sep 21 09:15:43 2012 +0300 @@ -9,6 +9,8 @@ import io import _pyio as pyio import pickle +import sys +import os class MemorySeekTestMixin: @@ -711,6 +713,25 @@ memio.close() self.assertRaises(ValueError, memio.__setstate__, ("closed", "", 0, None)) + check_sizeof = support.check_sizeof + + @support.cpython_only + def test_sizeof(self): + basesize = support.calcobjsize('P2PP4c5P') + usize = len('\0'.encode('unicode-internal')) + stdsize = basesize + 2 * usize + sys.getsizeof(os.linesep) + check = self.check_sizeof + self.assertEqual(object.__sizeof__(io.StringIO()), basesize) + check(io.StringIO(), stdsize) + # newline + for newline in '', '\n', '\r', '\r\n': + check(io.StringIO(newline=newline), + basesize + 2 * usize + sys.getsizeof(newline)) + # UCS4 buffer + for c in 'a', '\x80', '\u0100', '\U00010000': + check(io.StringIO(c * 1000), + stdsize + len((c * 1000).encode('unicode-internal'))) + class CStringIOPickleTest(PyStringIOPickleTest): UnsupportedOperation = io.UnsupportedOperation diff -r eccd94d4ee77 Modules/_io/stringio.c --- a/Modules/_io/stringio.c Thu Sep 20 20:51:14 2012 +0100 +++ b/Modules/_io/stringio.c Fri Sep 21 09:15:43 2012 +0300 @@ -500,6 +500,7 @@ static int stringio_clear(stringio *self) { + Py_CLEAR(self->decoder); Py_CLEAR(self->dict); return 0; } @@ -649,6 +650,22 @@ return 0; } +static PyObject * +stringio_sizeof(stringio *self, void *unused) +{ + size_t res = sizeof(stringio); + + if (self->buf) + res += self->buf_size * sizeof(Py_UNICODE); + if (self->readnl) { + size_t sz = _PySys_GetSizeOf(self->readnl); + if (sz == (size_t)-1 && PyErr_Occurred()) + return NULL; + res += sz; + } + return PyLong_FromSize_t(res); +} + /* Properties and pseudo-properties */ PyDoc_STRVAR(stringio_readable_doc, @@ -854,6 +871,7 @@ {"__getstate__", (PyCFunction)stringio_getstate, METH_NOARGS}, {"__setstate__", (PyCFunction)stringio_setstate, METH_O}, + {"__sizeof__", (PyCFunction)stringio_sizeof, METH_NOARGS}, {NULL, NULL} /* sentinel */ }; diff -r eccd94d4ee77 Python/sysmodule.c --- a/Python/sysmodule.c Thu Sep 20 20:51:14 2012 +0100 +++ b/Python/sysmodule.c Fri Sep 21 09:15:43 2012 +0300 @@ -807,29 +807,17 @@ } #endif /* USE_MALLOPT */ -static PyObject * -sys_getsizeof(PyObject *self, PyObject *args, PyObject *kwds) +size_t +_PySys_GetSizeOf(PyObject *o) { PyObject *res = NULL; - static PyObject *str__sizeof__ = NULL, *gc_head_size = NULL; - static char *kwlist[] = {"object", "default", 0}; - PyObject *o, *dflt = NULL; PyObject *method; - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getsizeof", - kwlist, &o, &dflt)) - return NULL; - - /* Initialize static variable for GC head size */ - if (gc_head_size == NULL) { - gc_head_size = PyLong_FromSsize_t(sizeof(PyGC_Head)); - if (gc_head_size == NULL) - return NULL; - } + size_t size; + static PyObject *str__sizeof__ = NULL; /* Make sure the type is initialized. float gets initialized late */ if (PyType_Ready(Py_TYPE(o)) < 0) - return NULL; + return (size_t)-1; method = _PyObject_LookupSpecial(o, "__sizeof__", &str__sizeof__); @@ -844,24 +832,45 @@ Py_DECREF(method); } - /* Has a default value been given */ - if ((res == NULL) && (dflt != NULL) && - PyErr_ExceptionMatches(PyExc_TypeError)) - { - PyErr_Clear(); - Py_INCREF(dflt); - return dflt; - } - else if (res == NULL) - return res; + if (res == NULL) + return (size_t)-1; + + size = PyLong_AsSize_t(res); + Py_DECREF(res); + if (size == (size_t)-1 && PyErr_Occurred()) + return (size_t)-1; /* add gc_head size */ - if (PyObject_IS_GC(o)) { - PyObject *tmp = res; - res = PyNumber_Add(tmp, gc_head_size); - Py_DECREF(tmp); + if (PyObject_IS_GC(o)) + size += sizeof(PyGC_Head); + return size; +} + +static PyObject * +sys_getsizeof(PyObject *self, PyObject *args, PyObject *kwds) +{ + static char *kwlist[] = {"object", "default", 0}; + size_t size; + PyObject *o, *dflt = NULL; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getsizeof", + kwlist, &o, &dflt)) + return NULL; + + size = _PySys_GetSizeOf(o); + + if (size == (size_t)-1 && PyErr_Occurred()) { + /* Has a default value been given */ + if (dflt != NULL && PyErr_ExceptionMatches(PyExc_TypeError)) { + PyErr_Clear(); + Py_INCREF(dflt); + return dflt; + } + else + return NULL; } - return res; + + return PyLong_FromSize_t(size); } PyDoc_STRVAR(getsizeof_doc,