#include "Python.h"
#include "pycore_abstract.h"
#include "pycore_interp.h"
#include "pycore_list.h"
#include "pycore_long.h"
#include "pycore_object.h"
#include "pycore_tuple.h"
#include <stddef.h>
#include "clinic/listobject.c.h"
_Py_DECLARE_STR(list_err, "list index out of range");
#if PyList_MAXFREELIST > 0
static struct _Py_list_state *
get_list_state(void)
{
PyInterpreterState *interp = _PyInterpreterState_GET();
return &interp->list;
}
#endif
static int
list_resize(PyListObject *self, Py_ssize_t newsize)
{
PyObject **items;
size_t new_allocated, num_allocated_bytes;
Py_ssize_t allocated = self->allocated;
if (allocated >= newsize && newsize >= (allocated >> 1)) {
assert(self->ob_item != NULL || newsize == 0);
Py_SET_SIZE(self, newsize);
return 0;
}
new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3;
if (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize))
new_allocated = ((size_t)newsize + 3) & ~(size_t)3;
if (newsize == 0)
new_allocated = 0;
if (new_allocated <= (size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)) {
num_allocated_bytes = new_allocated * sizeof(PyObject *);
items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes);
}
else {
items = NULL;
}
if (items == NULL) {
PyErr_NoMemory();
return -1;
}
self->ob_item = items;
Py_SET_SIZE(self, newsize);
self->allocated = new_allocated;
return 0;
}
static int
list_preallocate_exact(PyListObject *self, Py_ssize_t size)
{
assert(self->ob_item == NULL);
assert(size > 0);
size = (size + 1) & ~(size_t)1;
PyObject **items = PyMem_New(PyObject*, size);
if (items == NULL) {
PyErr_NoMemory();
return -1;
}
self->ob_item = items;
self->allocated = size;
return 0;
}
void
_PyList_ClearFreeList(PyInterpreterState *interp)
{
#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = &interp->list;
while (state->numfree) {
PyListObject *op = state->free_list[--state->numfree];
assert(PyList_CheckExact(op));
PyObject_GC_Del(op);
}
#endif
}
void
_PyList_Fini(PyInterpreterState *interp)
{
_PyList_ClearFreeList(interp);
#if defined(Py_DEBUG) && PyList_MAXFREELIST > 0
struct _Py_list_state *state = &interp->list;
state->numfree = -1;
#endif
}
void
_PyList_DebugMallocStats(FILE *out)
{
#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = get_list_state();
_PyDebugAllocatorStats(out,
"free PyListObject",
state->numfree, sizeof(PyListObject));
#endif
}
PyObject *
PyList_New(Py_ssize_t size)
{
PyListObject *op;
if (size < 0) {
PyErr_BadInternalCall();
return NULL;
}
#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = get_list_state();
#ifdef Py_DEBUG
assert(state->numfree != -1);
#endif
if (PyList_MAXFREELIST && state->numfree) {
state->numfree--;
op = state->free_list[state->numfree];
OBJECT_STAT_INC(from_freelist);
_Py_NewReference((PyObject *)op);
}
else
#endif
{
op = PyObject_GC_New(PyListObject, &PyList_Type);
if (op == NULL) {
return NULL;
}
}
if (size <= 0) {
op->ob_item = NULL;
}
else {
op->ob_item = (PyObject **) PyMem_Calloc(size, sizeof(PyObject *));
if (op->ob_item == NULL) {
Py_DECREF(op);
return PyErr_NoMemory();
}
}
Py_SET_SIZE(op, size);
op->allocated = size;
_PyObject_GC_TRACK(op);
return (PyObject *) op;
}
static PyObject *
list_new_prealloc(Py_ssize_t size)
{
assert(size > 0);
PyListObject *op = (PyListObject *) PyList_New(0);
if (op == NULL) {
return NULL;
}
assert(op->ob_item == NULL);
op->ob_item = PyMem_New(PyObject *, size);
if (op->ob_item == NULL) {
Py_DECREF(op);
return PyErr_NoMemory();
}
op->allocated = size;
return (PyObject *) op;
}
Py_ssize_t
PyList_Size(PyObject *op)
{
if (!PyList_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
else
return Py_SIZE(op);
}
static inline int
valid_index(Py_ssize_t i, Py_ssize_t limit)
{
return (size_t) i < (size_t) limit;
}
PyObject *
PyList_GetItem(PyObject *op, Py_ssize_t i)
{
if (!PyList_Check(op)) {
PyErr_BadInternalCall();
return NULL;
}
if (!valid_index(i, Py_SIZE(op))) {
_Py_DECLARE_STR(list_err, "list index out of range");
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
return NULL;
}
return ((PyListObject *)op) -> ob_item[i];
}
int
PyList_SetItem(PyObject *op, Py_ssize_t i,
PyObject *newitem)
{
PyObject **p;
if (!PyList_Check(op)) {
Py_XDECREF(newitem);
PyErr_BadInternalCall();
return -1;
}
if (!valid_index(i, Py_SIZE(op))) {
Py_XDECREF(newitem);
PyErr_SetString(PyExc_IndexError,
"list assignment index out of range");
return -1;
}
p = ((PyListObject *)op) -> ob_item + i;
Py_XSETREF(*p, newitem);
return 0;
}
static int
ins1(PyListObject *self, Py_ssize_t where, PyObject *v)
{
Py_ssize_t i, n = Py_SIZE(self);
PyObject **items;
if (v == NULL) {
PyErr_BadInternalCall();
return -1;
}
assert((size_t)n + 1 < PY_SSIZE_T_MAX);
if (list_resize(self, n+1) < 0)
return -1;
if (where < 0) {
where += n;
if (where < 0)
where = 0;
}
if (where > n)
where = n;
items = self->ob_item;
for (i = n; --i >= where; )
items[i+1] = items[i];
items[where] = Py_NewRef(v);
return 0;
}
int
PyList_Insert(PyObject *op, Py_ssize_t where, PyObject *newitem)
{
if (!PyList_Check(op)) {
PyErr_BadInternalCall();
return -1;
}
return ins1((PyListObject *)op, where, newitem);
}
int
_PyList_AppendTakeRefListResize(PyListObject *self, PyObject *newitem)
{
Py_ssize_t len = PyList_GET_SIZE(self);
assert(self->allocated == -1 || self->allocated == len);
if (list_resize(self, len + 1) < 0) {
Py_DECREF(newitem);
return -1;
}
PyList_SET_ITEM(self, len, newitem);
return 0;
}
int
PyList_Append(PyObject *op, PyObject *newitem)
{
if (PyList_Check(op) && (newitem != NULL)) {
return _PyList_AppendTakeRef((PyListObject *)op, Py_NewRef(newitem));
}
PyErr_BadInternalCall();
return -1;
}
static void
list_dealloc(PyListObject *op)
{
Py_ssize_t i;
PyObject_GC_UnTrack(op);
Py_TRASHCAN_BEGIN(op, list_dealloc)
if (op->ob_item != NULL) {
i = Py_SIZE(op);
while (--i >= 0) {
Py_XDECREF(op->ob_item[i]);
}
PyMem_Free(op->ob_item);
}
#if PyList_MAXFREELIST > 0
struct _Py_list_state *state = get_list_state();
#ifdef Py_DEBUG
assert(state->numfree != -1);
#endif
if (state->numfree < PyList_MAXFREELIST && PyList_CheckExact(op)) {
state->free_list[state->numfree++] = op;
OBJECT_STAT_INC(to_freelist);
}
else
#endif
{
Py_TYPE(op)->tp_free((PyObject *)op);
}
Py_TRASHCAN_END
}
static PyObject *
list_repr(PyListObject *v)
{
Py_ssize_t i;
PyObject *s;
_PyUnicodeWriter writer;
if (Py_SIZE(v) == 0) {
return PyUnicode_FromString("[]");
}
i = Py_ReprEnter((PyObject*)v);
if (i != 0) {
return i > 0 ? PyUnicode_FromString("[...]") : NULL;
}
_PyUnicodeWriter_Init(&writer);
writer.overallocate = 1;
writer.min_length = 1 + 1 + (2 + 1) * (Py_SIZE(v) - 1) + 1;
if (_PyUnicodeWriter_WriteChar(&writer, '[') < 0)
goto error;
for (i = 0; i < Py_SIZE(v); ++i) {
if (i > 0) {
if (_PyUnicodeWriter_WriteASCIIString(&writer, ", ", 2) < 0)
goto error;
}
s = PyObject_Repr(v->ob_item[i]);
if (s == NULL)
goto error;
if (_PyUnicodeWriter_WriteStr(&writer, s) < 0) {
Py_DECREF(s);
goto error;
}
Py_DECREF(s);
}
writer.overallocate = 0;
if (_PyUnicodeWriter_WriteChar(&writer, ']') < 0)
goto error;
Py_ReprLeave((PyObject *)v);
return _PyUnicodeWriter_Finish(&writer);
error:
_PyUnicodeWriter_Dealloc(&writer);
Py_ReprLeave((PyObject *)v);
return NULL;
}
static Py_ssize_t
list_length(PyListObject *a)
{
return Py_SIZE(a);
}
static int
list_contains(PyListObject *a, PyObject *el)
{
PyObject *item;
Py_ssize_t i;
int cmp;
for (i = 0, cmp = 0 ; cmp == 0 && i < Py_SIZE(a); ++i) {
item = PyList_GET_ITEM(a, i);
Py_INCREF(item);
cmp = PyObject_RichCompareBool(item, el, Py_EQ);
Py_DECREF(item);
}
return cmp;
}
static PyObject *
list_item(PyListObject *a, Py_ssize_t i)
{
if (!valid_index(i, Py_SIZE(a))) {
PyErr_SetObject(PyExc_IndexError, &_Py_STR(list_err));
return NULL;
}
return Py_NewRef(a->ob_item[i]);
}
static PyObject *
list_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
{
PyListObject *np;
PyObject **src, **dest;
Py_ssize_t i, len;
len = ihigh - ilow;
if (len <= 0) {
return PyList_New(0);
}
np = (PyListObject *) list_new_prealloc(len);
if (np == NULL)
return NULL;
src = a->ob_item + ilow;
dest = np->ob_item;
for (i = 0; i < len; i++) {
PyObject *v = src[i];
dest[i] = Py_NewRef(v);
}
Py_SET_SIZE(np, len);
return (PyObject *)np;
}
PyObject *
PyList_GetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh)
{
if (!PyList_Check(a)) {
PyErr_BadInternalCall();
return NULL;
}
if (ilow < 0) {
ilow = 0;
}
else if (ilow > Py_SIZE(a)) {
ilow = Py_SIZE(a);
}
if (ihigh < ilow) {
ihigh = ilow;
}
else if (ihigh > Py_SIZE(a)) {
ihigh = Py_SIZE(a);
}
return list_slice((PyListObject *)a, ilow, ihigh);
}
static PyObject *
list_concat(PyListObject *a, PyObject *bb)
{
Py_ssize_t size;
Py_ssize_t i;
PyObject **src, **dest;
PyListObject *np;
if (!PyList_Check(bb)) {
PyErr_Format(PyExc_TypeError,
"can only concatenate list (not \"%.200s\") to list",
Py_TYPE(bb)->tp_name);
return NULL;
}
#define b ((PyListObject *)bb)
assert((size_t)Py_SIZE(a) + (size_t)Py_SIZE(b) < PY_SSIZE_T_MAX);
size = Py_SIZE(a) + Py_SIZE(b);
if (size == 0) {
return PyList_New(0);
}
np = (PyListObject *) list_new_prealloc(size);
if (np == NULL) {
return NULL;
}
src = a->ob_item;
dest = np->ob_item;
for (i = 0; i < Py_SIZE(a); i++) {
PyObject *v = src[i];
dest[i] = Py_NewRef(v);
}
src = b->ob_item;
dest = np->ob_item + Py_SIZE(a);
for (i = 0; i < Py_SIZE(b); i++) {
PyObject *v = src[i];
dest[i] = Py_NewRef(v);
}
Py_SET_SIZE(np, size);
return (PyObject *)np;
#undef b
}
static PyObject *
list_repeat(PyListObject *a, Py_ssize_t n)
{
const Py_ssize_t input_size = Py_SIZE(a);
if (input_size == 0 || n <= 0)
return PyList_New(0);
assert(n > 0);
if (input_size > PY_SSIZE_T_MAX / n)
return PyErr_NoMemory();
Py_ssize_t output_size = input_size * n;
PyListObject *np = (PyListObject *) list_new_prealloc(output_size);
if (np == NULL)
return NULL;
PyObject **dest = np->ob_item;
if (input_size == 1) {
PyObject *elem = a->ob_item[0];
_Py_RefcntAdd(elem, n);
PyObject **dest_end = dest + output_size;
while (dest < dest_end) {
*dest++ = elem;
}
}
else {
PyObject **src = a->ob_item;
PyObject **src_end = src + input_size;
while (src < src_end) {
_Py_RefcntAdd(*src, n);
*dest++ = *src++;
}
_Py_memory_repeat((char *)np->ob_item, sizeof(PyObject *)*output_size,
sizeof(PyObject *)*input_size);
}
Py_SET_SIZE(np, output_size);
return (PyObject *) np;
}
static int
_list_clear(PyListObject *a)
{
Py_ssize_t i;
PyObject **item = a->ob_item;
if (item != NULL) {
i = Py_SIZE(a);
Py_SET_SIZE(a, 0);
a->ob_item = NULL;
a->allocated = 0;
while (--i >= 0) {
Py_XDECREF(item[i]);
}
PyMem_Free(item);
}
return 0;
}
static int
list_ass_slice(PyListObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
{
PyObject *recycle_on_stack[8];
PyObject **recycle = recycle_on_stack;
PyObject **item;
PyObject **vitem = NULL;
PyObject *v_as_SF = NULL;
Py_ssize_t n;
Py_ssize_t norig;
Py_ssize_t d;
Py_ssize_t k;
size_t s;
int result = -1;
#define b ((PyListObject *)v)
if (v == NULL)
n = 0;
else {
if (a == b) {
v = list_slice(b, 0, Py_SIZE(b));
if (v == NULL)
return result;
result = list_ass_slice(a, ilow, ihigh, v);
Py_DECREF(v);
return result;
}
v_as_SF = PySequence_Fast(v, "can only assign an iterable");
if(v_as_SF == NULL)
goto Error;
n = PySequence_Fast_GET_SIZE(v_as_SF);
vitem = PySequence_Fast_ITEMS(v_as_SF);
}
if (ilow < 0)
ilow = 0;
else if (ilow > Py_SIZE(a))
ilow = Py_SIZE(a);
if (ihigh < ilow)
ihigh = ilow;
else if (ihigh > Py_SIZE(a))
ihigh = Py_SIZE(a);
norig = ihigh - ilow;
assert(norig >= 0);
d = n - norig;
if (Py_SIZE(a) + d == 0) {
Py_XDECREF(v_as_SF);
return _list_clear(a);
}
item = a->ob_item;
s = norig * sizeof(PyObject *);
if (s) {
if (s > sizeof(recycle_on_stack)) {
recycle = (PyObject **)PyMem_Malloc(s);
if (recycle == NULL) {
PyErr_NoMemory();
goto Error;
}
}
memcpy(recycle, &item[ilow], s);
}
if (d < 0) {
Py_ssize_t tail;
tail = (Py_SIZE(a) - ihigh) * sizeof(PyObject *);
memmove(&item[ihigh+d], &item[ihigh], tail);
if (list_resize(a, Py_SIZE(a) + d) < 0) {
memmove(&item[ihigh], &item[ihigh+d], tail);
memcpy(&item[ilow], recycle, s);
goto Error;
}
item = a->ob_item;
}
else if (d > 0) {
k = Py_SIZE(a);
if (list_resize(a, k+d) < 0)
goto Error;
item = a->ob_item;
memmove(&item[ihigh+d], &item[ihigh],
(k - ihigh)*sizeof(PyObject *));
}
for (k = 0; k < n; k++, ilow++) {
PyObject *w = vitem[k];
item[ilow] = Py_XNewRef(w);
}
for (k = norig - 1; k >= 0; --k)
Py_XDECREF(recycle[k]);
result = 0;
Error:
if (recycle != recycle_on_stack)
PyMem_Free(recycle);
Py_XDECREF(v_as_SF);
return result;
#undef b
}
int
PyList_SetSlice(PyObject *a, Py_ssize_t ilow, Py_ssize_t ihigh, PyObject *v)
{
if (!PyList_Check(a)) {
PyErr_BadInternalCall();
return -1;
}
return list_ass_slice((PyListObject *)a, ilow, ihigh, v);
}
static PyObject *
list_inplace_repeat(PyListObject *self, Py_ssize_t n)
{
Py_ssize_t input_size = PyList_GET_SIZE(self);
if (input_size == 0 || n == 1) {
return Py_NewRef(self);
}
if (n < 1) {
(void)_list_clear(self);
return Py_NewRef(self);
}
if (input_size > PY_SSIZE_T_MAX / n) {
return PyErr_NoMemory();
}
Py_ssize_t output_size = input_size * n;
if (list_resize(self, output_size) < 0)
return NULL;
PyObject **items = self->ob_item;
for (Py_ssize_t j = 0; j < input_size; j++) {
_Py_RefcntAdd(items[j], n-1);
}
_Py_memory_repeat((char *)items, sizeof(PyObject *)*output_size,
sizeof(PyObject *)*input_size);
return Py_NewRef(self);
}
static int
list_ass_item(PyListObject *a, Py_ssize_t i, PyObject *v)
{
if (!valid_index(i, Py_SIZE(a))) {
PyErr_SetString(PyExc_IndexError,
"list assignment index out of range");
return -1;
}
if (v == NULL)
return list_ass_slice(a, i, i+1, v);
Py_SETREF(a->ob_item[i], Py_NewRef(v));
return 0;
}
static PyObject *
list_insert_impl(PyListObject *self, Py_ssize_t index, PyObject *object)
{
if (ins1(self, index, object) == 0)
Py_RETURN_NONE;
return NULL;
}
static PyObject *
list_clear_impl(PyListObject *self)
{
_list_clear(self);
Py_RETURN_NONE;
}
static PyObject *
list_copy_impl(PyListObject *self)
{
return list_slice(self, 0, Py_SIZE(self));
}
static PyObject *
list_append(PyListObject *self, PyObject *object)
{
if (_PyList_AppendTakeRef(self, Py_NewRef(object)) < 0) {
return NULL;
}
Py_RETURN_NONE;
}
static PyObject *
list_extend(PyListObject *self, PyObject *iterable)
{
PyObject *it;
Py_ssize_t m;
Py_ssize_t n;
Py_ssize_t i;
PyObject *(*iternext)(PyObject *);
if (PyList_CheckExact(iterable) || PyTuple_CheckExact(iterable) ||
(PyObject *)self == iterable) {
PyObject **src, **dest;
iterable = PySequence_Fast(iterable, "argument must be iterable");
if (!iterable)
return NULL;
n = PySequence_Fast_GET_SIZE(iterable);
if (n == 0) {
Py_DECREF(iterable);
Py_RETURN_NONE;
}
m = Py_SIZE(self);
assert(m < PY_SSIZE_T_MAX - n);
if (self->ob_item == NULL) {
if (list_preallocate_exact(self, n) < 0) {
return NULL;
}
Py_SET_SIZE(self, n);
}
else if (list_resize(self, m + n) < 0) {
Py_DECREF(iterable);
return NULL;
}
src = PySequence_Fast_ITEMS(iterable);
dest = self->ob_item + m;
for (i = 0; i < n; i++) {
PyObject *o = src[i];
dest[i] = Py_NewRef(o);
}
Py_DECREF(iterable);
Py_RETURN_NONE;
}
it = PyObject_GetIter(iterable);
if (it == NULL)
return NULL;
iternext = *Py_TYPE(it)->tp_iternext;
n = PyObject_LengthHint(iterable, 8);
if (n < 0) {
Py_DECREF(it);
return NULL;
}
m = Py_SIZE(self);
if (m > PY_SSIZE_T_MAX - n) {
}
else if (self->ob_item == NULL) {
if (n && list_preallocate_exact(self, n) < 0)
goto error;
}
else {
if (list_resize(self, m + n) < 0)
goto error;
Py_SET_SIZE(self, m);
}
for (;;) {
PyObject *item = iternext(it);
if (item == NULL) {
if (PyErr_Occurred()) {
if (PyErr_ExceptionMatches(PyExc_StopIteration))
PyErr_Clear();
else
goto error;
}
break;
}
if (Py_SIZE(self) < self->allocated) {
Py_ssize_t len = Py_SIZE(self);
Py_SET_SIZE(self, len + 1);
PyList_SET_ITEM(self, len, item);
}
else {
if (_PyList_AppendTakeRef(self, item) < 0)
goto error;
}
}
if (Py_SIZE(self) < self->allocated) {
if (list_resize(self, Py_SIZE(self)) < 0)
goto error;
}
Py_DECREF(it);
Py_RETURN_NONE;
error:
Py_DECREF(it);
return NULL;
}
PyObject *
_PyList_Extend(PyListObject *self, PyObject *iterable)
{
return list_extend(self, iterable);
}
static PyObject *
list_inplace_concat(PyListObject *self, PyObject *other)
{
PyObject *result;
result = list_extend(self, other);
if (result == NULL)
return result;
Py_DECREF(result);
return Py_NewRef(self);
}
static PyObject *
list_pop_impl(PyListObject *self, Py_ssize_t index)
{
PyObject *v;
int status;
if (Py_SIZE(self) == 0) {
PyErr_SetString(PyExc_IndexError, "pop from empty list");
return NULL;
}
if (index < 0)
index += Py_SIZE(self);
if (!valid_index(index, Py_SIZE(self))) {
PyErr_SetString(PyExc_IndexError, "pop index out of range");
return NULL;
}
PyObject **items = self->ob_item;
v = items[index];
const Py_ssize_t size_after_pop = Py_SIZE(self) - 1;
if (size_after_pop == 0) {
Py_INCREF(v);
status = _list_clear(self);
}
else {
if ((size_after_pop - index) > 0) {
memmove(&items[index], &items[index+1], (size_after_pop - index) * sizeof(PyObject *));
}
status = list_resize(self, size_after_pop);
}
if (status >= 0) {
return v;
}
else {
memmove(&items[index+1], &items[index], (size_after_pop - index)* sizeof(PyObject *));
items[index] = v;
return NULL;
}
}
static void
reverse_slice(PyObject **lo, PyObject **hi)
{
assert(lo && hi);
--hi;
while (lo < hi) {
PyObject *t = *lo;
*lo = *hi;
*hi = t;
++lo;
--hi;
}
}
typedef struct {
PyObject **keys;
PyObject **values;
} sortslice;
Py_LOCAL_INLINE(void)
sortslice_copy(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j)
{
s1->keys[i] = s2->keys[j];
if (s1->values != NULL)
s1->values[i] = s2->values[j];
}
Py_LOCAL_INLINE(void)
sortslice_copy_incr(sortslice *dst, sortslice *src)
{
*dst->keys++ = *src->keys++;
if (dst->values != NULL)
*dst->values++ = *src->values++;
}
Py_LOCAL_INLINE(void)
sortslice_copy_decr(sortslice *dst, sortslice *src)
{
*dst->keys-- = *src->keys--;
if (dst->values != NULL)
*dst->values-- = *src->values--;
}
Py_LOCAL_INLINE(void)
sortslice_memcpy(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j,
Py_ssize_t n)
{
memcpy(&s1->keys[i], &s2->keys[j], sizeof(PyObject *) * n);
if (s1->values != NULL)
memcpy(&s1->values[i], &s2->values[j], sizeof(PyObject *) * n);
}
Py_LOCAL_INLINE(void)
sortslice_memmove(sortslice *s1, Py_ssize_t i, sortslice *s2, Py_ssize_t j,
Py_ssize_t n)
{
memmove(&s1->keys[i], &s2->keys[j], sizeof(PyObject *) * n);
if (s1->values != NULL)
memmove(&s1->values[i], &s2->values[j], sizeof(PyObject *) * n);
}
Py_LOCAL_INLINE(void)
sortslice_advance(sortslice *slice, Py_ssize_t n)
{
slice->keys += n;
if (slice->values != NULL)
slice->values += n;
}
#define ISLT(X, Y) (*(ms->key_compare))(X, Y, ms)
#define IFLT(X, Y) if ((k = ISLT(X, Y)) < 0) goto fail; \
if (k)
#define MAX_MERGE_PENDING (SIZEOF_SIZE_T * 8)
#define MIN_GALLOP 7
#define MERGESTATE_TEMP_SIZE 256
struct s_slice {
sortslice base;
Py_ssize_t len;
int power;
};
typedef struct s_MergeState MergeState;
struct s_MergeState {
Py_ssize_t min_gallop;
Py_ssize_t listlen;
PyObject **basekeys;
sortslice a;
Py_ssize_t alloced;
int n;
struct s_slice pending[MAX_MERGE_PENDING];
PyObject *temparray[MERGESTATE_TEMP_SIZE];
int (*key_compare)(PyObject *, PyObject *, MergeState *);
PyObject *(*key_richcompare)(PyObject *, PyObject *, int);
int (*tuple_elem_compare)(PyObject *, PyObject *, MergeState *);
};
static int
binarysort(MergeState *ms, sortslice lo, PyObject **hi, PyObject **start)
{
Py_ssize_t k;
PyObject **l, **p, **r;
PyObject *pivot;
assert(lo.keys <= start && start <= hi);
if (lo.keys == start)
++start;
for (; start < hi; ++start) {
l = lo.keys;
r = start;
pivot = *r;
assert(l < r);
do {
p = l + ((r - l) >> 1);
IFLT(pivot, *p)
r = p;
else
l = p+1;
} while (l < r);
assert(l == r);
for (p = start; p > l; --p)
*p = *(p-1);
*l = pivot;
if (lo.values != NULL) {
Py_ssize_t offset = lo.values - lo.keys;
p = start + offset;
pivot = *p;
l += offset;
for (p = start + offset; p > l; --p)
*p = *(p-1);
*l = pivot;
}
}
return 0;
fail:
return -1;
}
static Py_ssize_t
count_run(MergeState *ms, PyObject **lo, PyObject **hi, int *descending)
{
Py_ssize_t k;
Py_ssize_t n;
assert(lo < hi);
*descending = 0;
++lo;
if (lo == hi)
return 1;
n = 2;
IFLT(*lo, *(lo-1)) {
*descending = 1;
for (lo = lo+1; lo < hi; ++lo, ++n) {
IFLT(*lo, *(lo-1))
;
else
break;
}
}
else {
for (lo = lo+1; lo < hi; ++lo, ++n) {
IFLT(*lo, *(lo-1))
break;
}
}
return n;
fail:
return -1;
}
static Py_ssize_t
gallop_left(MergeState *ms, PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint)
{
Py_ssize_t ofs;
Py_ssize_t lastofs;
Py_ssize_t k;
assert(key && a && n > 0 && hint >= 0 && hint < n);
a += hint;
lastofs = 0;
ofs = 1;
IFLT(*a, key) {
const Py_ssize_t maxofs = n - hint;
while (ofs < maxofs) {
IFLT(a[ofs], key) {
lastofs = ofs;
assert(ofs <= (PY_SSIZE_T_MAX - 1) / 2);
ofs = (ofs << 1) + 1;
}
else
break;
}
if (ofs > maxofs)
ofs = maxofs;
lastofs += hint;
ofs += hint;
}
else {
const Py_ssize_t maxofs = hint + 1;
while (ofs < maxofs) {
IFLT(*(a-ofs), key)
break;
lastofs = ofs;
assert(ofs <= (PY_SSIZE_T_MAX - 1) / 2);
ofs = (ofs << 1) + 1;
}
if (ofs > maxofs)
ofs = maxofs;
k = lastofs;
lastofs = hint - ofs;
ofs = hint - k;
}
a -= hint;
assert(-1 <= lastofs && lastofs < ofs && ofs <= n);
++lastofs;
while (lastofs < ofs) {
Py_ssize_t m = lastofs + ((ofs - lastofs) >> 1);
IFLT(a[m], key)
lastofs = m+1;
else
ofs = m;
}
assert(lastofs == ofs);
return ofs;
fail:
return -1;
}
static Py_ssize_t
gallop_right(MergeState *ms, PyObject *key, PyObject **a, Py_ssize_t n, Py_ssize_t hint)
{
Py_ssize_t ofs;
Py_ssize_t lastofs;
Py_ssize_t k;
assert(key && a && n > 0 && hint >= 0 && hint < n);
a += hint;
lastofs = 0;
ofs = 1;
IFLT(key, *a) {
const Py_ssize_t maxofs = hint + 1;
while (ofs < maxofs) {
IFLT(key, *(a-ofs)) {
lastofs = ofs;
assert(ofs <= (PY_SSIZE_T_MAX - 1) / 2);
ofs = (ofs << 1) + 1;
}
else
break;
}
if (ofs > maxofs)
ofs = maxofs;
k = lastofs;
lastofs = hint - ofs;
ofs = hint - k;
}
else {
const Py_ssize_t maxofs = n - hint;
while (ofs < maxofs) {
IFLT(key, a[ofs])
break;
lastofs = ofs;
assert(ofs <= (PY_SSIZE_T_MAX - 1) / 2);
ofs = (ofs << 1) + 1;
}
if (ofs > maxofs)
ofs = maxofs;
lastofs += hint;
ofs += hint;
}
a -= hint;
assert(-1 <= lastofs && lastofs < ofs && ofs <= n);
++lastofs;
while (lastofs < ofs) {
Py_ssize_t m = lastofs + ((ofs - lastofs) >> 1);
IFLT(key, a[m])
ofs = m;
else
lastofs = m+1;
}
assert(lastofs == ofs);
return ofs;
fail:
return -1;
}
static void
merge_init(MergeState *ms, Py_ssize_t list_size, int has_keyfunc,
sortslice *lo)
{
assert(ms != NULL);
if (has_keyfunc) {
ms->alloced = (list_size + 1) / 2;
if (MERGESTATE_TEMP_SIZE / 2 < ms->alloced)
ms->alloced = MERGESTATE_TEMP_SIZE / 2;
ms->a.values = &ms->temparray[ms->alloced];
}
else {
ms->alloced = MERGESTATE_TEMP_SIZE;
ms->a.values = NULL;
}
ms->a.keys = ms->temparray;
ms->n = 0;
ms->min_gallop = MIN_GALLOP;
ms->listlen = list_size;
ms->basekeys = lo->keys;
}
static void
merge_freemem(MergeState *ms)
{
assert(ms != NULL);
if (ms->a.keys != ms->temparray) {
PyMem_Free(ms->a.keys);
ms->a.keys = NULL;
}
}
static int
merge_getmem(MergeState *ms, Py_ssize_t need)
{
int multiplier;
assert(ms != NULL);
if (need <= ms->alloced)
return 0;
multiplier = ms->a.values != NULL ? 2 : 1;
merge_freemem(ms);
if ((size_t)need > PY_SSIZE_T_MAX / sizeof(PyObject *) / multiplier) {
PyErr_NoMemory();
return -1;
}
ms->a.keys = (PyObject **)PyMem_Malloc(multiplier * need
* sizeof(PyObject *));
if (ms->a.keys != NULL) {
ms->alloced = need;
if (ms->a.values != NULL)
ms->a.values = &ms->a.keys[need];
return 0;
}
PyErr_NoMemory();
return -1;
}
#define MERGE_GETMEM(MS, NEED) ((NEED) <= (MS)->alloced ? 0 : \
merge_getmem(MS, NEED))
static Py_ssize_t
merge_lo(MergeState *ms, sortslice ssa, Py_ssize_t na,
sortslice ssb, Py_ssize_t nb)
{
Py_ssize_t k;
sortslice dest;
int result = -1;
Py_ssize_t min_gallop;
assert(ms && ssa.keys && ssb.keys && na > 0 && nb > 0);
assert(ssa.keys + na == ssb.keys);
if (MERGE_GETMEM(ms, na) < 0)
return -1;
sortslice_memcpy(&ms->a, 0, &ssa, 0, na);
dest = ssa;
ssa = ms->a;
sortslice_copy_incr(&dest, &ssb);
--nb;
if (nb == 0)
goto Succeed;
if (na == 1)
goto CopyB;
min_gallop = ms->min_gallop;
for (;;) {
Py_ssize_t acount = 0;
Py_ssize_t bcount = 0;
for (;;) {
assert(na > 1 && nb > 0);
k = ISLT(ssb.keys[0], ssa.keys[0]);
if (k) {
if (k < 0)
goto Fail;
sortslice_copy_incr(&dest, &ssb);
++bcount;
acount = 0;
--nb;
if (nb == 0)
goto Succeed;
if (bcount >= min_gallop)
break;
}
else {
sortslice_copy_incr(&dest, &ssa);
++acount;
bcount = 0;
--na;
if (na == 1)
goto CopyB;
if (acount >= min_gallop)
break;
}
}
++min_gallop;
do {
assert(na > 1 && nb > 0);
min_gallop -= min_gallop > 1;
ms->min_gallop = min_gallop;
k = gallop_right(ms, ssb.keys[0], ssa.keys, na, 0);
acount = k;
if (k) {
if (k < 0)
goto Fail;
sortslice_memcpy(&dest, 0, &ssa, 0, k);
sortslice_advance(&dest, k);
sortslice_advance(&ssa, k);
na -= k;
if (na == 1)
goto CopyB;
if (na == 0)
goto Succeed;
}
sortslice_copy_incr(&dest, &ssb);
--nb;
if (nb == 0)
goto Succeed;
k = gallop_left(ms, ssa.keys[0], ssb.keys, nb, 0);
bcount = k;
if (k) {
if (k < 0)
goto Fail;
sortslice_memmove(&dest, 0, &ssb, 0, k);
sortslice_advance(&dest, k);
sortslice_advance(&ssb, k);
nb -= k;
if (nb == 0)
goto Succeed;
}
sortslice_copy_incr(&dest, &ssa);
--na;
if (na == 1)
goto CopyB;
} while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP);
++min_gallop;
ms->min_gallop = min_gallop;
}
Succeed:
result = 0;
Fail:
if (na)
sortslice_memcpy(&dest, 0, &ssa, 0, na);
return result;
CopyB:
assert(na == 1 && nb > 0);
sortslice_memmove(&dest, 0, &ssb, 0, nb);
sortslice_copy(&dest, nb, &ssa, 0);
return 0;
}
static Py_ssize_t
merge_hi(MergeState *ms, sortslice ssa, Py_ssize_t na,
sortslice ssb, Py_ssize_t nb)
{
Py_ssize_t k;
sortslice dest, basea, baseb;
int result = -1;
Py_ssize_t min_gallop;
assert(ms && ssa.keys && ssb.keys && na > 0 && nb > 0);
assert(ssa.keys + na == ssb.keys);
if (MERGE_GETMEM(ms, nb) < 0)
return -1;
dest = ssb;
sortslice_advance(&dest, nb-1);
sortslice_memcpy(&ms->a, 0, &ssb, 0, nb);
basea = ssa;
baseb = ms->a;
ssb.keys = ms->a.keys + nb - 1;
if (ssb.values != NULL)
ssb.values = ms->a.values + nb - 1;
sortslice_advance(&ssa, na - 1);
sortslice_copy_decr(&dest, &ssa);
--na;
if (na == 0)
goto Succeed;
if (nb == 1)
goto CopyA;
min_gallop = ms->min_gallop;
for (;;) {
Py_ssize_t acount = 0;
Py_ssize_t bcount = 0;
for (;;) {
assert(na > 0 && nb > 1);
k = ISLT(ssb.keys[0], ssa.keys[0]);
if (k) {
if (k < 0)
goto Fail;
sortslice_copy_decr(&dest, &ssa);
++acount;
bcount = 0;
--na;
if (na == 0)
goto Succeed;
if (acount >= min_gallop)
break;
}
else {
sortslice_copy_decr(&dest, &ssb);
++bcount;
acount = 0;
--nb;
if (nb == 1)
goto CopyA;
if (bcount >= min_gallop)
break;
}
}
++min_gallop;
do {
assert(na > 0 && nb > 1);
min_gallop -= min_gallop > 1;
ms->min_gallop = min_gallop;
k = gallop_right(ms, ssb.keys[0], basea.keys, na, na-1);
if (k < 0)
goto Fail;
k = na - k;
acount = k;
if (k) {
sortslice_advance(&dest, -k);
sortslice_advance(&ssa, -k);
sortslice_memmove(&dest, 1, &ssa, 1, k);
na -= k;
if (na == 0)
goto Succeed;
}
sortslice_copy_decr(&dest, &ssb);
--nb;
if (nb == 1)
goto CopyA;
k = gallop_left(ms, ssa.keys[0], baseb.keys, nb, nb-1);
if (k < 0)
goto Fail;
k = nb - k;
bcount = k;
if (k) {
sortslice_advance(&dest, -k);
sortslice_advance(&ssb, -k);
sortslice_memcpy(&dest, 1, &ssb, 1, k);
nb -= k;
if (nb == 1)
goto CopyA;
if (nb == 0)
goto Succeed;
}
sortslice_copy_decr(&dest, &ssa);
--na;
if (na == 0)
goto Succeed;
} while (acount >= MIN_GALLOP || bcount >= MIN_GALLOP);
++min_gallop;
ms->min_gallop = min_gallop;
}
Succeed:
result = 0;
Fail:
if (nb)
sortslice_memcpy(&dest, -(nb-1), &baseb, 0, nb);
return result;
CopyA:
assert(nb == 1 && na > 0);
sortslice_memmove(&dest, 1-na, &ssa, 1-na, na);
sortslice_advance(&dest, -na);
sortslice_advance(&ssa, -na);
sortslice_copy(&dest, 0, &ssb, 0);
return 0;
}
static Py_ssize_t
merge_at(MergeState *ms, Py_ssize_t i)
{
sortslice ssa, ssb;
Py_ssize_t na, nb;
Py_ssize_t k;
assert(ms != NULL);
assert(ms->n >= 2);
assert(i >= 0);
assert(i == ms->n - 2 || i == ms->n - 3);
ssa = ms->pending[i].base;
na = ms->pending[i].len;
ssb = ms->pending[i+1].base;
nb = ms->pending[i+1].len;
assert(na > 0 && nb > 0);
assert(ssa.keys + na == ssb.keys);
ms->pending[i].len = na + nb;
if (i == ms->n - 3)
ms->pending[i+1] = ms->pending[i+2];
--ms->n;
k = gallop_right(ms, *ssb.keys, ssa.keys, na, 0);
if (k < 0)
return -1;
sortslice_advance(&ssa, k);
na -= k;
if (na == 0)
return 0;
nb = gallop_left(ms, ssa.keys[na-1], ssb.keys, nb, nb-1);
if (nb <= 0)
return nb;
if (na <= nb)
return merge_lo(ms, ssa, na, ssb, nb);
else
return merge_hi(ms, ssa, na, ssb, nb);
}
static int
powerloop(Py_ssize_t s1, Py_ssize_t n1, Py_ssize_t n2, Py_ssize_t n)
{
int result = 0;
assert(s1 >= 0);
assert(n1 > 0 && n2 > 0);
assert(s1 + n1 + n2 <= n);
Py_ssize_t a = 2 * s1 + n1;
Py_ssize_t b = a + n1 + n2;
for (;;) {
++result;
if (a >= n) {
assert(b >= a);
a -= n;
b -= n;
}
else if (b >= n) {
break;
}
assert(a < b && b < n);
a <<= 1;
b <<= 1;
}
return result;
}
static int
found_new_run(MergeState *ms, Py_ssize_t n2)
{
assert(ms);
if (ms->n) {
assert(ms->n > 0);
struct s_slice *p = ms->pending;
Py_ssize_t s1 = p[ms->n - 1].base.keys - ms->basekeys;
Py_ssize_t n1 = p[ms->n - 1].len;
int power = powerloop(s1, n1, n2, ms->listlen);
while (ms->n > 1 && p[ms->n - 2].power > power) {
if (merge_at(ms, ms->n - 2) < 0)
return -1;
}
assert(ms->n < 2 || p[ms->n - 2].power < power);
p[ms->n - 1].power = power;
}
return 0;
}
static int
merge_force_collapse(MergeState *ms)
{
struct s_slice *p = ms->pending;
assert(ms);
while (ms->n > 1) {
Py_ssize_t n = ms->n - 2;
if (n > 0 && p[n-1].len < p[n+1].len)
--n;
if (merge_at(ms, n) < 0)
return -1;
}
return 0;
}
static Py_ssize_t
merge_compute_minrun(Py_ssize_t n)
{
Py_ssize_t r = 0;
assert(n >= 0);
while (n >= 64) {
r |= n & 1;
n >>= 1;
}
return n + r;
}
static void
reverse_sortslice(sortslice *s, Py_ssize_t n)
{
reverse_slice(s->keys, &s->keys[n]);
if (s->values != NULL)
reverse_slice(s->values, &s->values[n]);
}
static int
safe_object_compare(PyObject *v, PyObject *w, MergeState *ms)
{
return PyObject_RichCompareBool(v, w, Py_LT);
}
static int
unsafe_object_compare(PyObject *v, PyObject *w, MergeState *ms)
{
PyObject *res_obj; int res;
if (Py_TYPE(v)->tp_richcompare != ms->key_richcompare)
return PyObject_RichCompareBool(v, w, Py_LT);
assert(ms->key_richcompare != NULL);
res_obj = (*(ms->key_richcompare))(v, w, Py_LT);
if (res_obj == Py_NotImplemented) {
Py_DECREF(res_obj);
return PyObject_RichCompareBool(v, w, Py_LT);
}
if (res_obj == NULL)
return -1;
if (PyBool_Check(res_obj)) {
res = (res_obj == Py_True);
}
else {
res = PyObject_IsTrue(res_obj);
}
Py_DECREF(res_obj);
return res;
}
static int
unsafe_latin_compare(PyObject *v, PyObject *w, MergeState *ms)
{
Py_ssize_t len;
int res;
assert(Py_IS_TYPE(v, &PyUnicode_Type));
assert(Py_IS_TYPE(w, &PyUnicode_Type));
assert(PyUnicode_KIND(v) == PyUnicode_KIND(w));
assert(PyUnicode_KIND(v) == PyUnicode_1BYTE_KIND);
len = Py_MIN(PyUnicode_GET_LENGTH(v), PyUnicode_GET_LENGTH(w));
res = memcmp(PyUnicode_DATA(v), PyUnicode_DATA(w), len);
res = (res != 0 ?
res < 0 :
PyUnicode_GET_LENGTH(v) < PyUnicode_GET_LENGTH(w));
assert(res == PyObject_RichCompareBool(v, w, Py_LT));;
return res;
}
static int
unsafe_long_compare(PyObject *v, PyObject *w, MergeState *ms)
{
PyLongObject *vl, *wl;
intptr_t v0, w0;
int res;
assert(Py_IS_TYPE(v, &PyLong_Type));
assert(Py_IS_TYPE(w, &PyLong_Type));
assert(_PyLong_IsCompact((PyLongObject *)v));
assert(_PyLong_IsCompact((PyLongObject *)w));
vl = (PyLongObject*)v;
wl = (PyLongObject*)w;
v0 = _PyLong_CompactValue(vl);
w0 = _PyLong_CompactValue(wl);
res = v0 < w0;
assert(res == PyObject_RichCompareBool(v, w, Py_LT));
return res;
}
static int
unsafe_float_compare(PyObject *v, PyObject *w, MergeState *ms)
{
int res;
assert(Py_IS_TYPE(v, &PyFloat_Type));
assert(Py_IS_TYPE(w, &PyFloat_Type));
res = PyFloat_AS_DOUBLE(v) < PyFloat_AS_DOUBLE(w);
assert(res == PyObject_RichCompareBool(v, w, Py_LT));
return res;
}
static int
unsafe_tuple_compare(PyObject *v, PyObject *w, MergeState *ms)
{
PyTupleObject *vt, *wt;
Py_ssize_t i, vlen, wlen;
int k;
assert(Py_IS_TYPE(v, &PyTuple_Type));
assert(Py_IS_TYPE(w, &PyTuple_Type));
assert(Py_SIZE(v) > 0);
assert(Py_SIZE(w) > 0);
vt = (PyTupleObject *)v;
wt = (PyTupleObject *)w;
vlen = Py_SIZE(vt);
wlen = Py_SIZE(wt);
for (i = 0; i < vlen && i < wlen; i++) {
k = PyObject_RichCompareBool(vt->ob_item[i], wt->ob_item[i], Py_EQ);
if (k < 0)
return -1;
if (!k)
break;
}
if (i >= vlen || i >= wlen)
return vlen < wlen;
if (i == 0)
return ms->tuple_elem_compare(vt->ob_item[i], wt->ob_item[i], ms);
else
return PyObject_RichCompareBool(vt->ob_item[i], wt->ob_item[i], Py_LT);
}
static PyObject *
list_sort_impl(PyListObject *self, PyObject *keyfunc, int reverse)
{
MergeState ms;
Py_ssize_t nremaining;
Py_ssize_t minrun;
sortslice lo;
Py_ssize_t saved_ob_size, saved_allocated;
PyObject **saved_ob_item;
PyObject **final_ob_item;
PyObject *result = NULL;
Py_ssize_t i;
PyObject **keys;
assert(self != NULL);
assert(PyList_Check(self));
if (keyfunc == Py_None)
keyfunc = NULL;
saved_ob_size = Py_SIZE(self);
saved_ob_item = self->ob_item;
saved_allocated = self->allocated;
Py_SET_SIZE(self, 0);
self->ob_item = NULL;
self->allocated = -1;
if (keyfunc == NULL) {
keys = NULL;
lo.keys = saved_ob_item;
lo.values = NULL;
}
else {
if (saved_ob_size < MERGESTATE_TEMP_SIZE/2)
keys = &ms.temparray[saved_ob_size+1];
else {
keys = PyMem_Malloc(sizeof(PyObject *) * saved_ob_size);
if (keys == NULL) {
PyErr_NoMemory();
goto keyfunc_fail;
}
}
for (i = 0; i < saved_ob_size ; i++) {
keys[i] = PyObject_CallOneArg(keyfunc, saved_ob_item[i]);
if (keys[i] == NULL) {
for (i=i-1 ; i>=0 ; i--)
Py_DECREF(keys[i]);
if (saved_ob_size >= MERGESTATE_TEMP_SIZE/2)
PyMem_Free(keys);
goto keyfunc_fail;
}
}
lo.keys = keys;
lo.values = saved_ob_item;
}
if (saved_ob_size > 1) {
int keys_are_in_tuples = (Py_IS_TYPE(lo.keys[0], &PyTuple_Type) &&
Py_SIZE(lo.keys[0]) > 0);
PyTypeObject* key_type = (keys_are_in_tuples ?
Py_TYPE(PyTuple_GET_ITEM(lo.keys[0], 0)) :
Py_TYPE(lo.keys[0]));
int keys_are_all_same_type = 1;
int strings_are_latin = 1;
int ints_are_bounded = 1;
for (i=0; i < saved_ob_size; i++) {
if (keys_are_in_tuples &&
!(Py_IS_TYPE(lo.keys[i], &PyTuple_Type) && Py_SIZE(lo.keys[i]) != 0)) {
keys_are_in_tuples = 0;
keys_are_all_same_type = 0;
break;
}
PyObject *key = (keys_are_in_tuples ?
PyTuple_GET_ITEM(lo.keys[i], 0) :
lo.keys[i]);
if (!Py_IS_TYPE(key, key_type)) {
keys_are_all_same_type = 0;
if (!keys_are_in_tuples) {
break;
}
}
if (keys_are_all_same_type) {
if (key_type == &PyLong_Type &&
ints_are_bounded &&
!_PyLong_IsCompact((PyLongObject *)key)) {
ints_are_bounded = 0;
}
else if (key_type == &PyUnicode_Type &&
strings_are_latin &&
PyUnicode_KIND(key) != PyUnicode_1BYTE_KIND) {
strings_are_latin = 0;
}
}
}
if (keys_are_all_same_type) {
if (key_type == &PyUnicode_Type && strings_are_latin) {
ms.key_compare = unsafe_latin_compare;
}
else if (key_type == &PyLong_Type && ints_are_bounded) {
ms.key_compare = unsafe_long_compare;
}
else if (key_type == &PyFloat_Type) {
ms.key_compare = unsafe_float_compare;
}
else if ((ms.key_richcompare = key_type->tp_richcompare) != NULL) {
ms.key_compare = unsafe_object_compare;
}
else {
ms.key_compare = safe_object_compare;
}
}
else {
ms.key_compare = safe_object_compare;
}
if (keys_are_in_tuples) {
if (key_type == &PyTuple_Type) {
ms.tuple_elem_compare = safe_object_compare;
}
else {
ms.tuple_elem_compare = ms.key_compare;
}
ms.key_compare = unsafe_tuple_compare;
}
}
merge_init(&ms, saved_ob_size, keys != NULL, &lo);
nremaining = saved_ob_size;
if (nremaining < 2)
goto succeed;
if (reverse) {
if (keys != NULL)
reverse_slice(&keys[0], &keys[saved_ob_size]);
reverse_slice(&saved_ob_item[0], &saved_ob_item[saved_ob_size]);
}
minrun = merge_compute_minrun(nremaining);
do {
int descending;
Py_ssize_t n;
n = count_run(&ms, lo.keys, lo.keys + nremaining, &descending);
if (n < 0)
goto fail;
if (descending)
reverse_sortslice(&lo, n);
if (n < minrun) {
const Py_ssize_t force = nremaining <= minrun ?
nremaining : minrun;
if (binarysort(&ms, lo, lo.keys + force, lo.keys + n) < 0)
goto fail;
n = force;
}
assert(ms.n == 0 || ms.pending[ms.n -1].base.keys +
ms.pending[ms.n-1].len == lo.keys);
if (found_new_run(&ms, n) < 0)
goto fail;
assert(ms.n < MAX_MERGE_PENDING);
ms.pending[ms.n].base = lo;
ms.pending[ms.n].len = n;
++ms.n;
sortslice_advance(&lo, n);
nremaining -= n;
} while (nremaining);
if (merge_force_collapse(&ms) < 0)
goto fail;
assert(ms.n == 1);
assert(keys == NULL
? ms.pending[0].base.keys == saved_ob_item
: ms.pending[0].base.keys == &keys[0]);
assert(ms.pending[0].len == saved_ob_size);
lo = ms.pending[0].base;
succeed:
result = Py_None;
fail:
if (keys != NULL) {
for (i = 0; i < saved_ob_size; i++)
Py_DECREF(keys[i]);
if (saved_ob_size >= MERGESTATE_TEMP_SIZE/2)
PyMem_Free(keys);
}
if (self->allocated != -1 && result != NULL) {
PyErr_SetString(PyExc_ValueError, "list modified during sort");
result = NULL;
}
if (reverse && saved_ob_size > 1)
reverse_slice(saved_ob_item, saved_ob_item + saved_ob_size);
merge_freemem(&ms);
keyfunc_fail:
final_ob_item = self->ob_item;
i = Py_SIZE(self);
Py_SET_SIZE(self, saved_ob_size);
self->ob_item = saved_ob_item;
self->allocated = saved_allocated;
if (final_ob_item != NULL) {
while (--i >= 0) {
Py_XDECREF(final_ob_item[i]);
}
PyMem_Free(final_ob_item);
}
return Py_XNewRef(result);
}
#undef IFLT
#undef ISLT
int
PyList_Sort(PyObject *v)
{
if (v == NULL || !PyList_Check(v)) {
PyErr_BadInternalCall();
return -1;
}
v = list_sort_impl((PyListObject *)v, NULL, 0);
if (v == NULL)
return -1;
Py_DECREF(v);
return 0;
}
static PyObject *
list_reverse_impl(PyListObject *self)
{
if (Py_SIZE(self) > 1)
reverse_slice(self->ob_item, self->ob_item + Py_SIZE(self));
Py_RETURN_NONE;
}
int
PyList_Reverse(PyObject *v)
{
PyListObject *self = (PyListObject *)v;
if (v == NULL || !PyList_Check(v)) {
PyErr_BadInternalCall();
return -1;
}
if (Py_SIZE(self) > 1)
reverse_slice(self->ob_item, self->ob_item + Py_SIZE(self));
return 0;
}
PyObject *
PyList_AsTuple(PyObject *v)
{
if (v == NULL || !PyList_Check(v)) {
PyErr_BadInternalCall();
return NULL;
}
return _PyTuple_FromArray(((PyListObject *)v)->ob_item, Py_SIZE(v));
}
PyObject *
_PyList_FromArraySteal(PyObject *const *src, Py_ssize_t n)
{
if (n == 0) {
return PyList_New(0);
}
PyListObject *list = (PyListObject *)PyList_New(n);
if (list == NULL) {
for (Py_ssize_t i = 0; i < n; i++) {
Py_DECREF(src[i]);
}
return NULL;
}
PyObject **dst = list->ob_item;
memcpy(dst, src, n * sizeof(PyObject *));
return (PyObject *)list;
}
static PyObject *
list_index_impl(PyListObject *self, PyObject *value, Py_ssize_t start,
Py_ssize_t stop)
{
Py_ssize_t i;
if (start < 0) {
start += Py_SIZE(self);
if (start < 0)
start = 0;
}
if (stop < 0) {
stop += Py_SIZE(self);
if (stop < 0)
stop = 0;
}
for (i = start; i < stop && i < Py_SIZE(self); i++) {
PyObject *obj = self->ob_item[i];
Py_INCREF(obj);
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
Py_DECREF(obj);
if (cmp > 0)
return PyLong_FromSsize_t(i);
else if (cmp < 0)
return NULL;
}
PyErr_Format(PyExc_ValueError, "%R is not in list", value);
return NULL;
}
static PyObject *
list_count(PyListObject *self, PyObject *value)
{
Py_ssize_t count = 0;
Py_ssize_t i;
for (i = 0; i < Py_SIZE(self); i++) {
PyObject *obj = self->ob_item[i];
if (obj == value) {
count++;
continue;
}
Py_INCREF(obj);
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
Py_DECREF(obj);
if (cmp > 0)
count++;
else if (cmp < 0)
return NULL;
}
return PyLong_FromSsize_t(count);
}
static PyObject *
list_remove(PyListObject *self, PyObject *value)
{
Py_ssize_t i;
for (i = 0; i < Py_SIZE(self); i++) {
PyObject *obj = self->ob_item[i];
Py_INCREF(obj);
int cmp = PyObject_RichCompareBool(obj, value, Py_EQ);
Py_DECREF(obj);
if (cmp > 0) {
if (list_ass_slice(self, i, i+1,
(PyObject *)NULL) == 0)
Py_RETURN_NONE;
return NULL;
}
else if (cmp < 0)
return NULL;
}
PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list");
return NULL;
}
static int
list_traverse(PyListObject *o, visitproc visit, void *arg)
{
Py_ssize_t i;
for (i = Py_SIZE(o); --i >= 0; )
Py_VISIT(o->ob_item[i]);
return 0;
}
static PyObject *
list_richcompare(PyObject *v, PyObject *w, int op)
{
PyListObject *vl, *wl;
Py_ssize_t i;
if (!PyList_Check(v) || !PyList_Check(w))
Py_RETURN_NOTIMPLEMENTED;
vl = (PyListObject *)v;
wl = (PyListObject *)w;
if (Py_SIZE(vl) != Py_SIZE(wl) && (op == Py_EQ || op == Py_NE)) {
if (op == Py_EQ)
Py_RETURN_FALSE;
else
Py_RETURN_TRUE;
}
for (i = 0; i < Py_SIZE(vl) && i < Py_SIZE(wl); i++) {
PyObject *vitem = vl->ob_item[i];
PyObject *witem = wl->ob_item[i];
if (vitem == witem) {
continue;
}
Py_INCREF(vitem);
Py_INCREF(witem);
int k = PyObject_RichCompareBool(vitem, witem, Py_EQ);
Py_DECREF(vitem);
Py_DECREF(witem);
if (k < 0)
return NULL;
if (!k)
break;
}
if (i >= Py_SIZE(vl) || i >= Py_SIZE(wl)) {
Py_RETURN_RICHCOMPARE(Py_SIZE(vl), Py_SIZE(wl), op);
}
if (op == Py_EQ) {
Py_RETURN_FALSE;
}
if (op == Py_NE) {
Py_RETURN_TRUE;
}
return PyObject_RichCompare(vl->ob_item[i], wl->ob_item[i], op);
}
static int
list___init___impl(PyListObject *self, PyObject *iterable)
{
assert(0 <= Py_SIZE(self));
assert(Py_SIZE(self) <= self->allocated || self->allocated == -1);
assert(self->ob_item != NULL ||
self->allocated == 0 || self->allocated == -1);
if (self->ob_item != NULL) {
(void)_list_clear(self);
}
if (iterable != NULL) {
PyObject *rv = list_extend(self, iterable);
if (rv == NULL)
return -1;
Py_DECREF(rv);
}
return 0;
}
static PyObject *
list_vectorcall(PyObject *type, PyObject * const*args,
size_t nargsf, PyObject *kwnames)
{
if (!_PyArg_NoKwnames("list", kwnames)) {
return NULL;
}
Py_ssize_t nargs = PyVectorcall_NARGS(nargsf);
if (!_PyArg_CheckPositional("list", nargs, 0, 1)) {
return NULL;
}
PyObject *list = PyType_GenericAlloc(_PyType_CAST(type), 0);
if (list == NULL) {
return NULL;
}
if (nargs) {
if (list___init___impl((PyListObject *)list, args[0])) {
Py_DECREF(list);
return NULL;
}
}
return list;
}
static PyObject *
list___sizeof___impl(PyListObject *self)
{
size_t res = _PyObject_SIZE(Py_TYPE(self));
res += (size_t)self->allocated * sizeof(void*);
return PyLong_FromSize_t(res);
}
static PyObject *list_iter(PyObject *seq);
static PyObject *list_subscript(PyListObject*, PyObject*);
static PyMethodDef list_methods[] = {
{"__getitem__", (PyCFunction)list_subscript, METH_O|METH_COEXIST,
PyDoc_STR("__getitem__($self, index, /)\n--\n\nReturn self[index].")},
LIST___REVERSED___METHODDEF
LIST___SIZEOF___METHODDEF
LIST_CLEAR_METHODDEF
LIST_COPY_METHODDEF
LIST_APPEND_METHODDEF
LIST_INSERT_METHODDEF
LIST_EXTEND_METHODDEF
LIST_POP_METHODDEF
LIST_REMOVE_METHODDEF
LIST_INDEX_METHODDEF
LIST_COUNT_METHODDEF
LIST_REVERSE_METHODDEF
LIST_SORT_METHODDEF
{"__class_getitem__", Py_GenericAlias, METH_O|METH_CLASS, PyDoc_STR("See PEP 585")},
{NULL, NULL}
};
static PySequenceMethods list_as_sequence = {
(lenfunc)list_length,
(binaryfunc)list_concat,
(ssizeargfunc)list_repeat,
(ssizeargfunc)list_item,
0,
(ssizeobjargproc)list_ass_item,
0,
(objobjproc)list_contains,
(binaryfunc)list_inplace_concat,
(ssizeargfunc)list_inplace_repeat,
};
static PyObject *
list_subscript(PyListObject* self, PyObject* item)
{
if (_PyIndex_Check(item)) {
Py_ssize_t i;
i = PyNumber_AsSsize_t(item, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
return NULL;
if (i < 0)
i += PyList_GET_SIZE(self);
return list_item(self, i);
}
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength, i;
size_t cur;
PyObject* result;
PyObject* it;
PyObject **src, **dest;
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
return NULL;
}
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
step);
if (slicelength <= 0) {
return PyList_New(0);
}
else if (step == 1) {
return list_slice(self, start, stop);
}
else {
result = list_new_prealloc(slicelength);
if (!result) return NULL;
src = self->ob_item;
dest = ((PyListObject *)result)->ob_item;
for (cur = start, i = 0; i < slicelength;
cur += (size_t)step, i++) {
it = Py_NewRef(src[cur]);
dest[i] = it;
}
Py_SET_SIZE(result, slicelength);
return result;
}
}
else {
PyErr_Format(PyExc_TypeError,
"list indices must be integers or slices, not %.200s",
Py_TYPE(item)->tp_name);
return NULL;
}
}
static int
list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value)
{
if (_PyIndex_Check(item)) {
Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
if (i == -1 && PyErr_Occurred())
return -1;
if (i < 0)
i += PyList_GET_SIZE(self);
return list_ass_item(self, i, value);
}
else if (PySlice_Check(item)) {
Py_ssize_t start, stop, step, slicelength;
if (PySlice_Unpack(item, &start, &stop, &step) < 0) {
return -1;
}
slicelength = PySlice_AdjustIndices(Py_SIZE(self), &start, &stop,
step);
if (step == 1)
return list_ass_slice(self, start, stop, value);
if ((step < 0 && start < stop) ||
(step > 0 && start > stop))
stop = start;
if (value == NULL) {
PyObject **garbage;
size_t cur;
Py_ssize_t i;
int res;
if (slicelength <= 0)
return 0;
if (step < 0) {
stop = start + 1;
start = stop + step*(slicelength - 1) - 1;
step = -step;
}
garbage = (PyObject**)
PyMem_Malloc(slicelength*sizeof(PyObject*));
if (!garbage) {
PyErr_NoMemory();
return -1;
}
for (cur = start, i = 0;
cur < (size_t)stop;
cur += step, i++) {
Py_ssize_t lim = step - 1;
garbage[i] = PyList_GET_ITEM(self, cur);
if (cur + step >= (size_t)Py_SIZE(self)) {
lim = Py_SIZE(self) - cur - 1;
}
memmove(self->ob_item + cur - i,
self->ob_item + cur + 1,
lim * sizeof(PyObject *));
}
cur = start + (size_t)slicelength * step;
if (cur < (size_t)Py_SIZE(self)) {
memmove(self->ob_item + cur - slicelength,
self->ob_item + cur,
(Py_SIZE(self) - cur) *
sizeof(PyObject *));
}
Py_SET_SIZE(self, Py_SIZE(self) - slicelength);
res = list_resize(self, Py_SIZE(self));
for (i = 0; i < slicelength; i++) {
Py_DECREF(garbage[i]);
}
PyMem_Free(garbage);
return res;
}
else {
PyObject *ins, *seq;
PyObject **garbage, **seqitems, **selfitems;
Py_ssize_t i;
size_t cur;
if (self == (PyListObject*)value) {
seq = list_slice((PyListObject*)value, 0,
PyList_GET_SIZE(value));
}
else {
seq = PySequence_Fast(value,
"must assign iterable "
"to extended slice");
}
if (!seq)
return -1;
if (PySequence_Fast_GET_SIZE(seq) != slicelength) {
PyErr_Format(PyExc_ValueError,
"attempt to assign sequence of "
"size %zd to extended slice of "
"size %zd",
PySequence_Fast_GET_SIZE(seq),
slicelength);
Py_DECREF(seq);
return -1;
}
if (!slicelength) {
Py_DECREF(seq);
return 0;
}
garbage = (PyObject**)
PyMem_Malloc(slicelength*sizeof(PyObject*));
if (!garbage) {
Py_DECREF(seq);
PyErr_NoMemory();
return -1;
}
selfitems = self->ob_item;
seqitems = PySequence_Fast_ITEMS(seq);
for (cur = start, i = 0; i < slicelength;
cur += (size_t)step, i++) {
garbage[i] = selfitems[cur];
ins = Py_NewRef(seqitems[i]);
selfitems[cur] = ins;
}
for (i = 0; i < slicelength; i++) {
Py_DECREF(garbage[i]);
}
PyMem_Free(garbage);
Py_DECREF(seq);
return 0;
}
}
else {
PyErr_Format(PyExc_TypeError,
"list indices must be integers or slices, not %.200s",
Py_TYPE(item)->tp_name);
return -1;
}
}
static PyMappingMethods list_as_mapping = {
(lenfunc)list_length,
(binaryfunc)list_subscript,
(objobjargproc)list_ass_subscript
};
PyTypeObject PyList_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"list",
sizeof(PyListObject),
0,
(destructor)list_dealloc,
0,
0,
0,
0,
(reprfunc)list_repr,
0,
&list_as_sequence,
&list_as_mapping,
PyObject_HashNotImplemented,
0,
0,
PyObject_GenericGetAttr,
0,
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
Py_TPFLAGS_BASETYPE | Py_TPFLAGS_LIST_SUBCLASS |
_Py_TPFLAGS_MATCH_SELF | Py_TPFLAGS_SEQUENCE,
list___init____doc__,
(traverseproc)list_traverse,
(inquiry)_list_clear,
list_richcompare,
0,
list_iter,
0,
list_methods,
0,
0,
0,
0,
0,
0,
0,
(initproc)list___init__,
PyType_GenericAlloc,
PyType_GenericNew,
PyObject_GC_Del,
.tp_vectorcall = list_vectorcall,
};
static void listiter_dealloc(_PyListIterObject *);
static int listiter_traverse(_PyListIterObject *, visitproc, void *);
static PyObject *listiter_next(_PyListIterObject *);
static PyObject *listiter_len(_PyListIterObject *, PyObject *);
static PyObject *listiter_reduce_general(void *_it, int forward);
static PyObject *listiter_reduce(_PyListIterObject *, PyObject *);
static PyObject *listiter_setstate(_PyListIterObject *, PyObject *state);
PyDoc_STRVAR(length_hint_doc, "Private method returning an estimate of len(list(it)).");
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");
PyDoc_STRVAR(setstate_doc, "Set state information for unpickling.");
static PyMethodDef listiter_methods[] = {
{"__length_hint__", (PyCFunction)listiter_len, METH_NOARGS, length_hint_doc},
{"__reduce__", (PyCFunction)listiter_reduce, METH_NOARGS, reduce_doc},
{"__setstate__", (PyCFunction)listiter_setstate, METH_O, setstate_doc},
{NULL, NULL}
};
PyTypeObject PyListIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"list_iterator",
sizeof(_PyListIterObject),
0,
(destructor)listiter_dealloc,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
PyObject_GenericGetAttr,
0,
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
0,
(traverseproc)listiter_traverse,
0,
0,
0,
PyObject_SelfIter,
(iternextfunc)listiter_next,
listiter_methods,
0,
};
static PyObject *
list_iter(PyObject *seq)
{
_PyListIterObject *it;
if (!PyList_Check(seq)) {
PyErr_BadInternalCall();
return NULL;
}
it = PyObject_GC_New(_PyListIterObject, &PyListIter_Type);
if (it == NULL)
return NULL;
it->it_index = 0;
it->it_seq = (PyListObject *)Py_NewRef(seq);
_PyObject_GC_TRACK(it);
return (PyObject *)it;
}
static void
listiter_dealloc(_PyListIterObject *it)
{
_PyObject_GC_UNTRACK(it);
Py_XDECREF(it->it_seq);
PyObject_GC_Del(it);
}
static int
listiter_traverse(_PyListIterObject *it, visitproc visit, void *arg)
{
Py_VISIT(it->it_seq);
return 0;
}
static PyObject *
listiter_next(_PyListIterObject *it)
{
PyListObject *seq;
PyObject *item;
assert(it != NULL);
seq = it->it_seq;
if (seq == NULL)
return NULL;
assert(PyList_Check(seq));
if (it->it_index < PyList_GET_SIZE(seq)) {
item = PyList_GET_ITEM(seq, it->it_index);
++it->it_index;
return Py_NewRef(item);
}
it->it_seq = NULL;
Py_DECREF(seq);
return NULL;
}
static PyObject *
listiter_len(_PyListIterObject *it, PyObject *Py_UNUSED(ignored))
{
Py_ssize_t len;
if (it->it_seq) {
len = PyList_GET_SIZE(it->it_seq) - it->it_index;
if (len >= 0)
return PyLong_FromSsize_t(len);
}
return PyLong_FromLong(0);
}
static PyObject *
listiter_reduce(_PyListIterObject *it, PyObject *Py_UNUSED(ignored))
{
return listiter_reduce_general(it, 1);
}
static PyObject *
listiter_setstate(_PyListIterObject *it, PyObject *state)
{
Py_ssize_t index = PyLong_AsSsize_t(state);
if (index == -1 && PyErr_Occurred())
return NULL;
if (it->it_seq != NULL) {
if (index < 0)
index = 0;
else if (index > PyList_GET_SIZE(it->it_seq))
index = PyList_GET_SIZE(it->it_seq);
it->it_index = index;
}
Py_RETURN_NONE;
}
typedef struct {
PyObject_HEAD
Py_ssize_t it_index;
PyListObject *it_seq;
} listreviterobject;
static void listreviter_dealloc(listreviterobject *);
static int listreviter_traverse(listreviterobject *, visitproc, void *);
static PyObject *listreviter_next(listreviterobject *);
static PyObject *listreviter_len(listreviterobject *, PyObject *);
static PyObject *listreviter_reduce(listreviterobject *, PyObject *);
static PyObject *listreviter_setstate(listreviterobject *, PyObject *);
static PyMethodDef listreviter_methods[] = {
{"__length_hint__", (PyCFunction)listreviter_len, METH_NOARGS, length_hint_doc},
{"__reduce__", (PyCFunction)listreviter_reduce, METH_NOARGS, reduce_doc},
{"__setstate__", (PyCFunction)listreviter_setstate, METH_O, setstate_doc},
{NULL, NULL}
};
PyTypeObject PyListRevIter_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"list_reverseiterator",
sizeof(listreviterobject),
0,
(destructor)listreviter_dealloc,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
PyObject_GenericGetAttr,
0,
0,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,
0,
(traverseproc)listreviter_traverse,
0,
0,
0,
PyObject_SelfIter,
(iternextfunc)listreviter_next,
listreviter_methods,
0,
};
static PyObject *
list___reversed___impl(PyListObject *self)
{
listreviterobject *it;
it = PyObject_GC_New(listreviterobject, &PyListRevIter_Type);
if (it == NULL)
return NULL;
assert(PyList_Check(self));
it->it_index = PyList_GET_SIZE(self) - 1;
it->it_seq = (PyListObject*)Py_NewRef(self);
PyObject_GC_Track(it);
return (PyObject *)it;
}
static void
listreviter_dealloc(listreviterobject *it)
{
PyObject_GC_UnTrack(it);
Py_XDECREF(it->it_seq);
PyObject_GC_Del(it);
}
static int
listreviter_traverse(listreviterobject *it, visitproc visit, void *arg)
{
Py_VISIT(it->it_seq);
return 0;
}
static PyObject *
listreviter_next(listreviterobject *it)
{
PyObject *item;
Py_ssize_t index;
PyListObject *seq;
assert(it != NULL);
seq = it->it_seq;
if (seq == NULL) {
return NULL;
}
assert(PyList_Check(seq));
index = it->it_index;
if (index>=0 && index < PyList_GET_SIZE(seq)) {
item = PyList_GET_ITEM(seq, index);
it->it_index--;
return Py_NewRef(item);
}
it->it_index = -1;
it->it_seq = NULL;
Py_DECREF(seq);
return NULL;
}
static PyObject *
listreviter_len(listreviterobject *it, PyObject *Py_UNUSED(ignored))
{
Py_ssize_t len = it->it_index + 1;
if (it->it_seq == NULL || PyList_GET_SIZE(it->it_seq) < len)
len = 0;
return PyLong_FromSsize_t(len);
}
static PyObject *
listreviter_reduce(listreviterobject *it, PyObject *Py_UNUSED(ignored))
{
return listiter_reduce_general(it, 0);
}
static PyObject *
listreviter_setstate(listreviterobject *it, PyObject *state)
{
Py_ssize_t index = PyLong_AsSsize_t(state);
if (index == -1 && PyErr_Occurred())
return NULL;
if (it->it_seq != NULL) {
if (index < -1)
index = -1;
else if (index > PyList_GET_SIZE(it->it_seq) - 1)
index = PyList_GET_SIZE(it->it_seq) - 1;
it->it_index = index;
}
Py_RETURN_NONE;
}
static PyObject *
listiter_reduce_general(void *_it, int forward)
{
PyObject *list;
if (forward) {
PyObject *iter = _PyEval_GetBuiltin(&_Py_ID(iter));
if (!iter) {
return NULL;
}
_PyListIterObject *it = (_PyListIterObject *)_it;
if (it->it_seq) {
return Py_BuildValue("N(O)n", iter, it->it_seq, it->it_index);
}
Py_DECREF(iter);
} else {
PyObject *reversed = _PyEval_GetBuiltin(&_Py_ID(reversed));
if (!reversed) {
return NULL;
}
listreviterobject *it = (listreviterobject *)_it;
if (it->it_seq) {
return Py_BuildValue("N(O)n", reversed, it->it_seq, it->it_index);
}
Py_DECREF(reversed);
}
list = PyList_New(0);
if (list == NULL)
return NULL;
return Py_BuildValue("N(N)", _PyEval_GetBuiltin(&_Py_ID(iter)), list);
}