mirror of https://github.com/python/cpython
Issue #24362: Simplify the C OrderedDict fast nodes resize logic.
This commit is contained in:
parent
24ac877eed
commit
4c72918a59
|
@ -23,6 +23,8 @@ Library
|
||||||
|
|
||||||
- Issue #24368: Support keyword arguments in OrderedDict methods.
|
- Issue #24368: Support keyword arguments in OrderedDict methods.
|
||||||
|
|
||||||
|
- Issue #24362: Simplify the C OrderedDict fast nodes resize logic.
|
||||||
|
|
||||||
|
|
||||||
What's New in Python 3.5.0 beta 2?
|
What's New in Python 3.5.0 beta 2?
|
||||||
==================================
|
==================================
|
||||||
|
|
|
@ -503,12 +503,15 @@ struct _odictobject {
|
||||||
|
|
||||||
struct _odictnode {
|
struct _odictnode {
|
||||||
PyObject *key;
|
PyObject *key;
|
||||||
|
Py_hash_t hash;
|
||||||
_ODictNode *next;
|
_ODictNode *next;
|
||||||
_ODictNode *prev;
|
_ODictNode *prev;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define _odictnode_KEY(node) \
|
#define _odictnode_KEY(node) \
|
||||||
(node->key)
|
(node->key)
|
||||||
|
#define _odictnode_HASH(node) \
|
||||||
|
(node->hash)
|
||||||
/* borrowed reference */
|
/* borrowed reference */
|
||||||
#define _odictnode_VALUE(node, od) \
|
#define _odictnode_VALUE(node, od) \
|
||||||
PyODict_GetItemWithError((PyObject *)od, _odictnode_KEY(node))
|
PyODict_GetItemWithError((PyObject *)od, _odictnode_KEY(node))
|
||||||
|
@ -523,8 +526,6 @@ struct _odictnode {
|
||||||
for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
|
for (node = _odict_FIRST(od); node != NULL; node = _odictnode_NEXT(node))
|
||||||
|
|
||||||
|
|
||||||
static Py_ssize_t _odict_get_index(PyODictObject *, PyObject *); /* forward */
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_odict_free_fast_nodes(PyODictObject *od) {
|
_odict_free_fast_nodes(PyODictObject *od) {
|
||||||
if (od->od_fast_nodes) {
|
if (od->od_fast_nodes) {
|
||||||
|
@ -532,9 +533,25 @@ _odict_free_fast_nodes(PyODictObject *od) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the index into the hash table, regardless of a valid node. */
|
||||||
|
static Py_ssize_t
|
||||||
|
_odict_get_index_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
|
||||||
|
{
|
||||||
|
PyObject **value_addr = NULL;
|
||||||
|
PyDictKeyEntry *ep;
|
||||||
|
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
|
||||||
|
|
||||||
|
ep = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr);
|
||||||
|
if (ep == NULL)
|
||||||
|
return -1;
|
||||||
|
/* We use pointer arithmetic to get the entry's index into the table. */
|
||||||
|
return ep - keys->dk_entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Replace od->od_fast_nodes with a new table matching the size of dict's. */
|
||||||
static int
|
static int
|
||||||
_odict_resize(PyODictObject *od) {
|
_odict_resize(PyODictObject *od) {
|
||||||
Py_ssize_t size, prev_size, i;
|
Py_ssize_t size, i;
|
||||||
_ODictNode **fast_nodes, *node;
|
_ODictNode **fast_nodes, *node;
|
||||||
|
|
||||||
/* Initialize a new "fast nodes" table. */
|
/* Initialize a new "fast nodes" table. */
|
||||||
|
@ -548,27 +565,20 @@ _odict_resize(PyODictObject *od) {
|
||||||
fast_nodes[i] = NULL;
|
fast_nodes[i] = NULL;
|
||||||
|
|
||||||
/* Copy the current nodes into the table. */
|
/* Copy the current nodes into the table. */
|
||||||
prev_size = od->od_size;
|
|
||||||
od->od_size = size;
|
|
||||||
_odict_FOREACH(od, node) {
|
_odict_FOREACH(od, node) {
|
||||||
assert(node != NULL);
|
i = _odict_get_index_hash(od, _odictnode_KEY(node),
|
||||||
i = _odict_get_index(od, _odictnode_KEY(node));
|
_odictnode_HASH(node));
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
od->od_size = prev_size;
|
|
||||||
PyMem_FREE(fast_nodes);
|
PyMem_FREE(fast_nodes);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fast_nodes[i] = node;
|
fast_nodes[i] = node;
|
||||||
}
|
}
|
||||||
if (size != ((PyDictObject *)od)->ma_keys->dk_size) {
|
|
||||||
/* If _odict_get_index triggered a resize then we are already done. */
|
|
||||||
PyMem_FREE(fast_nodes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Replace the old fast nodes table. */
|
/* Replace the old fast nodes table. */
|
||||||
_odict_free_fast_nodes(od);
|
_odict_free_fast_nodes(od);
|
||||||
od->od_fast_nodes = fast_nodes;
|
od->od_fast_nodes = fast_nodes;
|
||||||
|
od->od_size = size;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -577,32 +587,22 @@ static Py_ssize_t
|
||||||
_odict_get_index(PyODictObject *od, PyObject *key)
|
_odict_get_index(PyODictObject *od, PyObject *key)
|
||||||
{
|
{
|
||||||
Py_hash_t hash;
|
Py_hash_t hash;
|
||||||
PyObject **value_addr = NULL;
|
PyDictKeysObject *keys;
|
||||||
PyDictKeyEntry *ep;
|
|
||||||
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
|
|
||||||
|
|
||||||
assert(key != NULL);
|
assert(key != NULL);
|
||||||
do {
|
hash = PyObject_Hash(key);
|
||||||
/* Ensure od_fast_nodes and dk_entries are in sync. */
|
if (hash == -1)
|
||||||
if (keys->dk_size != od->od_size) {
|
|
||||||
int resize_res = _odict_resize(od);
|
|
||||||
if (resize_res < 0)
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now get the index */
|
|
||||||
hash = PyObject_Hash(key);
|
|
||||||
if (hash == -1)
|
|
||||||
return -1;
|
|
||||||
/* May have resized during the PyObject_Hash() call. */
|
|
||||||
keys = ((PyDictObject *)od)->ma_keys;
|
|
||||||
} while (keys->dk_size != od->od_size);
|
|
||||||
|
|
||||||
ep = (keys->dk_lookup)((PyDictObject *)od, key, hash, &value_addr);
|
|
||||||
if (ep == NULL)
|
|
||||||
return -1;
|
return -1;
|
||||||
/* We use pointer arithmetic to get the entry's index into the table. */
|
keys = ((PyDictObject *)od)->ma_keys;
|
||||||
return ep - keys->dk_entries;
|
|
||||||
|
/* Ensure od_fast_nodes and dk_entries are in sync. */
|
||||||
|
if (keys->dk_size != od->od_size) {
|
||||||
|
int resize_res = _odict_resize(od);
|
||||||
|
if (resize_res < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _odict_get_index_hash(od, key, hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -665,10 +665,15 @@ _odict_add_tail(PyODictObject *od, _ODictNode *node)
|
||||||
static int
|
static int
|
||||||
_odict_add_new_node(PyODictObject *od, PyObject *key)
|
_odict_add_new_node(PyODictObject *od, PyObject *key)
|
||||||
{
|
{
|
||||||
|
Py_hash_t hash;
|
||||||
Py_ssize_t i;
|
Py_ssize_t i;
|
||||||
_ODictNode *node;
|
_ODictNode *node;
|
||||||
|
|
||||||
Py_INCREF(key);
|
Py_INCREF(key);
|
||||||
|
hash = PyObject_Hash(key);
|
||||||
|
if (hash == -1)
|
||||||
|
return -1;
|
||||||
|
|
||||||
i = _odict_get_index(od, key);
|
i = _odict_get_index(od, key);
|
||||||
if (i < 0) {
|
if (i < 0) {
|
||||||
if (!PyErr_Occurred())
|
if (!PyErr_Occurred())
|
||||||
|
@ -691,6 +696,7 @@ _odict_add_new_node(PyODictObject *od, PyObject *key)
|
||||||
}
|
}
|
||||||
|
|
||||||
_odictnode_KEY(node) = key;
|
_odictnode_KEY(node) = key;
|
||||||
|
_odictnode_HASH(node) = hash;
|
||||||
_odict_add_tail(od, node);
|
_odict_add_tail(od, node);
|
||||||
od->od_fast_nodes[i] = node;
|
od->od_fast_nodes[i] = node;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
Loading…
Reference in New Issue