Issue #25914: Fixed and simplified OrderedDict.__sizeof__.

This commit is contained in:
Serhiy Storchaka 2015-12-22 08:16:18 +02:00
parent 5af856404a
commit 0ce7a3a34c
5 changed files with 45 additions and 25 deletions

View File

@ -98,7 +98,7 @@ PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused);
PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp); PyAPI_FUNC(void) _PyDict_MaybeUntrack(PyObject *mp);
PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp); PyAPI_FUNC(int) _PyDict_HasOnlyStringKeys(PyObject *mp);
Py_ssize_t _PyDict_KeysSize(PyDictKeysObject *keys); 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_Pop(PyDictObject *, PyObject *, PyObject *);
PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *); PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *);
#define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL) #define _PyDict_HasSplitTable(d) ((d)->ma_values != NULL)

View File

@ -2,6 +2,7 @@ import contextlib
import copy import copy
import pickle import pickle
from random import randrange, shuffle from random import randrange, shuffle
import struct
import sys import sys
import unittest import unittest
from collections.abc import MutableMapping from collections.abc import MutableMapping
@ -596,6 +597,37 @@ class CPythonOrderedDictTests(OrderedDictTests, unittest.TestCase):
module = c_coll module = c_coll
OrderedDict = c_coll.OrderedDict 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): def test_key_change_during_iteration(self):
OrderedDict = self.OrderedDict OrderedDict = self.OrderedDict

View File

@ -28,6 +28,8 @@ Core and Builtins
Library Library
------- -------
- Issue #25914: Fixed and simplified OrderedDict.__sizeof__.
- Issue #25902: Fixed various refcount issues in ElementTree iteration. - Issue #25902: Fixed various refcount issues in ElementTree iteration.
- Issue #25717: Restore the previous behaviour of tolerating most fstat() - Issue #25717: Restore the previous behaviour of tolerating most fstat()

View File

@ -2554,7 +2554,7 @@ dict_tp_clear(PyObject *op)
static PyObject *dictiter_new(PyDictObject *, PyTypeObject *); static PyObject *dictiter_new(PyDictObject *, PyTypeObject *);
PyObject * Py_ssize_t
_PyDict_SizeOf(PyDictObject *mp) _PyDict_SizeOf(PyDictObject *mp)
{ {
Py_ssize_t size, res; Py_ssize_t size, res;
@ -2567,7 +2567,7 @@ _PyDict_SizeOf(PyDictObject *mp)
in the type object. */ in the type object. */
if (mp->ma_keys->dk_refcnt == 1) if (mp->ma_keys->dk_refcnt == 1)
res += sizeof(PyDictKeysObject) + (size-1) * sizeof(PyDictKeyEntry); res += sizeof(PyDictKeysObject) + (size-1) * sizeof(PyDictKeyEntry);
return PyLong_FromSsize_t(res); return res;
} }
Py_ssize_t Py_ssize_t
@ -2576,6 +2576,12 @@ _PyDict_KeysSize(PyDictKeysObject *keys)
return sizeof(PyDictKeysObject) + (DK_SIZE(keys)-1) * sizeof(PyDictKeyEntry); 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(getitem__doc__, "x.__getitem__(y) <==> x[y]");
PyDoc_STRVAR(sizeof__doc__, PyDoc_STRVAR(sizeof__doc__,
@ -2623,7 +2629,7 @@ static PyMethodDef mapp_methods[] = {
DICT___CONTAINS___METHODDEF DICT___CONTAINS___METHODDEF
{"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST, {"__getitem__", (PyCFunction)dict_subscript, METH_O | METH_COEXIST,
getitem__doc__}, getitem__doc__},
{"__sizeof__", (PyCFunction)_PyDict_SizeOf, METH_NOARGS, {"__sizeof__", (PyCFunction)dict_sizeof, METH_NOARGS,
sizeof__doc__}, sizeof__doc__},
{"get", (PyCFunction)dict_get, METH_VARARGS, {"get", (PyCFunction)dict_get, METH_VARARGS,
get__doc__}, get__doc__},

View File

@ -940,27 +940,7 @@ PyDoc_STRVAR(odict_sizeof__doc__, "");
static PyObject * static PyObject *
odict_sizeof(PyODictObject *od) odict_sizeof(PyODictObject *od)
{ {
PyObject *pylong; Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
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;
res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od); /* od_fast_nodes */ res += sizeof(_ODictNode *) * _odict_FAST_SIZE(od); /* od_fast_nodes */
if (!_odict_EMPTY(od)) { if (!_odict_EMPTY(od)) {
res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */ res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */