]> granicus.if.org Git - python/commitdiff
Issue #25914: Fixed and simplified OrderedDict.__sizeof__.
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 22 Dec 2015 06:16:18 +0000 (08:16 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Tue, 22 Dec 2015 06:16:18 +0000 (08:16 +0200)
Include/dictobject.h
Lib/test/test_ordered_dict.py
Misc/NEWS
Objects/dictobject.c
Objects/odictobject.c

index 80bd33029491804665c9bff2100f00d59427fb14..ba90aaf676c55cfb47786642f84424096b8b9f88 100644 (file)
@@ -98,7 +98,7 @@ PyAPI_FUNC(PyObject *) _PyDict_NewPresized(Py_ssize_t minused);
 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)
index 4b092279692c212731a76bed89edc2086c97229f..9d6c6ffa221814eef8d79bb76ec8fdf2bb0b7f9a 100644 (file)
@@ -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(OrderedDictTests, unittest.TestCase):
 
     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
index ef37f5f000d6d26a76153091806cfcec8eb853df..3257aa4a033759aac223571da19b6251d46010ea 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -28,6 +28,8 @@ Core and Builtins
 Library
 -------
 
+- Issue #25914: Fixed and simplified OrderedDict.__sizeof__.
+
 - Issue #25902: Fixed various refcount issues in ElementTree iteration.
 
 - Issue #25717: Restore the previous behaviour of tolerating most fstat()
index 3e6e112ba0431529452a694111ed9327a756bc9a..f53cd407962ddb8d455b64c9b580535f73d203d7 100644 (file)
@@ -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 @@ _PyDict_SizeOf(PyDictObject *mp)
        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 @@ _PyDict_KeysSize(PyDictKeysObject *keys)
     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__},
index 4e51f4d1475011d638404ccd0ef6cddfa61a0c22..c15b408dc24041188ed138f3d6f0343411dd5690 100644 (file)
@@ -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 */