diff -r ad25fdb6c521 Include/dictobject.h --- a/Include/dictobject.h Sun Dec 20 09:37:52 2015 +0200 +++ b/Include/dictobject.h Sun Dec 20 10:49:21 2015 +0200 @@ -98,7 +98,7 @@ PyAPI_FUNC(PyObject *) _PyDict_NewPresiz PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp); PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); -PyObject *_PyDict_SizeOf(PyDictObject *); +Py_ssize_t _PyDict_SizeOf(PyDictObject *); PyObject *_PyDict_Pop(PyDictObject *, PyObject *, PyObject *); PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) diff -r ad25fdb6c521 Lib/test/test_ordered_dict.py --- a/Lib/test/test_ordered_dict.py Sun Dec 20 09:37:52 2015 +0200 +++ b/Lib/test/test_ordered_dict.py Sun Dec 20 10:49:21 2015 +0200 @@ -2,6 +2,7 @@ import contextlib import copy import pickle from random import randrange, shuffle +import struct import sys import unittest from collections.abc import MutableMapping @@ -596,6 +597,37 @@ class CPythonOrderedDictTests(OrderedDic module = c_coll OrderedDict = c_coll.OrderedDict + check_sizeof = support.check_sizeof + + @support.cpython_only + def test_sizeof_exact(self): + OrderedDict = self.OrderedDict + calcsize = struct.calcsize + size = support.calcobjsize + check = self.check_sizeof + + basicsize = size('n2P' + '3PnPn2P') + calcsize('2nPn') + entrysize = calcsize('n2P') + calcsize('P') + nodesize = calcsize('Pn2P') + + od = OrderedDict() + check(od, basicsize + 8*entrysize) + od.x = 1 + check(od, basicsize + 8*entrysize) + od.update([(i, i) for i in range(3)]) + check(od, basicsize + 8*entrysize + 3*nodesize) + od.update([(i, i) for i in range(3, 10)]) + check(od, basicsize + 16*entrysize + 10*nodesize) + + check(od.keys(), size('P')) + check(od.items(), size('P')) + check(od.values(), size('P')) + + itersize = size('iP2n2P') + check(iter(od), itersize) + check(iter(od.keys()), itersize) + check(iter(od.items()), itersize) + check(iter(od.values()), itersize) def test_key_change_during_iteration(self): OrderedDict = self.OrderedDict diff -r ad25fdb6c521 Objects/dictobject.c --- a/Objects/dictobject.c Sun Dec 20 09:37:52 2015 +0200 +++ b/Objects/dictobject.c Sun Dec 20 10:49:21 2015 +0200 @@ -2554,7 +2554,7 @@ dict_tp_clear(PyObject *op) static PyObject *dictiter_new(PyDictObject *, PyTypeObject *); -PyObject * +Py_ssize_t _PyDict_SizeOf(PyDictObject *mp) { Py_ssize_t size, res; @@ -2567,7 +2567,7 @@ PyObject * in the type object. */ if (mp->ma_keys->dk_refcnt == 1) res += sizeof(PyDictKeysObject) + (size-1) * sizeof(PyDictKeyEntry); - return PyLong_FromSsize_t(res); + return res; } Py_ssize_t @@ -2576,6 +2576,12 @@ Py_ssize_t return sizeof(PyDictKeysObject) + (DK_SIZE(keys)-1) * sizeof(PyDictKeyEntry); } +PyObject * +dict_sizeof(PyDictObject *mp) +{ + return PyLong_FromSsize_t(_PyDict_SizeOf(mp)); +} + PyDoc_STRVAR(getitem__doc__, "x.__getitem__(y) <==> x[y]"); PyDoc_STRVAR(sizeof__doc__, @@ -2623,7 +2629,7 @@ static PyMethodDef mapp_methods[] = { DICT___CONTAINS___METHODDEF {"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST, getitem__doc__}, - {"__sizeof__", (PyCFunction)_PyDict_SizeOf, METH_NOARGS, + {"__sizeof__", (PyCFunction)dict_sizeof, METH_NOARGS, sizeof__doc__}, {"get", (PyCFunction)dict_get, METH_VARARGS, get__doc__}, diff -r ad25fdb6c521 Objects/odictobject.c --- a/Objects/odictobject.c Sun Dec 20 09:37:52 2015 +0200 +++ b/Objects/odictobject.c Sun Dec 20 10:49:21 2015 +0200 @@ -940,27 +940,7 @@ PyDoc_STRVAR(odict_sizeof__doc__, ""); static PyObject * odict_sizeof(PyODictObject *od) { - PyObject *pylong; - Py_ssize_t res, temp; - - pylong = _PyDict_SizeOf((PyDictObject *)od); - if (pylong == NULL) - return NULL; - res = PyLong_AsSsize_t(pylong); - Py_DECREF(pylong); - if (res == -1 && PyErr_Occurred()) - return NULL; - - /* instance dict */ - pylong = _PyDict_SizeOf((PyDictObject *)od->od_inst_dict); - if (pylong == NULL) - return NULL; - temp = PyLong_AsSsize_t(pylong); - Py_DECREF(pylong); - if (temp == -1 && PyErr_Occurred()) - return NULL; - res += temp; - + Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od); res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od); /* od_fast_nodes */ if (!_odict_EMPTY(od)) { res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */