Merge from 3.6.
This commit is contained in:
commit
1aa85a9eea
|
@ -10,6 +10,8 @@ What's New in Python 3.7.0 alpha 1
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #28183: Optimize and cleanup dict iteration.
|
||||||
|
|
||||||
- Issue #26081: Added C implementation of asyncio.Future.
|
- Issue #26081: Added C implementation of asyncio.Future.
|
||||||
Original patch by Yury Selivanov.
|
Original patch by Yury Selivanov.
|
||||||
|
|
||||||
|
|
|
@ -1690,43 +1690,56 @@ PyDict_Clear(PyObject *op)
|
||||||
assert(_PyDict_CheckConsistency(mp));
|
assert(_PyDict_CheckConsistency(mp));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Returns -1 if no more items (or op is not a dict),
|
/* Internal version of PyDict_Next that returns a hash value in addition
|
||||||
* index of item otherwise. Stores value in pvalue
|
* to the key and value.
|
||||||
|
* Return 1 on success, return 0 when the reached the end of the dictionary
|
||||||
|
* (or if op is not a dictionary)
|
||||||
*/
|
*/
|
||||||
static inline Py_ssize_t
|
int
|
||||||
dict_next(PyObject *op, Py_ssize_t i, PyObject **pvalue)
|
_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
|
||||||
|
PyObject **pvalue, Py_hash_t *phash)
|
||||||
{
|
{
|
||||||
Py_ssize_t n;
|
Py_ssize_t i, n;
|
||||||
PyDictObject *mp;
|
PyDictObject *mp;
|
||||||
PyObject **value_ptr = NULL;
|
PyDictKeyEntry *entry_ptr;
|
||||||
|
PyObject *value;
|
||||||
|
|
||||||
if (!PyDict_Check(op))
|
if (!PyDict_Check(op))
|
||||||
return -1;
|
return 0;
|
||||||
mp = (PyDictObject *)op;
|
mp = (PyDictObject *)op;
|
||||||
if (i < 0)
|
i = *ppos;
|
||||||
return -1;
|
|
||||||
|
|
||||||
n = mp->ma_keys->dk_nentries;
|
n = mp->ma_keys->dk_nentries;
|
||||||
|
if ((size_t)i >= (size_t)n)
|
||||||
|
return 0;
|
||||||
if (mp->ma_values) {
|
if (mp->ma_values) {
|
||||||
for (; i < n; i++) {
|
PyObject **value_ptr = &mp->ma_values[i];
|
||||||
value_ptr = &mp->ma_values[i];
|
while (i < n && *value_ptr == NULL) {
|
||||||
if (*value_ptr != NULL)
|
value_ptr++;
|
||||||
break;
|
i++;
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
PyDictKeyEntry *ep0 = DK_ENTRIES(mp->ma_keys);
|
|
||||||
for (; i < n; i++) {
|
|
||||||
value_ptr = &ep0[i].me_value;
|
|
||||||
if (*value_ptr != NULL)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (i >= n)
|
if (i >= n)
|
||||||
return -1;
|
return 0;
|
||||||
|
entry_ptr = &DK_ENTRIES(mp->ma_keys)[i];
|
||||||
|
value = *value_ptr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
entry_ptr = &DK_ENTRIES(mp->ma_keys)[i];
|
||||||
|
while (i < n && entry_ptr->me_value == NULL) {
|
||||||
|
entry_ptr++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i >= n)
|
||||||
|
return 0;
|
||||||
|
value = entry_ptr->me_value;
|
||||||
|
}
|
||||||
|
*ppos = i+1;
|
||||||
|
if (pkey)
|
||||||
|
*pkey = entry_ptr->me_key;
|
||||||
|
if (phash)
|
||||||
|
*phash = entry_ptr->me_hash;
|
||||||
if (pvalue)
|
if (pvalue)
|
||||||
*pvalue = *value_ptr;
|
*pvalue = value;
|
||||||
return i;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1739,6 +1752,9 @@ dict_next(PyObject *op, Py_ssize_t i, PyObject **pvalue)
|
||||||
* Refer to borrowed references in key and value.
|
* Refer to borrowed references in key and value.
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
|
* Return 1 on success, return 0 when the reached the end of the dictionary
|
||||||
|
* (or if op is not a dictionary)
|
||||||
|
*
|
||||||
* CAUTION: In general, it isn't safe to use PyDict_Next in a loop that
|
* CAUTION: In general, it isn't safe to use PyDict_Next in a loop that
|
||||||
* mutates the dict. One exception: it is safe if the loop merely changes
|
* mutates the dict. One exception: it is safe if the loop merely changes
|
||||||
* the values associated with the keys (but doesn't insert new keys or
|
* the values associated with the keys (but doesn't insert new keys or
|
||||||
|
@ -1747,36 +1763,7 @@ dict_next(PyObject *op, Py_ssize_t i, PyObject **pvalue)
|
||||||
int
|
int
|
||||||
PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
|
PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey, PyObject **pvalue)
|
||||||
{
|
{
|
||||||
PyDictObject *mp = (PyDictObject*)op;
|
return _PyDict_Next(op, ppos, pkey, pvalue, NULL);
|
||||||
Py_ssize_t i = dict_next(op, *ppos, pvalue);
|
|
||||||
if (i < 0)
|
|
||||||
return 0;
|
|
||||||
mp = (PyDictObject *)op;
|
|
||||||
*ppos = i+1;
|
|
||||||
if (pkey)
|
|
||||||
*pkey = DK_ENTRIES(mp->ma_keys)[i].me_key;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Internal version of PyDict_Next that returns a hash value in addition
|
|
||||||
* to the key and value.
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
_PyDict_Next(PyObject *op, Py_ssize_t *ppos, PyObject **pkey,
|
|
||||||
PyObject **pvalue, Py_hash_t *phash)
|
|
||||||
{
|
|
||||||
PyDictObject *mp;
|
|
||||||
PyDictKeyEntry *ep0;
|
|
||||||
Py_ssize_t i = dict_next(op, *ppos, pvalue);
|
|
||||||
if (i < 0)
|
|
||||||
return 0;
|
|
||||||
mp = (PyDictObject *)op;
|
|
||||||
ep0 = DK_ENTRIES(mp->ma_keys);
|
|
||||||
*ppos = i+1;
|
|
||||||
*phash = ep0[i].me_hash;
|
|
||||||
if (pkey)
|
|
||||||
*pkey = ep0[i].me_key;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Internal version of dict.pop(). */
|
/* Internal version of dict.pop(). */
|
||||||
|
@ -3352,13 +3339,13 @@ static PyMethodDef dictiter_methods[] = {
|
||||||
{NULL, NULL} /* sentinel */
|
{NULL, NULL} /* sentinel */
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *dictiter_iternextkey(dictiterobject *di)
|
static PyObject*
|
||||||
|
dictiter_iternextkey(dictiterobject *di)
|
||||||
{
|
{
|
||||||
PyObject *key;
|
PyObject *key;
|
||||||
Py_ssize_t i, n, offset;
|
Py_ssize_t i, n;
|
||||||
PyDictKeysObject *k;
|
PyDictKeysObject *k;
|
||||||
PyDictObject *d = di->di_dict;
|
PyDictObject *d = di->di_dict;
|
||||||
PyObject **value_ptr;
|
|
||||||
|
|
||||||
if (d == NULL)
|
if (d == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -3372,27 +3359,30 @@ static PyObject *dictiter_iternextkey(dictiterobject *di)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = di->di_pos;
|
i = di->di_pos;
|
||||||
if (i < 0)
|
|
||||||
goto fail;
|
|
||||||
k = d->ma_keys;
|
k = d->ma_keys;
|
||||||
|
n = k->dk_nentries;
|
||||||
if (d->ma_values) {
|
if (d->ma_values) {
|
||||||
value_ptr = &d->ma_values[i];
|
PyObject **value_ptr = &d->ma_values[i];
|
||||||
offset = sizeof(PyObject *);
|
while (i < n && *value_ptr == NULL) {
|
||||||
}
|
value_ptr++;
|
||||||
else {
|
|
||||||
value_ptr = &DK_ENTRIES(k)[i].me_value;
|
|
||||||
offset = sizeof(PyDictKeyEntry);
|
|
||||||
}
|
|
||||||
n = k->dk_nentries - 1;
|
|
||||||
while (i <= n && *value_ptr == NULL) {
|
|
||||||
value_ptr = (PyObject **)(((char *)value_ptr) + offset);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
di->di_pos = i+1;
|
if (i >= n)
|
||||||
if (i > n)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
di->len--;
|
|
||||||
key = DK_ENTRIES(k)[i].me_key;
|
key = DK_ENTRIES(k)[i].me_key;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyDictKeyEntry *entry_ptr = &DK_ENTRIES(k)[i];
|
||||||
|
while (i < n && entry_ptr->me_value == NULL) {
|
||||||
|
entry_ptr++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i >= n)
|
||||||
|
goto fail;
|
||||||
|
key = entry_ptr->me_key;
|
||||||
|
}
|
||||||
|
di->di_pos = i+1;
|
||||||
|
di->len--;
|
||||||
Py_INCREF(key);
|
Py_INCREF(key);
|
||||||
return key;
|
return key;
|
||||||
|
|
||||||
|
@ -3435,12 +3425,12 @@ PyTypeObject PyDictIterKey_Type = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *dictiter_iternextvalue(dictiterobject *di)
|
static PyObject *
|
||||||
|
dictiter_iternextvalue(dictiterobject *di)
|
||||||
{
|
{
|
||||||
PyObject *value;
|
PyObject *value;
|
||||||
Py_ssize_t i, n, offset;
|
Py_ssize_t i, n;
|
||||||
PyDictObject *d = di->di_dict;
|
PyDictObject *d = di->di_dict;
|
||||||
PyObject **value_ptr;
|
|
||||||
|
|
||||||
if (d == NULL)
|
if (d == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -3454,26 +3444,29 @@ static PyObject *dictiter_iternextvalue(dictiterobject *di)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = di->di_pos;
|
i = di->di_pos;
|
||||||
n = d->ma_keys->dk_nentries - 1;
|
n = d->ma_keys->dk_nentries;
|
||||||
if (i < 0 || i > n)
|
|
||||||
goto fail;
|
|
||||||
if (d->ma_values) {
|
if (d->ma_values) {
|
||||||
value_ptr = &d->ma_values[i];
|
PyObject **value_ptr = &d->ma_values[i];
|
||||||
offset = sizeof(PyObject *);
|
while (i < n && *value_ptr == NULL) {
|
||||||
|
value_ptr++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i >= n)
|
||||||
|
goto fail;
|
||||||
|
value = *value_ptr;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
value_ptr = &DK_ENTRIES(d->ma_keys)[i].me_value;
|
PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
|
||||||
offset = sizeof(PyDictKeyEntry);
|
while (i < n && entry_ptr->me_value == NULL) {
|
||||||
}
|
entry_ptr++;
|
||||||
while (i <= n && *value_ptr == NULL) {
|
|
||||||
value_ptr = (PyObject **)(((char *)value_ptr) + offset);
|
|
||||||
i++;
|
i++;
|
||||||
if (i > n)
|
}
|
||||||
|
if (i >= n)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
value = entry_ptr->me_value;
|
||||||
}
|
}
|
||||||
di->di_pos = i+1;
|
di->di_pos = i+1;
|
||||||
di->len--;
|
di->len--;
|
||||||
value = *value_ptr;
|
|
||||||
Py_INCREF(value);
|
Py_INCREF(value);
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
|
@ -3516,12 +3509,12 @@ PyTypeObject PyDictIterValue_Type = {
|
||||||
0,
|
0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static PyObject *dictiter_iternextitem(dictiterobject *di)
|
static PyObject *
|
||||||
|
dictiter_iternextitem(dictiterobject *di)
|
||||||
{
|
{
|
||||||
PyObject *key, *value, *result = di->di_result;
|
PyObject *key, *value, *result = di->di_result;
|
||||||
Py_ssize_t i, n, offset;
|
Py_ssize_t i, n;
|
||||||
PyDictObject *d = di->di_dict;
|
PyDictObject *d = di->di_dict;
|
||||||
PyObject **value_ptr;
|
|
||||||
|
|
||||||
if (d == NULL)
|
if (d == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -3535,37 +3528,41 @@ static PyObject *dictiter_iternextitem(dictiterobject *di)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = di->di_pos;
|
i = di->di_pos;
|
||||||
if (i < 0)
|
n = d->ma_keys->dk_nentries;
|
||||||
goto fail;
|
|
||||||
n = d->ma_keys->dk_nentries - 1;
|
|
||||||
if (d->ma_values) {
|
if (d->ma_values) {
|
||||||
value_ptr = &d->ma_values[i];
|
PyObject **value_ptr = &d->ma_values[i];
|
||||||
offset = sizeof(PyObject *);
|
while (i < n && *value_ptr == NULL) {
|
||||||
}
|
value_ptr++;
|
||||||
else {
|
|
||||||
value_ptr = &DK_ENTRIES(d->ma_keys)[i].me_value;
|
|
||||||
offset = sizeof(PyDictKeyEntry);
|
|
||||||
}
|
|
||||||
while (i <= n && *value_ptr == NULL) {
|
|
||||||
value_ptr = (PyObject **)(((char *)value_ptr) + offset);
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
di->di_pos = i+1;
|
if (i >= n)
|
||||||
if (i > n)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
|
key = DK_ENTRIES(d->ma_keys)[i].me_key;
|
||||||
|
value = *value_ptr;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PyDictKeyEntry *entry_ptr = &DK_ENTRIES(d->ma_keys)[i];
|
||||||
|
while (i < n && entry_ptr->me_value == NULL) {
|
||||||
|
entry_ptr++;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (i >= n)
|
||||||
|
goto fail;
|
||||||
|
key = entry_ptr->me_key;
|
||||||
|
value = entry_ptr->me_value;
|
||||||
|
}
|
||||||
|
di->di_pos = i+1;
|
||||||
|
di->len--;
|
||||||
if (result->ob_refcnt == 1) {
|
if (result->ob_refcnt == 1) {
|
||||||
Py_INCREF(result);
|
Py_INCREF(result);
|
||||||
Py_DECREF(PyTuple_GET_ITEM(result, 0));
|
Py_DECREF(PyTuple_GET_ITEM(result, 0));
|
||||||
Py_DECREF(PyTuple_GET_ITEM(result, 1));
|
Py_DECREF(PyTuple_GET_ITEM(result, 1));
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
result = PyTuple_New(2);
|
result = PyTuple_New(2);
|
||||||
if (result == NULL)
|
if (result == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
di->len--;
|
|
||||||
key = DK_ENTRIES(d->ma_keys)[i].me_key;
|
|
||||||
value = *value_ptr;
|
|
||||||
Py_INCREF(key);
|
Py_INCREF(key);
|
||||||
Py_INCREF(value);
|
Py_INCREF(value);
|
||||||
PyTuple_SET_ITEM(result, 0, key); /* steals reference */
|
PyTuple_SET_ITEM(result, 0, key); /* steals reference */
|
||||||
|
|
Loading…
Reference in New Issue