Commit fbe94c55 authored by Robert Schuppenies's avatar Robert Schuppenies

Merged revisions 64842,64853,64856,64945 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r64842 | robert.schuppenies | 2008-07-10 15:43:26 +0200 (Thu, 10 Jul 2008) | 2 lines

  Fixed Issue3122 and extended sys.getsizeof tests for built-in types.
........
  r64853 | robert.schuppenies | 2008-07-10 17:24:04 +0200 (Thu, 10 Jul 2008) | 3 lines

  Added additional __sizeof__ implementations and addressed comments made in
  Issue3122.
........
  r64856 | robert.schuppenies | 2008-07-10 19:13:55 +0200 (Thu, 10 Jul 2008) | 3 lines

  Added garbage collector overhead and optional default return value to
  sys.getsizeof.
........
  r64945 | robert.schuppenies | 2008-07-14 10:42:18 +0200 (Mon, 14 Jul 2008) | 2 lines

  Fixed test failure on Win64 machines.
........
parent 3065b87a
...@@ -331,13 +331,20 @@ always available. ...@@ -331,13 +331,20 @@ always available.
:func:`setrecursionlimit`. :func:`setrecursionlimit`.
.. function:: getsizeof(object) .. function:: getsizeof(object[, default])
Return the size of an object in bytes. The object can be any type of Return the size of an object in bytes. The object can be any type of
object. All built-in objects will return correct results, but this object. All built-in objects will return correct results, but this
does not have to hold true for third-party extensions as it is implementation does not have to hold true for third-party extensions as it is implementation
specific. specific.
The *default* argument allows to define a value which will be returned
if the object type does not provide means to retrieve the size and would
cause a `TypeError`.
func:`getsizeof` calls the object's __sizeof__ method and adds an additional
garbage collector overhead if the object is managed by the garbage collector.
.. versionadded:: 2.6 .. versionadded:: 2.6
......
...@@ -373,6 +373,9 @@ class SysModuleTest(unittest.TestCase): ...@@ -373,6 +373,9 @@ class SysModuleTest(unittest.TestCase):
class SizeofTest(unittest.TestCase): class SizeofTest(unittest.TestCase):
TPFLAGS_HAVE_GC = 1<<14
TPFLAGS_HEAPTYPE = 1<<9
def setUp(self): def setUp(self):
self.c = len(struct.pack('c', ' ')) self.c = len(struct.pack('c', ' '))
self.H = len(struct.pack('H', 0)) self.H = len(struct.pack('H', 0))
...@@ -382,22 +385,27 @@ class SizeofTest(unittest.TestCase): ...@@ -382,22 +385,27 @@ class SizeofTest(unittest.TestCase):
# due to missing size_t information from struct, it is assumed that # due to missing size_t information from struct, it is assumed that
# sizeof(Py_ssize_t) = sizeof(void*) # sizeof(Py_ssize_t) = sizeof(void*)
self.header = 'PP' self.header = 'PP'
self.vheader = self.header + 'P'
if hasattr(sys, "gettotalrefcount"): if hasattr(sys, "gettotalrefcount"):
self.header += '2P' self.header += '2P'
self.vheader += '2P'
import _testcapi
self.gc_headsize = _testcapi.SIZEOF_PYGC_HEAD
self.file = open(test.support.TESTFN, 'wb') self.file = open(test.support.TESTFN, 'wb')
def tearDown(self): def tearDown(self):
self.file.close() self.file.close()
test.support.unlink(test.support.TESTFN) test.support.unlink(test.support.TESTFN)
def check_sizeof(self, o, size, size2=None): def check_sizeof(self, o, size):
"""Check size of o. Possible are size and optionally size2)."""
result = sys.getsizeof(o) result = sys.getsizeof(o)
msg = 'wrong size for %s: got %d, expected ' % (type(o), result) # add GC header size
if (size2 != None) and (result != size): if ((type(o) == type) and (o.__flags__ & self.TPFLAGS_HEAPTYPE) or\
self.assertEqual(result, size2, msg + str(size2)) ((type(o) != type) and (type(o).__flags__ & self.TPFLAGS_HAVE_GC))):
else: size += self.gc_headsize
self.assertEqual(result, size, msg + str(size)) msg = 'wrong size for %s: got %d, expected %d' \
% (type(o), result, size)
self.assertEqual(result, size, msg)
def calcsize(self, fmt): def calcsize(self, fmt):
"""Wrapper around struct.calcsize which enforces the alignment of the """Wrapper around struct.calcsize which enforces the alignment of the
...@@ -408,29 +416,116 @@ class SizeofTest(unittest.TestCase): ...@@ -408,29 +416,116 @@ class SizeofTest(unittest.TestCase):
""" """
return struct.calcsize(fmt + '0P') return struct.calcsize(fmt + '0P')
def test_standardtypes(self): def test_gc_head_size(self):
# Check that the gc header size is added to objects tracked by the gc.
h = self.header
vh = self.vheader
size = self.calcsize
gc_header_size = self.gc_headsize
# bool objects are not gc tracked
self.assertEqual(sys.getsizeof(True), size(vh) + self.H)
# but lists are
self.assertEqual(sys.getsizeof([]), size(vh + 'PP') + gc_header_size)
def test_default(self):
h = self.header h = self.header
vh = self.vheader
size = self.calcsize size = self.calcsize
self.assertEqual(sys.getsizeof(True), size(vh) + self.H)
self.assertEqual(sys.getsizeof(True, -1), size(vh) + self.H)
def test_objecttypes(self):
# check all types defined in Objects/
h = self.header
vh = self.vheader
size = self.calcsize
check = self.check_sizeof
# bool
check(True, size(vh) + self.H)
# buffer
# XXX
# builtin_function_or_method
check(len, size(h + '3P'))
# bytearray
samples = [b'', b'u'*100000]
for sample in samples:
x = bytearray(sample)
check(x, size(vh + 'iPP') + x.__alloc__() * self.c)
# bytearray_iterator
check(iter(bytearray()), size(h + 'PP'))
# cell # cell
def get_cell(): def get_cell():
x = 42 x = 42
def inner(): def inner():
return x return x
return inner return inner
self.check_sizeof(get_cell().__closure__[0], size(h + 'P')) check(get_cell().__closure__[0], size(h + 'P'))
# code # code
self.check_sizeof(get_cell().__code__, size(h + '5i8Pi2P')) check(get_cell().__code__, size(h + '5i8Pi2P'))
# complex # complex
self.check_sizeof(complex(0,1), size(h + '2d')) check(complex(0,1), size(h + '2d'))
# method_descriptor (descriptor object)
check(str.lower, size(h + '2PP'))
# classmethod_descriptor (descriptor object)
# XXX
# member_descriptor (descriptor object)
import datetime
check(datetime.timedelta.days, size(h + '2PP'))
# getset_descriptor (descriptor object)
import collections
check(collections.defaultdict.default_factory, size(h + '2PP'))
# wrapper_descriptor (descriptor object)
check(int.__add__, size(h + '2P2P'))
# method-wrapper (descriptor object)
check({}.__iter__, size(h + '2P'))
# dict
check({}, size(h + '3P2P' + 8*'P2P'))
longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
check(longdict, size(h + '3P2P' + 8*'P2P') + 16*size('P2P'))
# dictionary-keyiterator
check({}.keys(), size(h + 'P'))
# dictionary-valueiterator
check({}.values(), size(h + 'P'))
# dictionary-itemiterator
check({}.items(), size(h + 'P'))
# dictproxy
class C(object): pass
check(C.__dict__, size(h + 'P'))
# BaseException
check(BaseException(), size(h + '5P'))
# UnicodeEncodeError
check(UnicodeEncodeError("", "", 0, 0, ""), size(h + '5P 2P2PP'))
# UnicodeDecodeError
# XXX
# check(UnicodeDecodeError("", "", 0, 0, ""), size(h + '5P2PP'))
# UnicodeTranslateError
check(UnicodeTranslateError("", 0, 1, ""), size(h + '5P 2P2PP'))
# ellipses
check(Ellipsis, size(h + ''))
# EncodingMap
import codecs, encodings.iso8859_3
x = codecs.charmap_build(encodings.iso8859_3.decoding_table)
check(x, size(h + '32B2iB'))
# enumerate # enumerate
self.check_sizeof(enumerate([]), size(h + 'l3P')) check(enumerate([]), size(h + 'l3P'))
# reverse # reverse
self.check_sizeof(reversed(''), size(h + 'PP')) check(reversed(''), size(h + 'PP'))
# float # float
self.check_sizeof(float(0), size(h + 'd')) check(float(0), size(h + 'd'))
# sys.floatinfo
check(sys.float_info, size(vh) + self.P * len(sys.float_info))
# frame
import inspect
CO_MAXBLOCKS = 20
x = inspect.currentframe()
ncells = len(x.f_code.co_cellvars)
nfrees = len(x.f_code.co_freevars)
extras = x.f_code.co_stacksize + x.f_code.co_nlocals +\
ncells + nfrees - 1
check(x, size(vh + '12P3i' + CO_MAXBLOCKS*'3i' + 'P' + extras*'P'))
# function # function
def func(): pass def func(): pass
self.check_sizeof(func, size(h + '11P')) check(func, size(h + '11P'))
class c(): class c():
@staticmethod @staticmethod
def foo(): def foo():
...@@ -439,40 +534,99 @@ class SizeofTest(unittest.TestCase): ...@@ -439,40 +534,99 @@ class SizeofTest(unittest.TestCase):
def bar(cls): def bar(cls):
pass pass
# staticmethod # staticmethod
self.check_sizeof(foo, size(h + 'P')) check(foo, size(h + 'P'))
# classmethod # classmethod
self.check_sizeof(bar, size(h + 'P')) check(bar, size(h + 'P'))
# generator # generator
def get_gen(): yield 1 def get_gen(): yield 1
self.check_sizeof(get_gen(), size(h + 'Pi2P')) check(get_gen(), size(h + 'Pi2P'))
# builtin_function_or_method # iterator
self.check_sizeof(abs, size(h + '3P')) check(iter('abc'), size(h + 'lP'))
# callable-iterator
import re
check(re.finditer('',''), size(h + '2P'))
# list
samples = [[], [1,2,3], ['1', '2', '3']]
for sample in samples:
check(sample, size(vh + 'PP') + len(sample)*self.P)
# sortwrapper (list)
# XXX
# cmpwrapper (list)
# XXX
# listiterator (list)
check(iter([]), size(h + 'lP'))
# listreverseiterator (list)
check(reversed([]), size(h + 'lP'))
# long
check(0, size(vh))
check(1, size(vh) + self.H)
check(-1, size(vh) + self.H)
check(32768, size(vh) + 2*self.H)
check(32768*32768-1, size(vh) + 2*self.H)
check(32768*32768, size(vh) + 3*self.H)
# memory
check(memoryview(b''), size(h + 'P P2P2i5P'))
# module # module
self.check_sizeof(unittest, size(h + '3P')) check(unittest, size(h + '3P'))
# None
check(None, size(h + ''))
# NotImplementedType
check(NotImplemented, size(h))
# object
check(object(), size(h + ''))
# property (descriptor object)
class C(object):
def getx(self): return self.__x
def setx(self, value): self.__x = value
def delx(self): del self.__x
x = property(getx, setx, delx, "")
check(x, size(h + '4Pi'))
# PyCObject
# XXX
# rangeiterator
check(iter(range(1)), size(h + '4l'))
# reverse
check(reversed(''), size(h + 'PP'))
# range # range
self.check_sizeof(range(1), size(h + '3P')) check(range(1), size(h + '3P'))
check(range(66000), size(h + '3l'))
# set
# frozenset
PySet_MINSIZE = 8
samples = [[], range(10), range(50)]
s = size(h + '3P2P' + PySet_MINSIZE*'lP' + 'lP')
for sample in samples:
minused = len(sample)
if minused == 0: tmp = 1
# the computation of minused is actually a bit more complicated
# but this suffices for the sizeof test
minused = minused*2
newsize = PySet_MINSIZE
while newsize <= minused:
newsize = newsize << 1
if newsize <= 8:
check(set(sample), s)
check(frozenset(sample), s)
else:
check(set(sample), s + newsize*struct.calcsize('lP'))
check(frozenset(sample), s + newsize*struct.calcsize('lP'))
# setiterator
check(iter(set()), size(h + 'P3P'))
# slice # slice
self.check_sizeof(slice(0), size(h + '3P')) check(slice(0), size(h + '3P'))
# super
h += 'P' check(super(int), size(h + '3P'))
# bool # tuple
self.check_sizeof(True, size(h + 'H')) check((), size(vh))
# new-style class check((1,2,3), size(vh) + 3*self.P)
class class_newstyle(object): # type
def method(): # (PyTypeObject + PyNumberMethods + PyMappingMethods +
pass
# type (PyTypeObject + PyNumberMethods + PyMappingMethods +
# PySequenceMethods + PyBufferProcs) # PySequenceMethods + PyBufferProcs)
self.check_sizeof(class_newstyle, size(h + 'P2P15Pl4PP9PP11PI') +\ s = size(vh + 'P2P15Pl4PP9PP11PI') + size('16Pi17P 3P 10P 2P 2P')
size('16Pi17P 3P 10P 2P 2P')) check(int, s)
# class
def test_specialtypes(self): class newstyleclass(object): pass
h = self.header check(newstyleclass, s)
size = self.calcsize
# dict
self.check_sizeof({}, size(h + '3P2P') + 8*size('P2P'))
longdict = {1:1, 2:2, 3:3, 4:4, 5:5, 6:6, 7:7, 8:8}
self.check_sizeof(longdict, size(h + '3P2P') + (8+16)*size('P2P'))
# unicode # unicode
usize = len('\0'.encode('unicode-internal')) usize = len('\0'.encode('unicode-internal'))
samples = ['', '1'*100] samples = ['', '1'*100]
...@@ -480,31 +634,38 @@ class SizeofTest(unittest.TestCase): ...@@ -480,31 +634,38 @@ class SizeofTest(unittest.TestCase):
# has been cached # has been cached
for s in samples: for s in samples:
basicsize = size(h + 'PPliP') + usize * (len(s) + 1) basicsize = size(h + 'PPliP') + usize * (len(s) + 1)
defenc = bytes(s, 'ascii') check(s, basicsize)
self.check_sizeof(s, basicsize, # weakref
size2=basicsize + sys.getsizeof(defenc)) import weakref
# trigger caching encoded version as bytes object check(weakref.ref(int), size(h + '2Pl2P'))
# weakproxy
# XXX
# weakcallableproxy
check(weakref.proxy(int), size(h + '2Pl2P'))
def test_pythontypes(self):
# check all types defined in Python/
h = self.header
vh = self.vheader
size = self.calcsize
check = self.check_sizeof
# _ast.AST
import _ast
check(_ast.AST(), size(h + ''))
# imp.NullImporter
import imp
check(imp.NullImporter(self.file.name), size(h + ''))
try: try:
getattr(sys, s) raise TypeError
except AttributeError: except TypeError:
pass tb = sys.exc_info()[2]
finally: # traceback
self.check_sizeof(s, basicsize + sys.getsizeof(defenc)) if tb != None:
check(tb, size(h + '2P2i'))
h += 'P' # symtable entry
# list # XXX
self.check_sizeof([], size(h + 'PP')) # sys.flags
self.check_sizeof([1, 2, 3], size(h + 'PP') + 3*self.P) check(sys.flags, size(vh) + self.P * len(sys.flags))
# long
self.check_sizeof(0, size(h + 'H'))
self.check_sizeof(1, size(h + 'H'))
self.check_sizeof(-1, size(h + 'H'))
self.check_sizeof(32768, size(h + 'H') + self.H)
self.check_sizeof(32768*32768-1, size(h + 'H') + self.H)
self.check_sizeof(32768*32768, size(h + 'H') + 2*self.H)
# tuple
self.check_sizeof((), size(h))
self.check_sizeof((1,2,3), size(h) + 3*self.P)
def test_main(): def test_main():
......
...@@ -1182,6 +1182,7 @@ PyInit__testcapi(void) ...@@ -1182,6 +1182,7 @@ PyInit__testcapi(void)
PyModule_AddObject(m, "ULLONG_MAX", PyLong_FromUnsignedLongLong(PY_ULLONG_MAX)); PyModule_AddObject(m, "ULLONG_MAX", PyLong_FromUnsignedLongLong(PY_ULLONG_MAX));
PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyLong_FromSsize_t(PY_SSIZE_T_MAX)); PyModule_AddObject(m, "PY_SSIZE_T_MAX", PyLong_FromSsize_t(PY_SSIZE_T_MAX));
PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyLong_FromSsize_t(PY_SSIZE_T_MIN)); PyModule_AddObject(m, "PY_SSIZE_T_MIN", PyLong_FromSsize_t(PY_SSIZE_T_MIN));
PyModule_AddObject(m, "SIZEOF_PYGC_HEAD", PyLong_FromSsize_t(sizeof(PyGC_Head)));
TestError = PyErr_NewException("_testcapi.error", NULL, NULL); TestError = PyErr_NewException("_testcapi.error", NULL, NULL);
Py_INCREF(TestError); Py_INCREF(TestError);
......
...@@ -3033,6 +3033,19 @@ bytes_reduce(PyByteArrayObject *self) ...@@ -3033,6 +3033,19 @@ bytes_reduce(PyByteArrayObject *self)
return Py_BuildValue("(O(Ns)N)", Py_TYPE(self), latin1, "latin-1", dict); return Py_BuildValue("(O(Ns)N)", Py_TYPE(self), latin1, "latin-1", dict);
} }
PyDoc_STRVAR(sizeof_doc,
"B.__sizeof__() -> int\n\
\n\
Returns the size of B in memory, in bytes");
static PyObject *
bytes_sizeof(PyByteArrayObject *self)
{
Py_ssize_t res;
res = sizeof(PyByteArrayObject) + self->ob_alloc * sizeof(char);
return PyLong_FromSsize_t(res);
}
static PySequenceMethods bytes_as_sequence = { static PySequenceMethods bytes_as_sequence = {
(lenfunc)bytes_length, /* sq_length */ (lenfunc)bytes_length, /* sq_length */
(binaryfunc)PyByteArray_Concat, /* sq_concat */ (binaryfunc)PyByteArray_Concat, /* sq_concat */
...@@ -3061,6 +3074,7 @@ static PyMethodDef ...@@ -3061,6 +3074,7 @@ static PyMethodDef
bytes_methods[] = { bytes_methods[] = {
{"__alloc__", (PyCFunction)bytes_alloc, METH_NOARGS, alloc_doc}, {"__alloc__", (PyCFunction)bytes_alloc, METH_NOARGS, alloc_doc},
{"__reduce__", (PyCFunction)bytes_reduce, METH_NOARGS, reduce_doc}, {"__reduce__", (PyCFunction)bytes_reduce, METH_NOARGS, reduce_doc},
{"__sizeof__", (PyCFunction)bytes_sizeof, METH_NOARGS, sizeof_doc},
{"append", (PyCFunction)bytes_append, METH_O, append__doc__}, {"append", (PyCFunction)bytes_append, METH_O, append__doc__},
{"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS, {"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS,
_Py_capitalize__doc__}, _Py_capitalize__doc__},
......
...@@ -513,6 +513,29 @@ frame_clear(PyFrameObject *f) ...@@ -513,6 +513,29 @@ frame_clear(PyFrameObject *f)
} }
} }
static PyObject *
frame_sizeof(PyFrameObject *f)
{
Py_ssize_t res, extras, ncells, nfrees;
ncells = PyTuple_GET_SIZE(f->f_code->co_cellvars);
nfrees = PyTuple_GET_SIZE(f->f_code->co_freevars);
extras = f->f_code->co_stacksize + f->f_code->co_nlocals +
ncells + nfrees;
// subtract one as it is already included in PyFrameObject
res = sizeof(PyFrameObject) + (extras-1) * sizeof(PyObject *);
return PyLong_FromSsize_t(res);
}
PyDoc_STRVAR(sizeof__doc__,
"F.__sizeof__() -> size of F in memory, in bytes");
static PyMethodDef frame_methods[] = {
{"__sizeof__", (PyCFunction)frame_sizeof, METH_NOARGS,
sizeof__doc__},
{NULL, NULL} /* sentinel */
};
PyTypeObject PyFrame_Type = { PyTypeObject PyFrame_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0) PyVarObject_HEAD_INIT(&PyType_Type, 0)
...@@ -542,7 +565,7 @@ PyTypeObject PyFrame_Type = { ...@@ -542,7 +565,7 @@ PyTypeObject PyFrame_Type = {
0, /* tp_weaklistoffset */ 0, /* tp_weaklistoffset */
0, /* tp_iter */ 0, /* tp_iter */
0, /* tp_iternext */ 0, /* tp_iternext */
0, /* tp_methods */ frame_methods, /* tp_methods */
frame_memberlist, /* tp_members */ frame_memberlist, /* tp_members */
frame_getsetlist, /* tp_getset */ frame_getsetlist, /* tp_getset */
0, /* tp_base */ 0, /* tp_base */
......
...@@ -3638,9 +3638,7 @@ long_sizeof(PyLongObject *v) ...@@ -3638,9 +3638,7 @@ long_sizeof(PyLongObject *v)
{ {
Py_ssize_t res; Py_ssize_t res;
res = sizeof(PyLongObject) + abs(Py_SIZE(v)) * sizeof(digit); res = sizeof(PyVarObject) + abs(Py_SIZE(v))*sizeof(digit);
if (Py_SIZE(v) != 0)
res -= sizeof(digit);
return PyLong_FromSsize_t(res); return PyLong_FromSsize_t(res);
} }
......
...@@ -1944,6 +1944,18 @@ done: ...@@ -1944,6 +1944,18 @@ done:
PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
static PyObject *
set_sizeof(PySetObject *so)
{
Py_ssize_t res;
res = sizeof(PySetObject);
if (so->table != so->smalltable)
res = res + (so->mask + 1) * sizeof(setentry);
return PyLong_FromSsize_t(res);
}
PyDoc_STRVAR(sizeof_doc, "S.__sizeof__() -> size of S in memory, in bytes");
static int static int
set_init(PySetObject *self, PyObject *args, PyObject *kwds) set_init(PySetObject *self, PyObject *args, PyObject *kwds)
{ {
...@@ -2011,6 +2023,8 @@ static PyMethodDef set_methods[] = { ...@@ -2011,6 +2023,8 @@ static PyMethodDef set_methods[] = {
reduce_doc}, reduce_doc},
{"remove", (PyCFunction)set_remove, METH_O, {"remove", (PyCFunction)set_remove, METH_O,
remove_doc}, remove_doc},
{"__sizeof__", (PyCFunction)set_sizeof, METH_NOARGS,
sizeof_doc},
{"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O,
symmetric_difference_doc}, symmetric_difference_doc},
{"symmetric_difference_update",(PyCFunction)set_symmetric_difference_update, METH_O, {"symmetric_difference_update",(PyCFunction)set_symmetric_difference_update, METH_O,
...@@ -2127,6 +2141,8 @@ static PyMethodDef frozenset_methods[] = { ...@@ -2127,6 +2141,8 @@ static PyMethodDef frozenset_methods[] = {
issuperset_doc}, issuperset_doc},
{"__reduce__", (PyCFunction)set_reduce, METH_NOARGS, {"__reduce__", (PyCFunction)set_reduce, METH_NOARGS,
reduce_doc}, reduce_doc},
{"__sizeof__", (PyCFunction)set_sizeof, METH_NOARGS,
sizeof_doc},
{"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O,
symmetric_difference_doc}, symmetric_difference_doc},
{"union", (PyCFunction)set_union, METH_VARARGS, {"union", (PyCFunction)set_union, METH_VARARGS,
......
...@@ -8350,20 +8350,8 @@ PyDoc_STRVAR(p_format__doc__, ...@@ -8350,20 +8350,8 @@ PyDoc_STRVAR(p_format__doc__,
static PyObject * static PyObject *
unicode__sizeof__(PyUnicodeObject *v) unicode__sizeof__(PyUnicodeObject *v)
{ {
PyObject *res = NULL, *defsize = NULL; return PyLong_FromSsize_t(sizeof(PyUnicodeObject) +
res = PyLong_FromSsize_t(sizeof(PyUnicodeObject) +
sizeof(Py_UNICODE) * (v->length + 1)); sizeof(Py_UNICODE) * (v->length + 1));
if (v->defenc) {
defsize = PyObject_CallMethod(v->defenc, "__sizeof__", NULL);
if (defsize == NULL) {
Py_DECREF(res);
return NULL;
}
res = PyNumber_Add(res, defsize);
Py_DECREF(defsize);
}
return res;
} }
PyDoc_STRVAR(sizeof__doc__, PyDoc_STRVAR(sizeof__doc__,
......
...@@ -610,9 +610,16 @@ sys_mdebug(PyObject *self, PyObject *args) ...@@ -610,9 +610,16 @@ sys_mdebug(PyObject *self, PyObject *args)
#endif /* USE_MALLOPT */ #endif /* USE_MALLOPT */
static PyObject * static PyObject *
sys_getsizeof(PyObject *self, PyObject *args) sys_getsizeof(PyObject *self, PyObject *args, PyObject *kwds)
{ {
static PyObject * str__sizeof__ = NULL; PyObject *res = NULL;
static PyObject *str__sizeof__, *gc_head_size = NULL;
static char *kwlist[] = {"object", "default", 0};
PyObject *o, *dflt = NULL;
if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O:getsizeof",
kwlist, &o, &dflt))
return NULL;
/* Initialize static variable needed by _PyType_Lookup */ /* Initialize static variable needed by _PyType_Lookup */
if (str__sizeof__ == NULL) { if (str__sizeof__ == NULL) {
...@@ -621,24 +628,47 @@ sys_getsizeof(PyObject *self, PyObject *args) ...@@ -621,24 +628,47 @@ sys_getsizeof(PyObject *self, PyObject *args)
return NULL; return NULL;
} }
/* Type objects */ /* Initialize static variable for GC head size */
if (PyType_Check(args)){ if (gc_head_size == NULL) {
PyObject *method = _PyType_Lookup(Py_TYPE(args), gc_head_size = PyLong_FromSsize_t(sizeof(PyGC_Head));
str__sizeof__); if (gc_head_size == NULL)
if (method == NULL) { return NULL;
}
/* Make sure the type is initialized. float gets initialized late */
if (PyType_Ready(Py_TYPE(o)) < 0)
return NULL;
PyObject *method = _PyType_Lookup(Py_TYPE(o), str__sizeof__);
if (method == NULL)
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"Type %.100s doesn't define __sizeof__", "Type %.100s doesn't define __sizeof__",
Py_TYPE(args)->tp_name); Py_TYPE(o)->tp_name);
return NULL; else
res = PyObject_CallFunctionObjArgs(method, o, NULL);
/* Has a default value been given */
if ((res == NULL) && (dflt != NULL) &&
PyErr_ExceptionMatches(PyExc_TypeError))
{
PyErr_Clear();
Py_INCREF(dflt);
return dflt;
} }
return PyObject_CallFunctionObjArgs(method, args, NULL); else if (res == NULL)
return res;
/* add gc_head size */
if (PyObject_IS_GC(o)) {
PyObject *tmp = res;
res = PyNumber_Add(tmp, gc_head_size);
Py_DECREF(tmp);
} }
else return res;
return PyObject_CallMethod(args, "__sizeof__", NULL);
} }
PyDoc_STRVAR(getsizeof_doc, PyDoc_STRVAR(getsizeof_doc,
"getsizeof(object) -> int\n\ "getsizeof(object, default) -> int\n\
\n\ \n\
Return the size of object in bytes."); Return the size of object in bytes.");
...@@ -845,7 +875,8 @@ static PyMethodDef sys_methods[] = { ...@@ -845,7 +875,8 @@ static PyMethodDef sys_methods[] = {
{"getrefcount", (PyCFunction)sys_getrefcount, METH_O, getrefcount_doc}, {"getrefcount", (PyCFunction)sys_getrefcount, METH_O, getrefcount_doc},
{"getrecursionlimit", (PyCFunction)sys_getrecursionlimit, METH_NOARGS, {"getrecursionlimit", (PyCFunction)sys_getrecursionlimit, METH_NOARGS,
getrecursionlimit_doc}, getrecursionlimit_doc},
{"getsizeof", sys_getsizeof, METH_O, getsizeof_doc}, {"getsizeof", (PyCFunction)sys_getsizeof,
METH_VARARGS | METH_KEYWORDS, getsizeof_doc},
{"_getframe", sys_getframe, METH_VARARGS, getframe_doc}, {"_getframe", sys_getframe, METH_VARARGS, getframe_doc},
#ifdef MS_WINDOWS #ifdef MS_WINDOWS
{"getwindowsversion", (PyCFunction)sys_getwindowsversion, METH_NOARGS, {"getwindowsversion", (PyCFunction)sys_getwindowsversion, METH_NOARGS,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment