Tipragot
628be439b8
Cela permet de ne pas avoir de problèmes de compatibilité car python est dans le git.
336 lines
9.8 KiB
C
336 lines
9.8 KiB
C
// List primitive operations
|
|
//
|
|
// These are registered in mypyc.primitives.list_ops.
|
|
|
|
#include <Python.h>
|
|
#include "CPy.h"
|
|
|
|
#ifndef Py_TPFLAGS_SEQUENCE
|
|
#define Py_TPFLAGS_SEQUENCE (1 << 5)
|
|
#endif
|
|
|
|
PyObject *CPyList_Build(Py_ssize_t len, ...) {
|
|
Py_ssize_t i;
|
|
|
|
PyObject *res = PyList_New(len);
|
|
if (res == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
va_list args;
|
|
va_start(args, len);
|
|
for (i = 0; i < len; i++) {
|
|
// Steals the reference
|
|
PyObject *value = va_arg(args, PyObject *);
|
|
PyList_SET_ITEM(res, i, value);
|
|
}
|
|
va_end(args);
|
|
|
|
return res;
|
|
}
|
|
|
|
PyObject *CPyList_GetItemUnsafe(PyObject *list, CPyTagged index) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
PyObject *result = PyList_GET_ITEM(list, n);
|
|
Py_INCREF(result);
|
|
return result;
|
|
}
|
|
|
|
PyObject *CPyList_GetItemShort(PyObject *list, CPyTagged index) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
Py_ssize_t size = PyList_GET_SIZE(list);
|
|
if (n >= 0) {
|
|
if (n >= size) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
n += size;
|
|
if (n < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
}
|
|
PyObject *result = PyList_GET_ITEM(list, n);
|
|
Py_INCREF(result);
|
|
return result;
|
|
}
|
|
|
|
PyObject *CPyList_GetItemShortBorrow(PyObject *list, CPyTagged index) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
Py_ssize_t size = PyList_GET_SIZE(list);
|
|
if (n >= 0) {
|
|
if (n >= size) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
n += size;
|
|
if (n < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
}
|
|
return PyList_GET_ITEM(list, n);
|
|
}
|
|
|
|
PyObject *CPyList_GetItem(PyObject *list, CPyTagged index) {
|
|
if (CPyTagged_CheckShort(index)) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
Py_ssize_t size = PyList_GET_SIZE(list);
|
|
if (n >= 0) {
|
|
if (n >= size) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
n += size;
|
|
if (n < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
}
|
|
PyObject *result = PyList_GET_ITEM(list, n);
|
|
Py_INCREF(result);
|
|
return result;
|
|
} else {
|
|
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
PyObject *CPyList_GetItemBorrow(PyObject *list, CPyTagged index) {
|
|
if (CPyTagged_CheckShort(index)) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
Py_ssize_t size = PyList_GET_SIZE(list);
|
|
if (n >= 0) {
|
|
if (n >= size) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
} else {
|
|
n += size;
|
|
if (n < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
}
|
|
return PyList_GET_ITEM(list, n);
|
|
} else {
|
|
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
PyObject *CPyList_GetItemInt64(PyObject *list, int64_t index) {
|
|
size_t size = PyList_GET_SIZE(list);
|
|
if (likely((uint64_t)index < size)) {
|
|
PyObject *result = PyList_GET_ITEM(list, index);
|
|
Py_INCREF(result);
|
|
return result;
|
|
}
|
|
if (index >= 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
index += size;
|
|
if (index < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
PyObject *result = PyList_GET_ITEM(list, index);
|
|
Py_INCREF(result);
|
|
return result;
|
|
}
|
|
|
|
PyObject *CPyList_GetItemInt64Borrow(PyObject *list, int64_t index) {
|
|
size_t size = PyList_GET_SIZE(list);
|
|
if (likely((uint64_t)index < size)) {
|
|
return PyList_GET_ITEM(list, index);
|
|
}
|
|
if (index >= 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
index += size;
|
|
if (index < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list index out of range");
|
|
return NULL;
|
|
}
|
|
return PyList_GET_ITEM(list, index);
|
|
}
|
|
|
|
bool CPyList_SetItem(PyObject *list, CPyTagged index, PyObject *value) {
|
|
if (CPyTagged_CheckShort(index)) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
Py_ssize_t size = PyList_GET_SIZE(list);
|
|
if (n >= 0) {
|
|
if (n >= size) {
|
|
PyErr_SetString(PyExc_IndexError, "list assignment index out of range");
|
|
return false;
|
|
}
|
|
} else {
|
|
n += size;
|
|
if (n < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list assignment index out of range");
|
|
return false;
|
|
}
|
|
}
|
|
// PyList_SET_ITEM doesn't decref the old element, so we do
|
|
Py_DECREF(PyList_GET_ITEM(list, n));
|
|
// N.B: Steals reference
|
|
PyList_SET_ITEM(list, n, value);
|
|
return true;
|
|
} else {
|
|
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
bool CPyList_SetItemInt64(PyObject *list, int64_t index, PyObject *value) {
|
|
size_t size = PyList_GET_SIZE(list);
|
|
if (unlikely((uint64_t)index >= size)) {
|
|
if (index > 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list assignment index out of range");
|
|
return false;
|
|
}
|
|
index += size;
|
|
if (index < 0) {
|
|
PyErr_SetString(PyExc_IndexError, "list assignment index out of range");
|
|
return false;
|
|
}
|
|
}
|
|
// PyList_SET_ITEM doesn't decref the old element, so we do
|
|
Py_DECREF(PyList_GET_ITEM(list, index));
|
|
// N.B: Steals reference
|
|
PyList_SET_ITEM(list, index, value);
|
|
return true;
|
|
}
|
|
|
|
// This function should only be used to fill in brand new lists.
|
|
bool CPyList_SetItemUnsafe(PyObject *list, CPyTagged index, PyObject *value) {
|
|
if (CPyTagged_CheckShort(index)) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
PyList_SET_ITEM(list, n, value);
|
|
return true;
|
|
} else {
|
|
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
PyObject *CPyList_PopLast(PyObject *obj)
|
|
{
|
|
// I tried a specalized version of pop_impl for just removing the
|
|
// last element and it wasn't any faster in microbenchmarks than
|
|
// the generic one so I ditched it.
|
|
return list_pop_impl((PyListObject *)obj, -1);
|
|
}
|
|
|
|
PyObject *CPyList_Pop(PyObject *obj, CPyTagged index)
|
|
{
|
|
if (CPyTagged_CheckShort(index)) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
return list_pop_impl((PyListObject *)obj, n);
|
|
} else {
|
|
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
CPyTagged CPyList_Count(PyObject *obj, PyObject *value)
|
|
{
|
|
return list_count((PyListObject *)obj, value);
|
|
}
|
|
|
|
int CPyList_Insert(PyObject *list, CPyTagged index, PyObject *value)
|
|
{
|
|
if (CPyTagged_CheckShort(index)) {
|
|
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
|
return PyList_Insert(list, n, value);
|
|
}
|
|
// The max range doesn't exactly coincide with ssize_t, but we still
|
|
// want to keep the error message compatible with CPython.
|
|
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
|
return -1;
|
|
}
|
|
|
|
PyObject *CPyList_Extend(PyObject *o1, PyObject *o2) {
|
|
return _PyList_Extend((PyListObject *)o1, o2);
|
|
}
|
|
|
|
// Return -2 or error, -1 if not found, or index of first match otherwise.
|
|
static Py_ssize_t _CPyList_Find(PyObject *list, PyObject *obj) {
|
|
Py_ssize_t i;
|
|
for (i = 0; i < Py_SIZE(list); i++) {
|
|
PyObject *item = PyList_GET_ITEM(list, i);
|
|
Py_INCREF(item);
|
|
int cmp = PyObject_RichCompareBool(item, obj, Py_EQ);
|
|
Py_DECREF(item);
|
|
if (cmp != 0) {
|
|
if (cmp > 0) {
|
|
return i;
|
|
} else {
|
|
return -2;
|
|
}
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int CPyList_Remove(PyObject *list, PyObject *obj) {
|
|
Py_ssize_t index = _CPyList_Find(list, obj);
|
|
if (index == -2) {
|
|
return -1;
|
|
}
|
|
if (index == -1) {
|
|
PyErr_SetString(PyExc_ValueError, "list.remove(x): x not in list");
|
|
return -1;
|
|
}
|
|
return PyList_SetSlice(list, index, index + 1, NULL);
|
|
}
|
|
|
|
CPyTagged CPyList_Index(PyObject *list, PyObject *obj) {
|
|
Py_ssize_t index = _CPyList_Find(list, obj);
|
|
if (index == -2) {
|
|
return CPY_INT_TAG;
|
|
}
|
|
if (index == -1) {
|
|
PyErr_SetString(PyExc_ValueError, "value is not in list");
|
|
return CPY_INT_TAG;
|
|
}
|
|
return index << 1;
|
|
}
|
|
|
|
PyObject *CPySequence_Multiply(PyObject *seq, CPyTagged t_size) {
|
|
Py_ssize_t size = CPyTagged_AsSsize_t(t_size);
|
|
if (size == -1 && PyErr_Occurred()) {
|
|
return NULL;
|
|
}
|
|
return PySequence_Repeat(seq, size);
|
|
}
|
|
|
|
PyObject *CPySequence_RMultiply(CPyTagged t_size, PyObject *seq) {
|
|
return CPySequence_Multiply(seq, t_size);
|
|
}
|
|
|
|
PyObject *CPyList_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end) {
|
|
if (likely(PyList_CheckExact(obj)
|
|
&& CPyTagged_CheckShort(start) && CPyTagged_CheckShort(end))) {
|
|
Py_ssize_t startn = CPyTagged_ShortAsSsize_t(start);
|
|
Py_ssize_t endn = CPyTagged_ShortAsSsize_t(end);
|
|
if (startn < 0) {
|
|
startn += PyList_GET_SIZE(obj);
|
|
}
|
|
if (endn < 0) {
|
|
endn += PyList_GET_SIZE(obj);
|
|
}
|
|
return PyList_GetSlice(obj, startn, endn);
|
|
}
|
|
return CPyObject_GetSlice(obj, start, end);
|
|
}
|
|
|
|
int CPySequence_Check(PyObject *obj) {
|
|
return Py_TYPE(obj)->tp_flags & Py_TPFLAGS_SEQUENCE;
|
|
}
|