init
This commit is contained in:
commit
38355d2442
9083 changed files with 1225834 additions and 0 deletions
593
.venv/lib/python3.8/site-packages/mypyc/lib-rt/CPy.h
Normal file
593
.venv/lib/python3.8/site-packages/mypyc/lib-rt/CPy.h
Normal file
|
|
@ -0,0 +1,593 @@
|
|||
// Mypyc C API
|
||||
|
||||
#ifndef CPY_CPY_H
|
||||
#define CPY_CPY_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <Python.h>
|
||||
#include <frameobject.h>
|
||||
#include <structmember.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include "pythonsupport.h"
|
||||
#include "mypyc_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#if 0
|
||||
} // why isn't emacs smart enough to not indent this
|
||||
#endif
|
||||
|
||||
#define CPYTHON_LARGE_INT_ERRMSG "Python int too large to convert to C ssize_t"
|
||||
|
||||
|
||||
// Naming conventions:
|
||||
//
|
||||
// Tagged: tagged int
|
||||
// Long: tagged long int (pointer)
|
||||
// Short: tagged short int (unboxed)
|
||||
// Ssize_t: A Py_ssize_t, which ought to be the same width as pointers
|
||||
// Object: CPython object (PyObject *)
|
||||
|
||||
|
||||
// Tuple type definitions needed for API functions
|
||||
|
||||
|
||||
#ifndef MYPYC_DECLARED_tuple_T3OOO
|
||||
#define MYPYC_DECLARED_tuple_T3OOO
|
||||
typedef struct tuple_T3OOO {
|
||||
PyObject *f0;
|
||||
PyObject *f1;
|
||||
PyObject *f2;
|
||||
} tuple_T3OOO;
|
||||
static tuple_T3OOO tuple_undefined_T3OOO = { NULL, NULL, NULL };
|
||||
#endif
|
||||
|
||||
// Our return tuple wrapper for dictionary iteration helper.
|
||||
#ifndef MYPYC_DECLARED_tuple_T3CIO
|
||||
#define MYPYC_DECLARED_tuple_T3CIO
|
||||
typedef struct tuple_T3CIO {
|
||||
char f0; // Should continue?
|
||||
CPyTagged f1; // Last dict offset
|
||||
PyObject *f2; // Next dictionary key or value
|
||||
} tuple_T3CIO;
|
||||
static tuple_T3CIO tuple_undefined_T3CIO = { 2, CPY_INT_TAG, NULL };
|
||||
#endif
|
||||
|
||||
// Same as above but for both key and value.
|
||||
#ifndef MYPYC_DECLARED_tuple_T4CIOO
|
||||
#define MYPYC_DECLARED_tuple_T4CIOO
|
||||
typedef struct tuple_T4CIOO {
|
||||
char f0; // Should continue?
|
||||
CPyTagged f1; // Last dict offset
|
||||
PyObject *f2; // Next dictionary key
|
||||
PyObject *f3; // Next dictionary value
|
||||
} tuple_T4CIOO;
|
||||
static tuple_T4CIOO tuple_undefined_T4CIOO = { 2, CPY_INT_TAG, NULL, NULL };
|
||||
#endif
|
||||
|
||||
|
||||
// Native object operations
|
||||
|
||||
|
||||
// Search backwards through the trait part of a vtable (which sits *before*
|
||||
// the start of the vtable proper) looking for the subvtable describing a trait
|
||||
// implementation. We don't do any bounds checking so we'd better be pretty sure
|
||||
// we know that it is there.
|
||||
static inline CPyVTableItem *CPy_FindTraitVtable(PyTypeObject *trait, CPyVTableItem *vtable) {
|
||||
int i;
|
||||
for (i = -3; ; i -= 3) {
|
||||
if ((PyTypeObject *)vtable[i] == trait) {
|
||||
return (CPyVTableItem *)vtable[i + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use the same logic for offset table.
|
||||
static inline size_t CPy_FindAttrOffset(PyTypeObject *trait, CPyVTableItem *vtable, size_t index) {
|
||||
int i;
|
||||
for (i = -3; ; i -= 3) {
|
||||
if ((PyTypeObject *)vtable[i] == trait) {
|
||||
return ((size_t *)vtable[i + 2])[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get attribute value using vtable (may return an undefined value)
|
||||
#define CPY_GET_ATTR(obj, type, vtable_index, object_type, attr_type) \
|
||||
((attr_type (*)(object_type *))((object_type *)obj)->vtable[vtable_index])((object_type *)obj)
|
||||
|
||||
#define CPY_GET_ATTR_TRAIT(obj, trait, vtable_index, object_type, attr_type) \
|
||||
((attr_type (*)(object_type *))(CPy_FindTraitVtable(trait, ((object_type *)obj)->vtable))[vtable_index])((object_type *)obj)
|
||||
|
||||
// Set attribute value using vtable
|
||||
#define CPY_SET_ATTR(obj, type, vtable_index, value, object_type, attr_type) \
|
||||
((bool (*)(object_type *, attr_type))((object_type *)obj)->vtable[vtable_index])( \
|
||||
(object_type *)obj, value)
|
||||
|
||||
#define CPY_SET_ATTR_TRAIT(obj, trait, vtable_index, value, object_type, attr_type) \
|
||||
((bool (*)(object_type *, attr_type))(CPy_FindTraitVtable(trait, ((object_type *)obj)->vtable))[vtable_index])( \
|
||||
(object_type *)obj, value)
|
||||
|
||||
#define CPY_GET_METHOD(obj, type, vtable_index, object_type, method_type) \
|
||||
((method_type)(((object_type *)obj)->vtable[vtable_index]))
|
||||
|
||||
#define CPY_GET_METHOD_TRAIT(obj, trait, vtable_index, object_type, method_type) \
|
||||
((method_type)(CPy_FindTraitVtable(trait, ((object_type *)obj)->vtable)[vtable_index]))
|
||||
|
||||
|
||||
// Int operations
|
||||
|
||||
|
||||
CPyTagged CPyTagged_FromSsize_t(Py_ssize_t value);
|
||||
CPyTagged CPyTagged_FromObject(PyObject *object);
|
||||
CPyTagged CPyTagged_StealFromObject(PyObject *object);
|
||||
CPyTagged CPyTagged_BorrowFromObject(PyObject *object);
|
||||
PyObject *CPyTagged_AsObject(CPyTagged x);
|
||||
PyObject *CPyTagged_StealAsObject(CPyTagged x);
|
||||
Py_ssize_t CPyTagged_AsSsize_t(CPyTagged x);
|
||||
void CPyTagged_IncRef(CPyTagged x);
|
||||
void CPyTagged_DecRef(CPyTagged x);
|
||||
void CPyTagged_XDecRef(CPyTagged x);
|
||||
CPyTagged CPyTagged_Negate(CPyTagged num);
|
||||
CPyTagged CPyTagged_Invert(CPyTagged num);
|
||||
CPyTagged CPyTagged_Add(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_Subtract(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_Multiply(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_FloorDivide(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_Remainder(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_And(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_Or(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_Xor(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_Rshift(CPyTagged left, CPyTagged right);
|
||||
CPyTagged CPyTagged_Lshift(CPyTagged left, CPyTagged right);
|
||||
bool CPyTagged_IsEq_(CPyTagged left, CPyTagged right);
|
||||
bool CPyTagged_IsLt_(CPyTagged left, CPyTagged right);
|
||||
PyObject *CPyTagged_Str(CPyTagged n);
|
||||
PyObject *CPyLong_FromStrWithBase(PyObject *o, CPyTagged base);
|
||||
PyObject *CPyLong_FromStr(PyObject *o);
|
||||
PyObject *CPyLong_FromFloat(PyObject *o);
|
||||
PyObject *CPyBool_Str(bool b);
|
||||
|
||||
static inline int CPyTagged_CheckLong(CPyTagged x) {
|
||||
return x & CPY_INT_TAG;
|
||||
}
|
||||
|
||||
static inline int CPyTagged_CheckShort(CPyTagged x) {
|
||||
return !CPyTagged_CheckLong(x);
|
||||
}
|
||||
|
||||
static inline void CPyTagged_INCREF(CPyTagged x) {
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
CPyTagged_IncRef(x);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void CPyTagged_DECREF(CPyTagged x) {
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
CPyTagged_DecRef(x);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void CPyTagged_XDECREF(CPyTagged x) {
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
CPyTagged_XDecRef(x);
|
||||
}
|
||||
}
|
||||
|
||||
static inline Py_ssize_t CPyTagged_ShortAsSsize_t(CPyTagged x) {
|
||||
// NOTE: Assume that we sign extend.
|
||||
return (Py_ssize_t)x >> 1;
|
||||
}
|
||||
|
||||
static inline PyObject *CPyTagged_LongAsObject(CPyTagged x) {
|
||||
// NOTE: Assume target is not a short int.
|
||||
return (PyObject *)(x & ~CPY_INT_TAG);
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_TooBig(Py_ssize_t value) {
|
||||
// Micro-optimized for the common case where it fits.
|
||||
return (size_t)value > CPY_TAGGED_MAX
|
||||
&& (value >= 0 || value < CPY_TAGGED_MIN);
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsAddOverflow(CPyTagged sum, CPyTagged left, CPyTagged right) {
|
||||
// This check was copied from some of my old code I believe that it works :-)
|
||||
return (Py_ssize_t)(sum ^ left) < 0 && (Py_ssize_t)(sum ^ right) < 0;
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsSubtractOverflow(CPyTagged diff, CPyTagged left, CPyTagged right) {
|
||||
// This check was copied from some of my old code I believe that it works :-)
|
||||
return (Py_ssize_t)(diff ^ left) < 0 && (Py_ssize_t)(diff ^ right) >= 0;
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsMultiplyOverflow(CPyTagged left, CPyTagged right) {
|
||||
// This is conservative -- return false only in a small number of all non-overflow cases
|
||||
return left >= (1U << (CPY_INT_BITS/2 - 1)) || right >= (1U << (CPY_INT_BITS/2 - 1));
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_MaybeFloorDivideFault(CPyTagged left, CPyTagged right) {
|
||||
return right == 0 || left == -((size_t)1 << (CPY_INT_BITS-1));
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_MaybeRemainderFault(CPyTagged left, CPyTagged right) {
|
||||
// Division/modulus can fault when dividing INT_MIN by -1, but we
|
||||
// do our mods on still-tagged integers with the low-bit clear, so
|
||||
// -1 is actually represented as -2 and can't overflow.
|
||||
// Mod by 0 can still fault though.
|
||||
return right == 0;
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsEq(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left)) {
|
||||
return left == right;
|
||||
} else {
|
||||
return CPyTagged_IsEq_(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsNe(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left)) {
|
||||
return left != right;
|
||||
} else {
|
||||
return !CPyTagged_IsEq_(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsLt(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) {
|
||||
return (Py_ssize_t)left < (Py_ssize_t)right;
|
||||
} else {
|
||||
return CPyTagged_IsLt_(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsGe(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) {
|
||||
return (Py_ssize_t)left >= (Py_ssize_t)right;
|
||||
} else {
|
||||
return !CPyTagged_IsLt_(left, right);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsGt(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) {
|
||||
return (Py_ssize_t)left > (Py_ssize_t)right;
|
||||
} else {
|
||||
return CPyTagged_IsLt_(right, left);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool CPyTagged_IsLe(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) {
|
||||
return (Py_ssize_t)left <= (Py_ssize_t)right;
|
||||
} else {
|
||||
return !CPyTagged_IsLt_(right, left);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generic operations (that work with arbitrary types)
|
||||
|
||||
|
||||
/* We use intentionally non-inlined decrefs in rarely executed code
|
||||
* paths since it pretty substantially speeds up compile time. We have
|
||||
* our own copies both to avoid the null check in Py_DecRef and to avoid
|
||||
* making an indirect PIC call. */
|
||||
CPy_NOINLINE
|
||||
static void CPy_DecRef(PyObject *p) {
|
||||
CPy_DECREF(p);
|
||||
}
|
||||
|
||||
CPy_NOINLINE
|
||||
static void CPy_XDecRef(PyObject *p) {
|
||||
CPy_XDECREF(p);
|
||||
}
|
||||
|
||||
static inline CPyTagged CPyObject_Size(PyObject *obj) {
|
||||
Py_ssize_t s = PyObject_Size(obj);
|
||||
if (s < 0) {
|
||||
return CPY_INT_TAG;
|
||||
} else {
|
||||
// Technically __len__ could return a really big number, so we
|
||||
// should allow this to produce a boxed int. In practice it
|
||||
// shouldn't ever if the data structure actually contains all
|
||||
// the elements, but...
|
||||
return CPyTagged_FromSsize_t(s);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef MYPYC_LOG_GETATTR
|
||||
static void CPy_LogGetAttr(const char *method, PyObject *obj, PyObject *attr) {
|
||||
PyObject *module = PyImport_ImportModule("getattr_hook");
|
||||
if (module) {
|
||||
PyObject *res = PyObject_CallMethodObjArgs(module, method, obj, attr, NULL);
|
||||
Py_XDECREF(res);
|
||||
Py_DECREF(module);
|
||||
}
|
||||
PyErr_Clear();
|
||||
}
|
||||
#else
|
||||
#define CPy_LogGetAttr(method, obj, attr) (void)0
|
||||
#endif
|
||||
|
||||
// Intercept a method call and log it. This needs to be a macro
|
||||
// because there is no API that accepts va_args for making a
|
||||
// call. Worse, it needs to use the comma operator to return the right
|
||||
// value.
|
||||
#define CPyObject_CallMethodObjArgs(obj, attr, ...) \
|
||||
(CPy_LogGetAttr("log_method", (obj), (attr)), \
|
||||
PyObject_CallMethodObjArgs((obj), (attr), __VA_ARGS__))
|
||||
|
||||
// This one is a macro for consistency with the above, I guess.
|
||||
#define CPyObject_GetAttr(obj, attr) \
|
||||
(CPy_LogGetAttr("log", (obj), (attr)), \
|
||||
PyObject_GetAttr((obj), (attr)))
|
||||
|
||||
CPyTagged CPyObject_Hash(PyObject *o);
|
||||
PyObject *CPyObject_GetAttr3(PyObject *v, PyObject *name, PyObject *defl);
|
||||
PyObject *CPyIter_Next(PyObject *iter);
|
||||
PyObject *CPyNumber_Power(PyObject *base, PyObject *index);
|
||||
PyObject *CPyObject_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end);
|
||||
|
||||
|
||||
// List operations
|
||||
|
||||
|
||||
PyObject *CPyList_Build(Py_ssize_t len, ...);
|
||||
PyObject *CPyList_GetItem(PyObject *list, CPyTagged index);
|
||||
PyObject *CPyList_GetItemUnsafe(PyObject *list, CPyTagged index);
|
||||
PyObject *CPyList_GetItemShort(PyObject *list, CPyTagged index);
|
||||
bool CPyList_SetItem(PyObject *list, CPyTagged index, PyObject *value);
|
||||
bool CPyList_SetItemUnsafe(PyObject *list, CPyTagged index, PyObject *value);
|
||||
PyObject *CPyList_PopLast(PyObject *obj);
|
||||
PyObject *CPyList_Pop(PyObject *obj, CPyTagged index);
|
||||
CPyTagged CPyList_Count(PyObject *obj, PyObject *value);
|
||||
int CPyList_Insert(PyObject *list, CPyTagged index, PyObject *value);
|
||||
PyObject *CPyList_Extend(PyObject *o1, PyObject *o2);
|
||||
int CPyList_Remove(PyObject *list, PyObject *obj);
|
||||
CPyTagged CPyList_Index(PyObject *list, PyObject *obj);
|
||||
PyObject *CPySequence_Multiply(PyObject *seq, CPyTagged t_size);
|
||||
PyObject *CPySequence_RMultiply(CPyTagged t_size, PyObject *seq);
|
||||
PyObject *CPyList_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end);
|
||||
|
||||
|
||||
// Dict operations
|
||||
|
||||
|
||||
PyObject *CPyDict_GetItem(PyObject *dict, PyObject *key);
|
||||
int CPyDict_SetItem(PyObject *dict, PyObject *key, PyObject *value);
|
||||
PyObject *CPyDict_Get(PyObject *dict, PyObject *key, PyObject *fallback);
|
||||
PyObject *CPyDict_GetWithNone(PyObject *dict, PyObject *key);
|
||||
PyObject *CPyDict_SetDefault(PyObject *dict, PyObject *key, PyObject *value);
|
||||
PyObject *CPyDict_SetDefaultWithNone(PyObject *dict, PyObject *key);
|
||||
PyObject *CPyDict_SetDefaultWithEmptyDatatype(PyObject *dict, PyObject *key, int data_type);
|
||||
PyObject *CPyDict_Build(Py_ssize_t size, ...);
|
||||
int CPyDict_Update(PyObject *dict, PyObject *stuff);
|
||||
int CPyDict_UpdateInDisplay(PyObject *dict, PyObject *stuff);
|
||||
int CPyDict_UpdateFromAny(PyObject *dict, PyObject *stuff);
|
||||
PyObject *CPyDict_FromAny(PyObject *obj);
|
||||
PyObject *CPyDict_KeysView(PyObject *dict);
|
||||
PyObject *CPyDict_ValuesView(PyObject *dict);
|
||||
PyObject *CPyDict_ItemsView(PyObject *dict);
|
||||
PyObject *CPyDict_Keys(PyObject *dict);
|
||||
PyObject *CPyDict_Values(PyObject *dict);
|
||||
PyObject *CPyDict_Items(PyObject *dict);
|
||||
char CPyDict_Clear(PyObject *dict);
|
||||
PyObject *CPyDict_Copy(PyObject *dict);
|
||||
PyObject *CPyDict_GetKeysIter(PyObject *dict);
|
||||
PyObject *CPyDict_GetItemsIter(PyObject *dict);
|
||||
PyObject *CPyDict_GetValuesIter(PyObject *dict);
|
||||
tuple_T3CIO CPyDict_NextKey(PyObject *dict_or_iter, CPyTagged offset);
|
||||
tuple_T3CIO CPyDict_NextValue(PyObject *dict_or_iter, CPyTagged offset);
|
||||
tuple_T4CIOO CPyDict_NextItem(PyObject *dict_or_iter, CPyTagged offset);
|
||||
|
||||
// Check that dictionary didn't change size during iteration.
|
||||
static inline char CPyDict_CheckSize(PyObject *dict, CPyTagged size) {
|
||||
if (!PyDict_CheckExact(dict)) {
|
||||
// Dict subclasses will be checked by Python runtime.
|
||||
return 1;
|
||||
}
|
||||
Py_ssize_t py_size = CPyTagged_AsSsize_t(size);
|
||||
Py_ssize_t dict_size = PyDict_Size(dict);
|
||||
if (py_size != dict_size) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Str operations
|
||||
|
||||
|
||||
PyObject *CPyStr_Build(Py_ssize_t len, ...);
|
||||
PyObject *CPyStr_GetItem(PyObject *str, CPyTagged index);
|
||||
PyObject *CPyStr_Split(PyObject *str, PyObject *sep, CPyTagged max_split);
|
||||
PyObject *CPyStr_Replace(PyObject *str, PyObject *old_substr, PyObject *new_substr, CPyTagged max_replace);
|
||||
PyObject *CPyStr_Append(PyObject *o1, PyObject *o2);
|
||||
PyObject *CPyStr_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end);
|
||||
bool CPyStr_Startswith(PyObject *self, PyObject *subobj);
|
||||
bool CPyStr_Endswith(PyObject *self, PyObject *subobj);
|
||||
bool CPyStr_IsTrue(PyObject *obj);
|
||||
Py_ssize_t CPyStr_Size_size_t(PyObject *str);
|
||||
PyObject *CPy_Decode(PyObject *obj, PyObject *encoding, PyObject *errors);
|
||||
PyObject *CPy_Encode(PyObject *obj, PyObject *encoding, PyObject *errors);
|
||||
|
||||
|
||||
// Bytes operations
|
||||
|
||||
|
||||
PyObject *CPyBytes_Build(Py_ssize_t len, ...);
|
||||
PyObject *CPyBytes_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end);
|
||||
CPyTagged CPyBytes_GetItem(PyObject *o, CPyTagged index);
|
||||
PyObject *CPyBytes_Concat(PyObject *a, PyObject *b);
|
||||
PyObject *CPyBytes_Join(PyObject *sep, PyObject *iter);
|
||||
|
||||
|
||||
int CPyBytes_Compare(PyObject *left, PyObject *right);
|
||||
|
||||
|
||||
|
||||
// Set operations
|
||||
|
||||
|
||||
bool CPySet_Remove(PyObject *set, PyObject *key);
|
||||
|
||||
|
||||
// Tuple operations
|
||||
|
||||
|
||||
PyObject *CPySequenceTuple_GetItem(PyObject *tuple, CPyTagged index);
|
||||
PyObject *CPySequenceTuple_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end);
|
||||
bool CPySequenceTuple_SetItemUnsafe(PyObject *tuple, CPyTagged index, PyObject *value);
|
||||
|
||||
|
||||
// Exception operations
|
||||
|
||||
|
||||
// mypyc is not very good at dealing with refcount management of
|
||||
// pointers that might be NULL. As a workaround for this, the
|
||||
// exception APIs that might want to return NULL pointers instead
|
||||
// return properly refcounted pointers to this dummy object.
|
||||
struct ExcDummyStruct { PyObject_HEAD };
|
||||
extern struct ExcDummyStruct _CPy_ExcDummyStruct;
|
||||
extern PyObject *_CPy_ExcDummy;
|
||||
|
||||
static inline void _CPy_ToDummy(PyObject **p) {
|
||||
if (*p == NULL) {
|
||||
Py_INCREF(_CPy_ExcDummy);
|
||||
*p = _CPy_ExcDummy;
|
||||
}
|
||||
}
|
||||
|
||||
static inline PyObject *_CPy_FromDummy(PyObject *p) {
|
||||
if (p == _CPy_ExcDummy) return NULL;
|
||||
Py_INCREF(p);
|
||||
return p;
|
||||
}
|
||||
|
||||
static int CPy_NoErrOccured(void) {
|
||||
return PyErr_Occurred() == NULL;
|
||||
}
|
||||
|
||||
static inline bool CPy_KeepPropagating(void) {
|
||||
return 0;
|
||||
}
|
||||
// We want to avoid the public PyErr_GetExcInfo API for these because
|
||||
// it requires a bunch of spurious refcount traffic on the parts of
|
||||
// the triple we don't care about. Unfortunately the layout of the
|
||||
// data structure changed in 3.7 so we need to handle that.
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
|
||||
#define CPy_ExcState() PyThreadState_GET()->exc_info
|
||||
#else
|
||||
#define CPy_ExcState() PyThreadState_GET()
|
||||
#endif
|
||||
|
||||
void CPy_Raise(PyObject *exc);
|
||||
void CPy_Reraise(void);
|
||||
void CPyErr_SetObjectAndTraceback(PyObject *type, PyObject *value, PyObject *traceback);
|
||||
tuple_T3OOO CPy_CatchError(void);
|
||||
void CPy_RestoreExcInfo(tuple_T3OOO info);
|
||||
bool CPy_ExceptionMatches(PyObject *type);
|
||||
PyObject *CPy_GetExcValue(void);
|
||||
tuple_T3OOO CPy_GetExcInfo(void);
|
||||
void _CPy_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback);
|
||||
void CPyError_OutOfMemory(void);
|
||||
void CPy_TypeError(const char *expected, PyObject *value);
|
||||
void CPy_AddTraceback(const char *filename, const char *funcname, int line, PyObject *globals);
|
||||
|
||||
|
||||
// Misc operations
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 8
|
||||
#define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN(op, dealloc)
|
||||
#define CPy_TRASHCAN_END(op) Py_TRASHCAN_END
|
||||
#else
|
||||
#define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_SAFE_BEGIN(op)
|
||||
#define CPy_TRASHCAN_END(op) Py_TRASHCAN_SAFE_END(op)
|
||||
#endif
|
||||
|
||||
// Tweaked version of _PyArg_Parser in CPython
|
||||
typedef struct CPyArg_Parser {
|
||||
const char *format;
|
||||
const char * const *keywords;
|
||||
const char *fname;
|
||||
const char *custom_msg;
|
||||
int pos; /* number of positional-only arguments */
|
||||
int min; /* minimal number of arguments */
|
||||
int max; /* maximal number of positional arguments */
|
||||
int has_required_kws; /* are there any keyword-only arguments? */
|
||||
int required_kwonly_start;
|
||||
int varargs; /* does the function accept *args or **kwargs? */
|
||||
PyObject *kwtuple; /* tuple of keyword parameter names */
|
||||
struct CPyArg_Parser *next;
|
||||
} CPyArg_Parser;
|
||||
|
||||
// mypy lets ints silently coerce to floats, so a mypyc runtime float
|
||||
// might be an int also
|
||||
static inline bool CPyFloat_Check(PyObject *o) {
|
||||
return PyFloat_Check(o) || PyLong_Check(o);
|
||||
}
|
||||
|
||||
// TODO: find an unified way to avoid inline functions in non-C back ends that can not
|
||||
// use inline functions
|
||||
static inline bool CPy_TypeCheck(PyObject *o, PyObject *type) {
|
||||
return PyObject_TypeCheck(o, (PyTypeObject *)type);
|
||||
}
|
||||
|
||||
static inline PyObject *CPy_CalculateMetaclass(PyObject *type, PyObject *o) {
|
||||
return (PyObject *)_PyType_CalculateMetaclass((PyTypeObject *)type, o);
|
||||
}
|
||||
|
||||
PyObject *CPy_GetCoro(PyObject *obj);
|
||||
PyObject *CPyIter_Send(PyObject *iter, PyObject *val);
|
||||
int CPy_YieldFromErrorHandle(PyObject *iter, PyObject **outp);
|
||||
PyObject *CPy_FetchStopIterationValue(void);
|
||||
PyObject *CPyType_FromTemplate(PyObject *template_,
|
||||
PyObject *orig_bases,
|
||||
PyObject *modname);
|
||||
PyObject *CPyType_FromTemplateWarpper(PyObject *template_,
|
||||
PyObject *orig_bases,
|
||||
PyObject *modname);
|
||||
int CPyDataclass_SleightOfHand(PyObject *dataclass_dec, PyObject *tp,
|
||||
PyObject *dict, PyObject *annotations);
|
||||
PyObject *CPyPickle_SetState(PyObject *obj, PyObject *state);
|
||||
PyObject *CPyPickle_GetState(PyObject *obj);
|
||||
CPyTagged CPyTagged_Id(PyObject *o);
|
||||
void CPyDebug_Print(const char *msg);
|
||||
void CPy_Init(void);
|
||||
int CPyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
|
||||
const char *, const char *, const char * const *, ...);
|
||||
int CPyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...);
|
||||
int CPyArg_ParseStackAndKeywordsNoArgs(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...);
|
||||
int CPyArg_ParseStackAndKeywordsOneArg(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...);
|
||||
int CPyArg_ParseStackAndKeywordsSimple(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...);
|
||||
|
||||
int CPySequence_CheckUnpackCount(PyObject *sequence, Py_ssize_t expected);
|
||||
int CPyStatics_Initialize(PyObject **statics,
|
||||
const char * const *strings,
|
||||
const char * const *bytestrings,
|
||||
const char * const *ints,
|
||||
const double *floats,
|
||||
const double *complex_numbers,
|
||||
const int *tuples);
|
||||
PyObject *CPy_Super(PyObject *builtins, PyObject *self);
|
||||
PyObject *CPy_CallReverseOpMethod(PyObject *left, PyObject *right, const char *op,
|
||||
_Py_Identifier *method);
|
||||
|
||||
PyObject *CPyImport_ImportFrom(PyObject *module, PyObject *package_name,
|
||||
PyObject *import_name, PyObject *as_name);
|
||||
|
||||
PyObject *CPySingledispatch_RegisterFunction(PyObject *singledispatch_func, PyObject *cls,
|
||||
PyObject *func);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // CPY_CPY_H
|
||||
Binary file not shown.
143
.venv/lib/python3.8/site-packages/mypyc/lib-rt/bytes_ops.c
Normal file
143
.venv/lib/python3.8/site-packages/mypyc/lib-rt/bytes_ops.c
Normal file
|
|
@ -0,0 +1,143 @@
|
|||
// Bytes primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.bytes_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
// Returns -1 on error, 0 on inequality, 1 on equality.
|
||||
//
|
||||
// Falls back to PyObject_RichCompareBool.
|
||||
int CPyBytes_Compare(PyObject *left, PyObject *right) {
|
||||
if (PyBytes_CheckExact(left) && PyBytes_CheckExact(right)) {
|
||||
if (left == right) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Adapted from cpython internal implementation of bytes_compare.
|
||||
Py_ssize_t len = Py_SIZE(left);
|
||||
if (Py_SIZE(right) != len) {
|
||||
return 0;
|
||||
}
|
||||
PyBytesObject *left_b = (PyBytesObject *)left;
|
||||
PyBytesObject *right_b = (PyBytesObject *)right;
|
||||
if (left_b->ob_sval[0] != right_b->ob_sval[0]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return memcmp(left_b->ob_sval, right_b->ob_sval, len) == 0;
|
||||
}
|
||||
return PyObject_RichCompareBool(left, right, Py_EQ);
|
||||
}
|
||||
|
||||
CPyTagged CPyBytes_GetItem(PyObject *o, CPyTagged index) {
|
||||
if (CPyTagged_CheckShort(index)) {
|
||||
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
||||
Py_ssize_t size = ((PyVarObject *)o)->ob_size;
|
||||
if (n < 0)
|
||||
n += size;
|
||||
if (n < 0 || n >= size) {
|
||||
PyErr_SetString(PyExc_IndexError, "index out of range");
|
||||
return CPY_INT_TAG;
|
||||
}
|
||||
unsigned char num = PyBytes_Check(o) ? ((PyBytesObject *)o)->ob_sval[n]
|
||||
: ((PyByteArrayObject *)o)->ob_bytes[n];
|
||||
return num << 1;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
||||
return CPY_INT_TAG;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyBytes_Concat(PyObject *a, PyObject *b) {
|
||||
if (PyBytes_Check(a) && PyBytes_Check(b)) {
|
||||
Py_ssize_t a_len = ((PyVarObject *)a)->ob_size;
|
||||
Py_ssize_t b_len = ((PyVarObject *)b)->ob_size;
|
||||
PyBytesObject *ret = (PyBytesObject *)PyBytes_FromStringAndSize(NULL, a_len + b_len);
|
||||
if (ret != NULL) {
|
||||
memcpy(ret->ob_sval, ((PyBytesObject *)a)->ob_sval, a_len);
|
||||
memcpy(ret->ob_sval + a_len, ((PyBytesObject *)b)->ob_sval, b_len);
|
||||
}
|
||||
return (PyObject *)ret;
|
||||
} else if (PyByteArray_Check(a)) {
|
||||
return PyByteArray_Concat(a, b);
|
||||
} else {
|
||||
PyBytes_Concat(&a, b);
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
static inline Py_ssize_t Clamp(Py_ssize_t a, Py_ssize_t b, Py_ssize_t c) {
|
||||
return a < b ? b : (a >= c ? c : a);
|
||||
}
|
||||
|
||||
PyObject *CPyBytes_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end) {
|
||||
if ((PyBytes_Check(obj) || PyByteArray_Check(obj))
|
||||
&& CPyTagged_CheckShort(start) && CPyTagged_CheckShort(end)) {
|
||||
Py_ssize_t startn = CPyTagged_ShortAsSsize_t(start);
|
||||
Py_ssize_t endn = CPyTagged_ShortAsSsize_t(end);
|
||||
Py_ssize_t len = ((PyVarObject *)obj)->ob_size;
|
||||
if (startn < 0) {
|
||||
startn += len;
|
||||
}
|
||||
if (endn < 0) {
|
||||
endn += len;
|
||||
}
|
||||
startn = Clamp(startn, 0, len);
|
||||
endn = Clamp(endn, 0, len);
|
||||
Py_ssize_t slice_len = endn - startn;
|
||||
if (PyBytes_Check(obj)) {
|
||||
return PyBytes_FromStringAndSize(PyBytes_AS_STRING(obj) + startn, slice_len);
|
||||
} else {
|
||||
return PyByteArray_FromStringAndSize(PyByteArray_AS_STRING(obj) + startn, slice_len);
|
||||
}
|
||||
}
|
||||
return CPyObject_GetSlice(obj, start, end);
|
||||
}
|
||||
|
||||
// Like _PyBytes_Join but fallback to dynamic call if 'sep' is not bytes
|
||||
// (mostly commonly, for bytearrays)
|
||||
PyObject *CPyBytes_Join(PyObject *sep, PyObject *iter) {
|
||||
if (PyBytes_CheckExact(sep)) {
|
||||
return _PyBytes_Join(sep, iter);
|
||||
} else {
|
||||
_Py_IDENTIFIER(join);
|
||||
return _PyObject_CallMethodIdOneArg(sep, &PyId_join, iter);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyBytes_Build(Py_ssize_t len, ...) {
|
||||
Py_ssize_t i;
|
||||
Py_ssize_t sz = 0;
|
||||
|
||||
va_list args;
|
||||
va_start(args, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
PyObject *item = va_arg(args, PyObject *);
|
||||
size_t add_sz = ((PyVarObject *)item)->ob_size;
|
||||
// Using size_t to avoid overflow during arithmetic calculation
|
||||
if (add_sz > (size_t)(PY_SSIZE_T_MAX - sz)) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"join() result is too long for a Python bytes");
|
||||
return NULL;
|
||||
}
|
||||
sz += add_sz;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
PyBytesObject *ret = (PyBytesObject *)PyBytes_FromStringAndSize(NULL, sz);
|
||||
if (ret != NULL) {
|
||||
char *res_data = ret->ob_sval;
|
||||
va_start(args, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
PyObject *item = va_arg(args, PyObject *);
|
||||
Py_ssize_t item_sz = ((PyVarObject *)item)->ob_size;
|
||||
memcpy(res_data, ((PyBytesObject *)item)->ob_sval, item_sz);
|
||||
res_data += item_sz;
|
||||
}
|
||||
va_end(args);
|
||||
assert(res_data == ret->ob_sval + ((PyVarObject *)ret)->ob_size);
|
||||
}
|
||||
|
||||
return (PyObject *)ret;
|
||||
}
|
||||
438
.venv/lib/python3.8/site-packages/mypyc/lib-rt/dict_ops.c
Normal file
438
.venv/lib/python3.8/site-packages/mypyc/lib-rt/dict_ops.c
Normal file
|
|
@ -0,0 +1,438 @@
|
|||
// Dict primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.dict_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
// Dict subclasses like defaultdict override things in interesting
|
||||
// ways, so we don't want to just directly use the dict methods. Not
|
||||
// sure if it is actually worth doing all this stuff, but it saves
|
||||
// some indirections.
|
||||
PyObject *CPyDict_GetItem(PyObject *dict, PyObject *key) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
PyObject *res = PyDict_GetItemWithError(dict, key);
|
||||
if (!res) {
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetObject(PyExc_KeyError, key);
|
||||
}
|
||||
} else {
|
||||
Py_INCREF(res);
|
||||
}
|
||||
return res;
|
||||
} else {
|
||||
return PyObject_GetItem(dict, key);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyDict_Build(Py_ssize_t size, ...) {
|
||||
Py_ssize_t i;
|
||||
|
||||
PyObject *res = _PyDict_NewPresized(size);
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args, size);
|
||||
|
||||
for (i = 0; i < size; i++) {
|
||||
PyObject *key = va_arg(args, PyObject *);
|
||||
PyObject *value = va_arg(args, PyObject *);
|
||||
if (PyDict_SetItem(res, key, value)) {
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyObject *CPyDict_Get(PyObject *dict, PyObject *key, PyObject *fallback) {
|
||||
// We are dodgily assuming that get on a subclass doesn't have
|
||||
// different behavior.
|
||||
PyObject *res = PyDict_GetItemWithError(dict, key);
|
||||
if (!res) {
|
||||
if (PyErr_Occurred()) {
|
||||
return NULL;
|
||||
}
|
||||
res = fallback;
|
||||
}
|
||||
Py_INCREF(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
PyObject *CPyDict_GetWithNone(PyObject *dict, PyObject *key) {
|
||||
return CPyDict_Get(dict, key, Py_None);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_SetDefault(PyObject *dict, PyObject *key, PyObject *value) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
PyObject* ret = PyDict_SetDefault(dict, key, value);
|
||||
Py_XINCREF(ret);
|
||||
return ret;
|
||||
}
|
||||
_Py_IDENTIFIER(setdefault);
|
||||
return _PyObject_CallMethodIdObjArgs(dict, &PyId_setdefault, key, value, NULL);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_SetDefaultWithNone(PyObject *dict, PyObject *key) {
|
||||
return CPyDict_SetDefault(dict, key, Py_None);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_SetDefaultWithEmptyDatatype(PyObject *dict, PyObject *key,
|
||||
int data_type) {
|
||||
PyObject *res = CPyDict_GetItem(dict, key);
|
||||
if (!res) {
|
||||
// CPyDict_GetItem() would generates an PyExc_KeyError
|
||||
// when key is not found.
|
||||
PyErr_Clear();
|
||||
|
||||
PyObject *new_obj;
|
||||
if (data_type == 1) {
|
||||
new_obj = PyList_New(0);
|
||||
} else if (data_type == 2) {
|
||||
new_obj = PyDict_New();
|
||||
} else if (data_type == 3) {
|
||||
new_obj = PySet_New(NULL);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (CPyDict_SetItem(dict, key, new_obj) == -1) {
|
||||
return NULL;
|
||||
} else {
|
||||
return new_obj;
|
||||
}
|
||||
} else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
int CPyDict_SetItem(PyObject *dict, PyObject *key, PyObject *value) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
return PyDict_SetItem(dict, key, value);
|
||||
} else {
|
||||
return PyObject_SetItem(dict, key, value);
|
||||
}
|
||||
}
|
||||
|
||||
static inline int CPy_ObjectToStatus(PyObject *obj) {
|
||||
if (obj) {
|
||||
Py_DECREF(obj);
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static int CPyDict_UpdateGeneral(PyObject *dict, PyObject *stuff) {
|
||||
_Py_IDENTIFIER(update);
|
||||
PyObject *res = _PyObject_CallMethodIdOneArg(dict, &PyId_update, stuff);
|
||||
return CPy_ObjectToStatus(res);
|
||||
}
|
||||
|
||||
int CPyDict_UpdateInDisplay(PyObject *dict, PyObject *stuff) {
|
||||
// from https://github.com/python/cpython/blob/55d035113dfb1bd90495c8571758f504ae8d4802/Python/ceval.c#L2710
|
||||
int ret = PyDict_Update(dict, stuff);
|
||||
if (ret < 0) {
|
||||
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%.200s' object is not a mapping",
|
||||
Py_TYPE(stuff)->tp_name);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int CPyDict_Update(PyObject *dict, PyObject *stuff) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
return PyDict_Update(dict, stuff);
|
||||
} else {
|
||||
return CPyDict_UpdateGeneral(dict, stuff);
|
||||
}
|
||||
}
|
||||
|
||||
int CPyDict_UpdateFromAny(PyObject *dict, PyObject *stuff) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
// Argh this sucks
|
||||
_Py_IDENTIFIER(keys);
|
||||
if (PyDict_Check(stuff) || _CPyObject_HasAttrId(stuff, &PyId_keys)) {
|
||||
return PyDict_Update(dict, stuff);
|
||||
} else {
|
||||
return PyDict_MergeFromSeq2(dict, stuff, 1);
|
||||
}
|
||||
} else {
|
||||
return CPyDict_UpdateGeneral(dict, stuff);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyDict_FromAny(PyObject *obj) {
|
||||
if (PyDict_Check(obj)) {
|
||||
return PyDict_Copy(obj);
|
||||
} else {
|
||||
int res;
|
||||
PyObject *dict = PyDict_New();
|
||||
if (!dict) {
|
||||
return NULL;
|
||||
}
|
||||
_Py_IDENTIFIER(keys);
|
||||
if (_CPyObject_HasAttrId(obj, &PyId_keys)) {
|
||||
res = PyDict_Update(dict, obj);
|
||||
} else {
|
||||
res = PyDict_MergeFromSeq2(dict, obj, 1);
|
||||
}
|
||||
if (res < 0) {
|
||||
Py_DECREF(dict);
|
||||
return NULL;
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyDict_KeysView(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)){
|
||||
return _CPyDictView_New(dict, &PyDictKeys_Type);
|
||||
}
|
||||
_Py_IDENTIFIER(keys);
|
||||
return _PyObject_CallMethodIdNoArgs(dict, &PyId_keys);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_ValuesView(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)){
|
||||
return _CPyDictView_New(dict, &PyDictValues_Type);
|
||||
}
|
||||
_Py_IDENTIFIER(values);
|
||||
return _PyObject_CallMethodIdNoArgs(dict, &PyId_values);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_ItemsView(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)){
|
||||
return _CPyDictView_New(dict, &PyDictItems_Type);
|
||||
}
|
||||
_Py_IDENTIFIER(items);
|
||||
return _PyObject_CallMethodIdNoArgs(dict, &PyId_items);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_Keys(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
return PyDict_Keys(dict);
|
||||
}
|
||||
// Inline generic fallback logic to also return a list.
|
||||
PyObject *list = PyList_New(0);
|
||||
_Py_IDENTIFIER(keys);
|
||||
PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_keys);
|
||||
if (view == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *res = _PyList_Extend((PyListObject *)list, view);
|
||||
Py_DECREF(view);
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
return list;
|
||||
}
|
||||
|
||||
PyObject *CPyDict_Values(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
return PyDict_Values(dict);
|
||||
}
|
||||
// Inline generic fallback logic to also return a list.
|
||||
PyObject *list = PyList_New(0);
|
||||
_Py_IDENTIFIER(values);
|
||||
PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_values);
|
||||
if (view == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *res = _PyList_Extend((PyListObject *)list, view);
|
||||
Py_DECREF(view);
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
return list;
|
||||
}
|
||||
|
||||
PyObject *CPyDict_Items(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
return PyDict_Items(dict);
|
||||
}
|
||||
// Inline generic fallback logic to also return a list.
|
||||
PyObject *list = PyList_New(0);
|
||||
_Py_IDENTIFIER(items);
|
||||
PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_items);
|
||||
if (view == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *res = _PyList_Extend((PyListObject *)list, view);
|
||||
Py_DECREF(view);
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
return list;
|
||||
}
|
||||
|
||||
char CPyDict_Clear(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
PyDict_Clear(dict);
|
||||
} else {
|
||||
_Py_IDENTIFIER(clear);
|
||||
PyObject *res = _PyObject_CallMethodIdNoArgs(dict, &PyId_clear);
|
||||
if (res == NULL) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
PyObject *CPyDict_Copy(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
return PyDict_Copy(dict);
|
||||
}
|
||||
_Py_IDENTIFIER(copy);
|
||||
return _PyObject_CallMethodIdNoArgs(dict, &PyId_copy);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_GetKeysIter(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
// Return dict itself to indicate we can use fast path instead.
|
||||
Py_INCREF(dict);
|
||||
return dict;
|
||||
}
|
||||
return PyObject_GetIter(dict);
|
||||
}
|
||||
|
||||
PyObject *CPyDict_GetItemsIter(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
// Return dict itself to indicate we can use fast path instead.
|
||||
Py_INCREF(dict);
|
||||
return dict;
|
||||
}
|
||||
_Py_IDENTIFIER(items);
|
||||
PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_items);
|
||||
if (view == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *iter = PyObject_GetIter(view);
|
||||
Py_DECREF(view);
|
||||
return iter;
|
||||
}
|
||||
|
||||
PyObject *CPyDict_GetValuesIter(PyObject *dict) {
|
||||
if (PyDict_CheckExact(dict)) {
|
||||
// Return dict itself to indicate we can use fast path instead.
|
||||
Py_INCREF(dict);
|
||||
return dict;
|
||||
}
|
||||
_Py_IDENTIFIER(values);
|
||||
PyObject *view = _PyObject_CallMethodIdNoArgs(dict, &PyId_values);
|
||||
if (view == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *iter = PyObject_GetIter(view);
|
||||
Py_DECREF(view);
|
||||
return iter;
|
||||
}
|
||||
|
||||
static void _CPyDict_FromNext(tuple_T3CIO *ret, PyObject *dict_iter) {
|
||||
// Get next item from iterator and set "should continue" flag.
|
||||
ret->f2 = PyIter_Next(dict_iter);
|
||||
if (ret->f2 == NULL) {
|
||||
ret->f0 = 0;
|
||||
Py_INCREF(Py_None);
|
||||
ret->f2 = Py_None;
|
||||
} else {
|
||||
ret->f0 = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers for fast dictionary iteration, return a single tuple
|
||||
// instead of writing to multiple registers, for exact dicts use
|
||||
// the fast path, and fall back to generic iterator logic for subclasses.
|
||||
tuple_T3CIO CPyDict_NextKey(PyObject *dict_or_iter, CPyTagged offset) {
|
||||
tuple_T3CIO ret;
|
||||
Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset);
|
||||
PyObject *dummy;
|
||||
|
||||
if (PyDict_CheckExact(dict_or_iter)) {
|
||||
ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &ret.f2, &dummy);
|
||||
if (ret.f0) {
|
||||
ret.f1 = CPyTagged_FromSsize_t(py_offset);
|
||||
} else {
|
||||
// Set key to None, so mypyc can manage refcounts.
|
||||
ret.f1 = 0;
|
||||
ret.f2 = Py_None;
|
||||
}
|
||||
// PyDict_Next() returns borrowed references.
|
||||
Py_INCREF(ret.f2);
|
||||
} else {
|
||||
// offset is dummy in this case, just use the old value.
|
||||
ret.f1 = offset;
|
||||
_CPyDict_FromNext(&ret, dict_or_iter);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
tuple_T3CIO CPyDict_NextValue(PyObject *dict_or_iter, CPyTagged offset) {
|
||||
tuple_T3CIO ret;
|
||||
Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset);
|
||||
PyObject *dummy;
|
||||
|
||||
if (PyDict_CheckExact(dict_or_iter)) {
|
||||
ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &dummy, &ret.f2);
|
||||
if (ret.f0) {
|
||||
ret.f1 = CPyTagged_FromSsize_t(py_offset);
|
||||
} else {
|
||||
// Set value to None, so mypyc can manage refcounts.
|
||||
ret.f1 = 0;
|
||||
ret.f2 = Py_None;
|
||||
}
|
||||
// PyDict_Next() returns borrowed references.
|
||||
Py_INCREF(ret.f2);
|
||||
} else {
|
||||
// offset is dummy in this case, just use the old value.
|
||||
ret.f1 = offset;
|
||||
_CPyDict_FromNext(&ret, dict_or_iter);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
tuple_T4CIOO CPyDict_NextItem(PyObject *dict_or_iter, CPyTagged offset) {
|
||||
tuple_T4CIOO ret;
|
||||
Py_ssize_t py_offset = CPyTagged_AsSsize_t(offset);
|
||||
|
||||
if (PyDict_CheckExact(dict_or_iter)) {
|
||||
ret.f0 = PyDict_Next(dict_or_iter, &py_offset, &ret.f2, &ret.f3);
|
||||
if (ret.f0) {
|
||||
ret.f1 = CPyTagged_FromSsize_t(py_offset);
|
||||
} else {
|
||||
// Set key and value to None, so mypyc can manage refcounts.
|
||||
ret.f1 = 0;
|
||||
ret.f2 = Py_None;
|
||||
ret.f3 = Py_None;
|
||||
}
|
||||
} else {
|
||||
ret.f1 = offset;
|
||||
PyObject *item = PyIter_Next(dict_or_iter);
|
||||
if (item == NULL || !PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 2) {
|
||||
if (item != NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "a tuple of length 2 expected");
|
||||
}
|
||||
ret.f0 = 0;
|
||||
ret.f2 = Py_None;
|
||||
ret.f3 = Py_None;
|
||||
} else {
|
||||
ret.f0 = 1;
|
||||
ret.f2 = PyTuple_GET_ITEM(item, 0);
|
||||
ret.f3 = PyTuple_GET_ITEM(item, 1);
|
||||
Py_DECREF(item);
|
||||
}
|
||||
}
|
||||
// PyDict_Next() returns borrowed references.
|
||||
Py_INCREF(ret.f2);
|
||||
Py_INCREF(ret.f3);
|
||||
return ret;
|
||||
}
|
||||
227
.venv/lib/python3.8/site-packages/mypyc/lib-rt/exc_ops.c
Normal file
227
.venv/lib/python3.8/site-packages/mypyc/lib-rt/exc_ops.c
Normal file
|
|
@ -0,0 +1,227 @@
|
|||
// Exception related primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.exc_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
void CPy_Raise(PyObject *exc) {
|
||||
if (PyObject_IsInstance(exc, (PyObject *)&PyType_Type)) {
|
||||
PyObject *obj = PyObject_CallFunctionObjArgs(exc, NULL);
|
||||
if (!obj)
|
||||
return;
|
||||
PyErr_SetObject(exc, obj);
|
||||
Py_DECREF(obj);
|
||||
} else {
|
||||
PyErr_SetObject((PyObject *)Py_TYPE(exc), exc);
|
||||
}
|
||||
}
|
||||
|
||||
void CPy_Reraise(void) {
|
||||
PyObject *p_type, *p_value, *p_traceback;
|
||||
PyErr_GetExcInfo(&p_type, &p_value, &p_traceback);
|
||||
PyErr_Restore(p_type, p_value, p_traceback);
|
||||
}
|
||||
|
||||
void CPyErr_SetObjectAndTraceback(PyObject *type, PyObject *value, PyObject *traceback) {
|
||||
// Set the value and traceback of an error. Because calling
|
||||
// PyErr_Restore takes away a reference to each object passed in
|
||||
// as an argument, we manually increase the reference count of
|
||||
// each argument before calling it.
|
||||
Py_INCREF(type);
|
||||
Py_INCREF(value);
|
||||
Py_INCREF(traceback);
|
||||
PyErr_Restore(type, value, traceback);
|
||||
}
|
||||
|
||||
tuple_T3OOO CPy_CatchError(void) {
|
||||
// We need to return the existing sys.exc_info() information, so
|
||||
// that it can be restored when we finish handling the error we
|
||||
// are catching now. Grab that triple and convert NULL values to
|
||||
// the ExcDummy object in order to simplify refcount handling in
|
||||
// generated code.
|
||||
tuple_T3OOO ret;
|
||||
PyErr_GetExcInfo(&ret.f0, &ret.f1, &ret.f2);
|
||||
_CPy_ToDummy(&ret.f0);
|
||||
_CPy_ToDummy(&ret.f1);
|
||||
_CPy_ToDummy(&ret.f2);
|
||||
|
||||
if (!PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_RuntimeError, "CPy_CatchError called with no error!");
|
||||
}
|
||||
|
||||
// Retrieve the error info and normalize it so that it looks like
|
||||
// what python code needs it to be.
|
||||
PyObject *type, *value, *traceback;
|
||||
PyErr_Fetch(&type, &value, &traceback);
|
||||
// Could we avoid always normalizing?
|
||||
PyErr_NormalizeException(&type, &value, &traceback);
|
||||
if (traceback != NULL) {
|
||||
PyException_SetTraceback(value, traceback);
|
||||
}
|
||||
// Indicate that we are now handling this exception by stashing it
|
||||
// in sys.exc_info(). mypyc routines that need access to the
|
||||
// exception will read it out of there.
|
||||
PyErr_SetExcInfo(type, value, traceback);
|
||||
// Clear the error indicator, since the exception isn't
|
||||
// propagating anymore.
|
||||
PyErr_Clear();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CPy_RestoreExcInfo(tuple_T3OOO info) {
|
||||
PyErr_SetExcInfo(_CPy_FromDummy(info.f0), _CPy_FromDummy(info.f1), _CPy_FromDummy(info.f2));
|
||||
}
|
||||
|
||||
bool CPy_ExceptionMatches(PyObject *type) {
|
||||
return PyErr_GivenExceptionMatches(CPy_ExcState()->exc_type, type);
|
||||
}
|
||||
|
||||
PyObject *CPy_GetExcValue(void) {
|
||||
PyObject *exc = CPy_ExcState()->exc_value;
|
||||
Py_INCREF(exc);
|
||||
return exc;
|
||||
}
|
||||
|
||||
static inline void _CPy_ToNone(PyObject **p) {
|
||||
if (*p == NULL) {
|
||||
Py_INCREF(Py_None);
|
||||
*p = Py_None;
|
||||
}
|
||||
}
|
||||
|
||||
void _CPy_GetExcInfo(PyObject **p_type, PyObject **p_value, PyObject **p_traceback) {
|
||||
PyErr_GetExcInfo(p_type, p_value, p_traceback);
|
||||
_CPy_ToNone(p_type);
|
||||
_CPy_ToNone(p_value);
|
||||
_CPy_ToNone(p_traceback);
|
||||
}
|
||||
|
||||
tuple_T3OOO CPy_GetExcInfo(void) {
|
||||
tuple_T3OOO ret;
|
||||
_CPy_GetExcInfo(&ret.f0, &ret.f1, &ret.f2);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CPyError_OutOfMemory(void) {
|
||||
fprintf(stderr, "fatal: out of memory\n");
|
||||
fflush(stderr);
|
||||
abort();
|
||||
}
|
||||
|
||||
// Construct a nicely formatted type name based on __module__ and __name__.
|
||||
static PyObject *CPy_GetTypeName(PyObject *type) {
|
||||
PyObject *module = NULL, *name = NULL;
|
||||
PyObject *full = NULL;
|
||||
|
||||
module = PyObject_GetAttrString(type, "__module__");
|
||||
if (!module || !PyUnicode_Check(module)) {
|
||||
goto out;
|
||||
}
|
||||
name = PyObject_GetAttrString(type, "__qualname__");
|
||||
if (!name || !PyUnicode_Check(name)) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (PyUnicode_CompareWithASCIIString(module, "builtins") == 0) {
|
||||
Py_INCREF(name);
|
||||
full = name;
|
||||
} else {
|
||||
full = PyUnicode_FromFormat("%U.%U", module, name);
|
||||
}
|
||||
|
||||
out:
|
||||
Py_XDECREF(module);
|
||||
Py_XDECREF(name);
|
||||
return full;
|
||||
}
|
||||
|
||||
// Get the type of a value as a string, expanding tuples to include
|
||||
// all the element types.
|
||||
static PyObject *CPy_FormatTypeName(PyObject *value) {
|
||||
if (Py_IsNone(value)) {
|
||||
return PyUnicode_FromString("None");
|
||||
}
|
||||
|
||||
if (!PyTuple_CheckExact(value)) {
|
||||
return CPy_GetTypeName((PyObject *)Py_TYPE(value));
|
||||
}
|
||||
|
||||
if (PyTuple_GET_SIZE(value) > 10) {
|
||||
return PyUnicode_FromFormat("tuple[<%d items>]", PyTuple_GET_SIZE(value));
|
||||
}
|
||||
|
||||
// Most of the logic is all for tuples, which is the only interesting case
|
||||
PyObject *output = PyUnicode_FromString("tuple[");
|
||||
if (!output) {
|
||||
return NULL;
|
||||
}
|
||||
/* This is quadratic but if that ever matters something is really weird. */
|
||||
int i;
|
||||
for (i = 0; i < PyTuple_GET_SIZE(value); i++) {
|
||||
PyObject *s = CPy_FormatTypeName(PyTuple_GET_ITEM(value, i));
|
||||
if (!s) {
|
||||
Py_DECREF(output);
|
||||
return NULL;
|
||||
}
|
||||
PyObject *next = PyUnicode_FromFormat("%U%U%s", output, s,
|
||||
i + 1 == PyTuple_GET_SIZE(value) ? "]" : ", ");
|
||||
Py_DECREF(output);
|
||||
Py_DECREF(s);
|
||||
if (!next) {
|
||||
return NULL;
|
||||
}
|
||||
output = next;
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
CPy_NOINLINE
|
||||
void CPy_TypeError(const char *expected, PyObject *value) {
|
||||
PyObject *out = CPy_FormatTypeName(value);
|
||||
if (out) {
|
||||
PyErr_Format(PyExc_TypeError, "%s object expected; got %U", expected, out);
|
||||
Py_DECREF(out);
|
||||
} else {
|
||||
PyErr_Format(PyExc_TypeError, "%s object expected; and errored formatting real type!",
|
||||
expected);
|
||||
}
|
||||
}
|
||||
|
||||
// This function is basically exactly the same with _PyTraceback_Add
|
||||
// which is available in all the versions we support.
|
||||
// We're continuing to use this because we'll probably optimize this later.
|
||||
void CPy_AddTraceback(const char *filename, const char *funcname, int line, PyObject *globals) {
|
||||
PyObject *exc, *val, *tb;
|
||||
PyThreadState *thread_state = PyThreadState_GET();
|
||||
PyFrameObject *frame_obj;
|
||||
|
||||
// We need to save off the exception state because in 3.8,
|
||||
// PyFrame_New fails if there is an error set and it fails to look
|
||||
// up builtins in the globals. (_PyTraceback_Add documents that it
|
||||
// needs to do it because it decodes the filename according to the
|
||||
// FS encoding, which could have a decoder in Python. We don't do
|
||||
// that so *that* doesn't apply to us.)
|
||||
PyErr_Fetch(&exc, &val, &tb);
|
||||
PyCodeObject *code_obj = PyCode_NewEmpty(filename, funcname, line);
|
||||
if (code_obj == NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
frame_obj = PyFrame_New(thread_state, code_obj, globals, 0);
|
||||
if (frame_obj == NULL) {
|
||||
Py_DECREF(code_obj);
|
||||
goto error;
|
||||
}
|
||||
frame_obj->f_lineno = line;
|
||||
PyErr_Restore(exc, val, tb);
|
||||
PyTraceBack_Here(frame_obj);
|
||||
Py_DECREF(code_obj);
|
||||
Py_DECREF(frame_obj);
|
||||
|
||||
return;
|
||||
|
||||
error:
|
||||
_PyErr_ChainExceptions(exc, val, tb);
|
||||
}
|
||||
59
.venv/lib/python3.8/site-packages/mypyc/lib-rt/generic_ops.c
Normal file
59
.venv/lib/python3.8/site-packages/mypyc/lib-rt/generic_ops.c
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// Generic primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.generic_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
CPyTagged CPyObject_Hash(PyObject *o) {
|
||||
Py_hash_t h = PyObject_Hash(o);
|
||||
if (h == -1) {
|
||||
return CPY_INT_TAG;
|
||||
} else {
|
||||
// This is tragically annoying. The range of hash values in
|
||||
// 64-bit python covers 64-bits, and our short integers only
|
||||
// cover 63. This means that half the time we are boxing the
|
||||
// result for basically no good reason. To add insult to
|
||||
// injury it is probably about to be immediately unboxed by a
|
||||
// tp_hash wrapper.
|
||||
return CPyTagged_FromSsize_t(h);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyObject_GetAttr3(PyObject *v, PyObject *name, PyObject *defl)
|
||||
{
|
||||
PyObject *result = PyObject_GetAttr(v, name);
|
||||
if (!result && PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
Py_INCREF(defl);
|
||||
result = defl;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *CPyIter_Next(PyObject *iter)
|
||||
{
|
||||
return (*Py_TYPE(iter)->tp_iternext)(iter);
|
||||
}
|
||||
|
||||
PyObject *CPyNumber_Power(PyObject *base, PyObject *index)
|
||||
{
|
||||
return PyNumber_Power(base, index, Py_None);
|
||||
}
|
||||
|
||||
PyObject *CPyObject_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end) {
|
||||
PyObject *start_obj = CPyTagged_AsObject(start);
|
||||
PyObject *end_obj = CPyTagged_AsObject(end);
|
||||
if (unlikely(start_obj == NULL || end_obj == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *slice = PySlice_New(start_obj, end_obj, NULL);
|
||||
Py_DECREF(start_obj);
|
||||
Py_DECREF(end_obj);
|
||||
if (unlikely(slice == NULL)) {
|
||||
return NULL;
|
||||
}
|
||||
PyObject *result = PyObject_GetItem(obj, slice);
|
||||
Py_DECREF(slice);
|
||||
return result;
|
||||
}
|
||||
450
.venv/lib/python3.8/site-packages/mypyc/lib-rt/getargs.c
Normal file
450
.venv/lib/python3.8/site-packages/mypyc/lib-rt/getargs.c
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
/* getargs implementation copied from Python 3.8 and stripped down to only include
|
||||
* the functions we need.
|
||||
* We also add support for required kwonly args and accepting *args / **kwargs.
|
||||
* A good idea would be to also vendor in the Fast versions and get our stuff
|
||||
* working with *that*.
|
||||
* Another probably good idea is to strip out all the formatting stuff we don't need
|
||||
* and then add in custom stuff that we do need.
|
||||
*
|
||||
* DOCUMENTATION OF THE EXTENSIONS:
|
||||
* - Arguments given after a @ format specify are required keyword-only arguments.
|
||||
* The | and $ specifiers must both appear before @.
|
||||
* - If the first character of a format string is %, then the function can support
|
||||
* *args and **kwargs. On seeing a %, the parser will consume two arguments,
|
||||
* which should be pointers to variables to store the *args and **kwargs, respectively.
|
||||
* Either pointer can be NULL, in which case the function doesn't take that
|
||||
* variety of vararg.
|
||||
* Unlike most format specifiers, the caller takes ownership of these objects
|
||||
* and is responsible for decrefing them.
|
||||
* - All arguments must use the 'O' format.
|
||||
* - There's minimal error checking of format strings. They are generated
|
||||
* programmatically and can be assumed valid.
|
||||
*/
|
||||
|
||||
// These macro definitions are copied from pyport.h in Python 3.9 and later
|
||||
// https://bugs.python.org/issue19569
|
||||
#if defined(__clang__)
|
||||
#define _Py_COMP_DIAG_PUSH _Pragma("clang diagnostic push")
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \
|
||||
_Pragma("clang diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define _Py_COMP_DIAG_POP _Pragma("clang diagnostic pop")
|
||||
#elif defined(__GNUC__) \
|
||||
&& ((__GNUC__ >= 5) || (__GNUC__ == 4) && (__GNUC_MINOR__ >= 6))
|
||||
#define _Py_COMP_DIAG_PUSH _Pragma("GCC diagnostic push")
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS \
|
||||
_Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"")
|
||||
#define _Py_COMP_DIAG_POP _Pragma("GCC diagnostic pop")
|
||||
#elif defined(_MSC_VER)
|
||||
#define _Py_COMP_DIAG_PUSH __pragma(warning(push))
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS __pragma(warning(disable: 4996))
|
||||
#define _Py_COMP_DIAG_POP __pragma(warning(pop))
|
||||
#else
|
||||
#define _Py_COMP_DIAG_PUSH
|
||||
#define _Py_COMP_DIAG_IGNORE_DEPR_DECLS
|
||||
#define _Py_COMP_DIAG_POP
|
||||
#endif
|
||||
|
||||
#include "Python.h"
|
||||
#include "pythonsupport.h"
|
||||
|
||||
#include <ctype.h>
|
||||
#include <float.h>
|
||||
|
||||
#ifndef PyDict_GET_SIZE
|
||||
#define PyDict_GET_SIZE(d) PyDict_Size(d)
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
int CPyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
|
||||
const char *, const char *, const char * const *, ...);
|
||||
|
||||
/* Forward */
|
||||
static int vgetargskeywords(PyObject *, PyObject *,
|
||||
const char *, const char *, const char * const *, va_list *);
|
||||
static void skipitem(const char **, va_list *);
|
||||
|
||||
/* Support for keyword arguments donated by
|
||||
Geoff Philbrick <philbric@delphi.hks.com> */
|
||||
|
||||
/* Return false (0) for error, else true. */
|
||||
int
|
||||
CPyArg_ParseTupleAndKeywords(PyObject *args,
|
||||
PyObject *keywords,
|
||||
const char *format,
|
||||
const char *fname,
|
||||
const char * const *kwlist, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list va;
|
||||
|
||||
va_start(va, kwlist);
|
||||
retval = vgetargskeywords(args, keywords, format, fname, kwlist, &va);
|
||||
va_end(va);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
|
||||
|
||||
static int
|
||||
vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format,
|
||||
const char *fname, const char * const *kwlist, va_list *p_va)
|
||||
{
|
||||
int min = INT_MAX;
|
||||
int max = INT_MAX;
|
||||
int required_kwonly_start = INT_MAX;
|
||||
int has_required_kws = 0;
|
||||
int i, pos, len;
|
||||
int skip = 0;
|
||||
Py_ssize_t nargs, nkwargs;
|
||||
PyObject *current_arg;
|
||||
int bound_pos_args;
|
||||
|
||||
PyObject **p_args = NULL, **p_kwargs = NULL;
|
||||
|
||||
assert(args != NULL && PyTuple_Check(args));
|
||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||
assert(format != NULL);
|
||||
assert(kwlist != NULL);
|
||||
assert(p_va != NULL);
|
||||
|
||||
/* scan kwlist and count the number of positional-only parameters */
|
||||
for (pos = 0; kwlist[pos] && !*kwlist[pos]; pos++) {
|
||||
}
|
||||
/* scan kwlist and get greatest possible nbr of args */
|
||||
for (len = pos; kwlist[len]; len++) {
|
||||
#ifdef DEBUG
|
||||
if (!*kwlist[len]) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Empty keyword parameter name");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (*format == '%') {
|
||||
p_args = va_arg(*p_va, PyObject **);
|
||||
p_kwargs = va_arg(*p_va, PyObject **);
|
||||
format++;
|
||||
}
|
||||
|
||||
nargs = PyTuple_GET_SIZE(args);
|
||||
nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
|
||||
if (unlikely(nargs + nkwargs > len && !p_args && !p_kwargs)) {
|
||||
/* Adding "keyword" (when nargs == 0) prevents producing wrong error
|
||||
messages in some special cases (see bpo-31229). */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes at most %d %sargument%s (%zd given)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
len,
|
||||
(nargs == 0) ? "keyword " : "",
|
||||
(len == 1) ? "" : "s",
|
||||
nargs + nkwargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* convert tuple args and keyword args in same loop, using kwlist to drive process */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (*format == '|') {
|
||||
#ifdef DEBUG
|
||||
if (min != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string (| specified twice)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
min = i;
|
||||
format++;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (max != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string ($ before |)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* If there are optional args, figure out whether we have
|
||||
* required keyword arguments so that we don't bail without
|
||||
* enforcing them. */
|
||||
has_required_kws = strchr(format, '@') != NULL;
|
||||
}
|
||||
if (*format == '$') {
|
||||
#ifdef DEBUG
|
||||
if (max != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string ($ specified twice)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
max = i;
|
||||
format++;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (max < pos) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Empty parameter name after $");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (skip) {
|
||||
/* Now we know the minimal and the maximal numbers of
|
||||
* positional arguments and can raise an exception with
|
||||
* informative message (see below). */
|
||||
break;
|
||||
}
|
||||
if (unlikely(max < nargs && !p_args)) {
|
||||
if (max == 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes no positional arguments",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()");
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes %s %d positional argument%s"
|
||||
" (%zd given)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
(min < max) ? "at most" : "exactly",
|
||||
max,
|
||||
max == 1 ? "" : "s",
|
||||
nargs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (*format == '@') {
|
||||
#ifdef DEBUG
|
||||
if (min == INT_MAX && max == INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string "
|
||||
"(@ without preceding | and $)");
|
||||
return 0;
|
||||
}
|
||||
if (required_kwonly_start != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string (@ specified twice)");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
required_kwonly_start = i;
|
||||
format++;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
if (IS_END_OF_FORMAT(*format)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"More keyword list entries (%d) than "
|
||||
"format specifiers (%d)", len, i);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (!skip) {
|
||||
if (i < nargs && i < max) {
|
||||
current_arg = PyTuple_GET_ITEM(args, i);
|
||||
}
|
||||
else if (nkwargs && i >= pos) {
|
||||
current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
|
||||
if (current_arg) {
|
||||
--nkwargs;
|
||||
}
|
||||
else if (PyErr_Occurred()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
current_arg = NULL;
|
||||
}
|
||||
|
||||
if (current_arg) {
|
||||
PyObject **p = va_arg(*p_va, PyObject **);
|
||||
*p = current_arg;
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < min || i >= required_kwonly_start) {
|
||||
if (likely(i < pos)) {
|
||||
assert (min == INT_MAX);
|
||||
assert (max == INT_MAX);
|
||||
skip = 1;
|
||||
/* At that moment we still don't know the minimal and
|
||||
* the maximal numbers of positional arguments. Raising
|
||||
* an exception is deferred until we encounter | and $
|
||||
* or the end of the format. */
|
||||
}
|
||||
else {
|
||||
if (i >= max) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s missing required "
|
||||
"keyword-only argument '%s'",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
kwlist[i]);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s missing required "
|
||||
"argument '%s' (pos %d)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
kwlist[i], i+1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/* current code reports success when all required args
|
||||
* fulfilled and no keyword args left, with no further
|
||||
* validation. XXX Maybe skip this in debug build ?
|
||||
*/
|
||||
if (!nkwargs && !skip && !has_required_kws &&
|
||||
!p_args && !p_kwargs)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* We are into optional args, skip through to any remaining
|
||||
* keyword args */
|
||||
skipitem(&format, p_va);
|
||||
}
|
||||
|
||||
if (unlikely(skip)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes %s %d positional argument%s"
|
||||
" (%zd given)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
(Py_MIN(pos, min) < i) ? "at least" : "exactly",
|
||||
Py_MIN(pos, min),
|
||||
Py_MIN(pos, min) == 1 ? "" : "s",
|
||||
nargs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!IS_END_OF_FORMAT(*format) &&
|
||||
(*format != '|') && (*format != '$') && (*format != '@'))
|
||||
{
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"more argument specifiers than keyword list entries "
|
||||
"(remaining format:'%s')", format);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
bound_pos_args = Py_MIN(nargs, Py_MIN(max, len));
|
||||
if (p_args) {
|
||||
*p_args = PyTuple_GetSlice(args, bound_pos_args, nargs);
|
||||
if (!*p_args) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (p_kwargs) {
|
||||
/* This unfortunately needs to be special cased because if len is 0 then we
|
||||
* never go through the main loop. */
|
||||
if (unlikely(nargs > 0 && len == 0 && !p_args)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes no positional arguments",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*p_kwargs = PyDict_New();
|
||||
if (!*p_kwargs) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
|
||||
if (nkwargs > 0) {
|
||||
PyObject *key, *value;
|
||||
Py_ssize_t j;
|
||||
/* make sure there are no arguments given by name and position */
|
||||
for (i = pos; i < bound_pos_args && i < len; i++) {
|
||||
current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
|
||||
if (unlikely(current_arg != NULL)) {
|
||||
/* arg present in tuple and in dict */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"argument for %.200s%s given by name ('%s') "
|
||||
"and position (%d)",
|
||||
(fname == NULL) ? "function" : fname,
|
||||
(fname == NULL) ? "" : "()",
|
||||
kwlist[i], i+1);
|
||||
goto latefail;
|
||||
}
|
||||
else if (unlikely(PyErr_Occurred() != NULL)) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
/* make sure there are no extraneous keyword arguments */
|
||||
j = 0;
|
||||
while (PyDict_Next(kwargs, &j, &key, &value)) {
|
||||
int match = 0;
|
||||
if (unlikely(!PyUnicode_Check(key))) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"keywords must be strings");
|
||||
goto latefail;
|
||||
}
|
||||
for (i = pos; i < len; i++) {
|
||||
if (CPyUnicode_EqualToASCIIString(key, kwlist[i])) {
|
||||
match = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!match) {
|
||||
if (unlikely(!p_kwargs)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%U' is an invalid keyword "
|
||||
"argument for %.200s%s",
|
||||
key,
|
||||
(fname == NULL) ? "this function" : fname,
|
||||
(fname == NULL) ? "" : "()");
|
||||
goto latefail;
|
||||
} else {
|
||||
if (PyDict_SetItem(*p_kwargs, key, value) < 0) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* Handle failures that have happened after we have tried to
|
||||
* create *args and **kwargs, if they exist. */
|
||||
latefail:
|
||||
if (p_args) {
|
||||
Py_XDECREF(*p_args);
|
||||
}
|
||||
if (p_kwargs) {
|
||||
Py_XDECREF(*p_kwargs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
skipitem(const char **p_format, va_list *p_va)
|
||||
{
|
||||
const char *format = *p_format;
|
||||
char c = *format++;
|
||||
|
||||
if (p_va != NULL) {
|
||||
(void) va_arg(*p_va, PyObject **);
|
||||
}
|
||||
|
||||
*p_format = format;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
574
.venv/lib/python3.8/site-packages/mypyc/lib-rt/getargsfast.c
Normal file
574
.venv/lib/python3.8/site-packages/mypyc/lib-rt/getargsfast.c
Normal file
|
|
@ -0,0 +1,574 @@
|
|||
/* getargskeywordsfast implementation copied from Python 3.9 and stripped down to
|
||||
* only include the functionality we need.
|
||||
*
|
||||
* We also add support for required kwonly args and accepting *args / **kwargs.
|
||||
*
|
||||
* DOCUMENTATION OF THE EXTENSIONS:
|
||||
* - Arguments given after a @ format specify required keyword-only arguments.
|
||||
* The | and $ specifiers must both appear before @.
|
||||
* - If the first character of a format string is %, then the function can support
|
||||
* *args and/or **kwargs. In this case the parser will consume two arguments,
|
||||
* which should be pointers to variables to store the *args and **kwargs, respectively.
|
||||
* Either pointer can be NULL, in which case the function doesn't take that
|
||||
* variety of vararg.
|
||||
* Unlike most format specifiers, the caller takes ownership of these objects
|
||||
* and is responsible for decrefing them.
|
||||
*/
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
/* None of this is supported on Python 3.6 or earlier */
|
||||
#if PY_VERSION_HEX >= 0x03070000
|
||||
|
||||
#define PARSER_INITED(parser) ((parser)->kwtuple != NULL)
|
||||
|
||||
/* Forward */
|
||||
static int
|
||||
vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
|
||||
PyObject *kwargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser,
|
||||
va_list *p_va);
|
||||
static void skipitem_fast(const char **, va_list *);
|
||||
|
||||
/* Parse args for an arbitrary signature */
|
||||
int
|
||||
CPyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list va;
|
||||
|
||||
va_start(va, parser);
|
||||
retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va);
|
||||
va_end(va);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Parse args for a function that takes no args */
|
||||
int
|
||||
CPyArg_ParseStackAndKeywordsNoArgs(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list va;
|
||||
|
||||
va_start(va, parser);
|
||||
if (nargs == 0 && kwnames == NULL) {
|
||||
// Fast path: no arguments
|
||||
retval = 1;
|
||||
} else {
|
||||
retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va);
|
||||
}
|
||||
va_end(va);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Parse args for a function that takes one arg */
|
||||
int
|
||||
CPyArg_ParseStackAndKeywordsOneArg(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list va;
|
||||
|
||||
va_start(va, parser);
|
||||
if (kwnames == NULL && nargs == 1) {
|
||||
// Fast path: one positional argument
|
||||
PyObject **p;
|
||||
p = va_arg(va, PyObject **);
|
||||
*p = args[0];
|
||||
retval = 1;
|
||||
} else {
|
||||
retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va);
|
||||
}
|
||||
va_end(va);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/* Parse args for a function that takes no keyword-only args, *args or **kwargs */
|
||||
int
|
||||
CPyArg_ParseStackAndKeywordsSimple(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser, ...)
|
||||
{
|
||||
int retval;
|
||||
va_list va;
|
||||
|
||||
va_start(va, parser);
|
||||
if (kwnames == NULL && PARSER_INITED(parser) &&
|
||||
nargs >= parser->min && nargs <= parser->max) {
|
||||
// Fast path: correct number of positional arguments only
|
||||
PyObject **p;
|
||||
Py_ssize_t i;
|
||||
for (i = 0; i < nargs; i++) {
|
||||
p = va_arg(va, PyObject **);
|
||||
*p = args[i];
|
||||
}
|
||||
retval = 1;
|
||||
} else {
|
||||
retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va);
|
||||
}
|
||||
va_end(va);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
|
||||
|
||||
|
||||
/* List of static parsers. */
|
||||
static struct CPyArg_Parser *static_arg_parsers = NULL;
|
||||
|
||||
static int
|
||||
parser_init(CPyArg_Parser *parser)
|
||||
{
|
||||
const char * const *keywords;
|
||||
const char *format, *msg;
|
||||
int i, len, min, max, nkw;
|
||||
PyObject *kwtuple;
|
||||
|
||||
assert(parser->keywords != NULL);
|
||||
if (PARSER_INITED(parser)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
keywords = parser->keywords;
|
||||
/* scan keywords and count the number of positional-only parameters */
|
||||
for (i = 0; keywords[i] && !*keywords[i]; i++) {
|
||||
}
|
||||
parser->pos = i;
|
||||
/* scan keywords and get greatest possible nbr of args */
|
||||
for (; keywords[i]; i++) {
|
||||
if (!*keywords[i]) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Empty keyword parameter name");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
len = i;
|
||||
|
||||
parser->required_kwonly_start = INT_MAX;
|
||||
if (*parser->format == '%') {
|
||||
parser->format++;
|
||||
parser->varargs = 1;
|
||||
}
|
||||
|
||||
format = parser->format;
|
||||
if (format) {
|
||||
/* grab the function name or custom error msg first (mutually exclusive) */
|
||||
parser->fname = strchr(parser->format, ':');
|
||||
if (parser->fname) {
|
||||
parser->fname++;
|
||||
parser->custom_msg = NULL;
|
||||
}
|
||||
else {
|
||||
parser->custom_msg = strchr(parser->format,';');
|
||||
if (parser->custom_msg)
|
||||
parser->custom_msg++;
|
||||
}
|
||||
|
||||
min = max = INT_MAX;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (*format == '|') {
|
||||
if (min != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string (| specified twice)");
|
||||
return 0;
|
||||
}
|
||||
if (max != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string ($ before |)");
|
||||
return 0;
|
||||
}
|
||||
min = i;
|
||||
format++;
|
||||
}
|
||||
if (*format == '$') {
|
||||
if (max != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string ($ specified twice)");
|
||||
return 0;
|
||||
}
|
||||
if (i < parser->pos) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Empty parameter name after $");
|
||||
return 0;
|
||||
}
|
||||
max = i;
|
||||
format++;
|
||||
}
|
||||
if (*format == '@') {
|
||||
if (parser->required_kwonly_start != INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string (@ specified twice)");
|
||||
return 0;
|
||||
}
|
||||
if (min == INT_MAX && max == INT_MAX) {
|
||||
PyErr_SetString(PyExc_SystemError,
|
||||
"Invalid format string "
|
||||
"(@ without preceding | and $)");
|
||||
return 0;
|
||||
}
|
||||
format++;
|
||||
parser->has_required_kws = 1;
|
||||
parser->required_kwonly_start = i;
|
||||
}
|
||||
if (IS_END_OF_FORMAT(*format)) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"More keyword list entries (%d) than "
|
||||
"format specifiers (%d)", len, i);
|
||||
return 0;
|
||||
}
|
||||
|
||||
skipitem_fast(&format, NULL);
|
||||
}
|
||||
parser->min = Py_MIN(min, len);
|
||||
parser->max = Py_MIN(max, len);
|
||||
|
||||
if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
|
||||
PyErr_Format(PyExc_SystemError,
|
||||
"more argument specifiers than keyword list entries "
|
||||
"(remaining format:'%s')", format);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
nkw = len - parser->pos;
|
||||
kwtuple = PyTuple_New(nkw);
|
||||
if (kwtuple == NULL) {
|
||||
return 0;
|
||||
}
|
||||
keywords = parser->keywords + parser->pos;
|
||||
for (i = 0; i < nkw; i++) {
|
||||
PyObject *str = PyUnicode_FromString(keywords[i]);
|
||||
if (str == NULL) {
|
||||
Py_DECREF(kwtuple);
|
||||
return 0;
|
||||
}
|
||||
PyUnicode_InternInPlace(&str);
|
||||
PyTuple_SET_ITEM(kwtuple, i, str);
|
||||
}
|
||||
parser->kwtuple = kwtuple;
|
||||
|
||||
assert(parser->next == NULL);
|
||||
parser->next = static_arg_parsers;
|
||||
static_arg_parsers = parser;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static PyObject*
|
||||
find_keyword(PyObject *kwnames, PyObject *const *kwstack, PyObject *key)
|
||||
{
|
||||
Py_ssize_t i, nkwargs;
|
||||
|
||||
nkwargs = PyTuple_GET_SIZE(kwnames);
|
||||
for (i = 0; i < nkwargs; i++) {
|
||||
PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
|
||||
|
||||
/* kwname == key will normally find a match in since keyword keys
|
||||
should be interned strings; if not retry below in a new loop. */
|
||||
if (kwname == key) {
|
||||
return kwstack[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < nkwargs; i++) {
|
||||
PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
|
||||
assert(PyUnicode_Check(kwname));
|
||||
if (_PyUnicode_EQ(kwname, key)) {
|
||||
return kwstack[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
|
||||
PyObject *kwargs, PyObject *kwnames,
|
||||
CPyArg_Parser *parser,
|
||||
va_list *p_va)
|
||||
{
|
||||
PyObject *kwtuple;
|
||||
const char *format;
|
||||
PyObject *keyword;
|
||||
int i, pos, len;
|
||||
Py_ssize_t nkwargs;
|
||||
PyObject *current_arg;
|
||||
PyObject *const *kwstack = NULL;
|
||||
int bound_pos_args;
|
||||
PyObject **p_args = NULL, **p_kwargs = NULL;
|
||||
|
||||
assert(kwargs == NULL || PyDict_Check(kwargs));
|
||||
assert(kwargs == NULL || kwnames == NULL);
|
||||
assert(p_va != NULL);
|
||||
|
||||
if (!parser_init(parser)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
kwtuple = parser->kwtuple;
|
||||
pos = parser->pos;
|
||||
len = pos + (int)PyTuple_GET_SIZE(kwtuple);
|
||||
|
||||
if (parser->varargs) {
|
||||
p_args = va_arg(*p_va, PyObject **);
|
||||
p_kwargs = va_arg(*p_va, PyObject **);
|
||||
}
|
||||
|
||||
if (kwargs != NULL) {
|
||||
nkwargs = PyDict_GET_SIZE(kwargs);
|
||||
}
|
||||
else if (kwnames != NULL) {
|
||||
nkwargs = PyTuple_GET_SIZE(kwnames);
|
||||
kwstack = args + nargs;
|
||||
}
|
||||
else {
|
||||
nkwargs = 0;
|
||||
}
|
||||
if (nargs + nkwargs > len && !p_args && !p_kwargs) {
|
||||
/* Adding "keyword" (when nargs == 0) prevents producing wrong error
|
||||
messages in some special cases (see bpo-31229). */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes at most %d %sargument%s (%zd given)",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()",
|
||||
len,
|
||||
(nargs == 0) ? "keyword " : "",
|
||||
(len == 1) ? "" : "s",
|
||||
nargs + nkwargs);
|
||||
return 0;
|
||||
}
|
||||
if (parser->max < nargs && !p_args) {
|
||||
if (parser->max == 0) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes no positional arguments",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()");
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes %s %d positional argument%s (%zd given)",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()",
|
||||
(parser->min < parser->max) ? "at most" : "exactly",
|
||||
parser->max,
|
||||
parser->max == 1 ? "" : "s",
|
||||
nargs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
format = parser->format;
|
||||
|
||||
/* convert tuple args and keyword args in same loop, using kwtuple to drive process */
|
||||
for (i = 0; i < len; i++) {
|
||||
if (*format == '|') {
|
||||
format++;
|
||||
}
|
||||
if (*format == '$') {
|
||||
format++;
|
||||
}
|
||||
if (*format == '@') {
|
||||
format++;
|
||||
}
|
||||
assert(!IS_END_OF_FORMAT(*format));
|
||||
|
||||
if (i < nargs && i < parser->max) {
|
||||
current_arg = args[i];
|
||||
}
|
||||
else if (nkwargs && i >= pos) {
|
||||
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
|
||||
if (kwargs != NULL) {
|
||||
current_arg = PyDict_GetItemWithError(kwargs, keyword);
|
||||
if (!current_arg && PyErr_Occurred()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else {
|
||||
current_arg = find_keyword(kwnames, kwstack, keyword);
|
||||
}
|
||||
if (current_arg) {
|
||||
--nkwargs;
|
||||
}
|
||||
}
|
||||
else {
|
||||
current_arg = NULL;
|
||||
}
|
||||
|
||||
if (current_arg) {
|
||||
PyObject **p = va_arg(*p_va, PyObject **);
|
||||
*p = current_arg;
|
||||
format++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < parser->min || i >= parser->required_kwonly_start) {
|
||||
/* Less arguments than required */
|
||||
if (i < pos) {
|
||||
Py_ssize_t min = Py_MIN(pos, parser->min);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes %s %d positional argument%s"
|
||||
" (%zd given)",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()",
|
||||
min < parser->max ? "at least" : "exactly",
|
||||
min,
|
||||
min == 1 ? "" : "s",
|
||||
nargs);
|
||||
}
|
||||
else {
|
||||
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
|
||||
if (i >= parser->max) {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
|
||||
"keyword-only argument '%U'",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()",
|
||||
keyword);
|
||||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
|
||||
"argument '%U' (pos %d)",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()",
|
||||
keyword, i+1);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/* current code reports success when all required args
|
||||
* fulfilled and no keyword args left, with no further
|
||||
* validation. XXX Maybe skip this in debug build ?
|
||||
*/
|
||||
if (!nkwargs && !parser->has_required_kws && !p_args && !p_kwargs) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* We are into optional args, skip through to any remaining
|
||||
* keyword args */
|
||||
skipitem_fast(&format, p_va);
|
||||
}
|
||||
|
||||
assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$'));
|
||||
|
||||
bound_pos_args = Py_MIN(nargs, Py_MIN(parser->max, len));
|
||||
if (p_args) {
|
||||
*p_args = PyTuple_New(nargs - bound_pos_args);
|
||||
if (!*p_args) {
|
||||
return 0;
|
||||
}
|
||||
for (i = bound_pos_args; i < nargs; i++) {
|
||||
PyObject *arg = args[i];
|
||||
Py_INCREF(arg);
|
||||
PyTuple_SET_ITEM(*p_args, i - bound_pos_args, arg);
|
||||
}
|
||||
}
|
||||
|
||||
if (p_kwargs) {
|
||||
/* This unfortunately needs to be special cased because if len is 0 then we
|
||||
* never go through the main loop. */
|
||||
if (nargs > 0 && len == 0 && !p_args) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.200s%s takes no positional arguments",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*p_kwargs = PyDict_New();
|
||||
if (!*p_kwargs) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
|
||||
if (nkwargs > 0) {
|
||||
Py_ssize_t j;
|
||||
PyObject *value;
|
||||
/* make sure there are no arguments given by name and position */
|
||||
for (i = pos; i < bound_pos_args; i++) {
|
||||
keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
|
||||
if (kwargs != NULL) {
|
||||
current_arg = PyDict_GetItemWithError(kwargs, keyword);
|
||||
if (!current_arg && PyErr_Occurred()) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
else {
|
||||
current_arg = find_keyword(kwnames, kwstack, keyword);
|
||||
}
|
||||
if (current_arg) {
|
||||
/* arg present in tuple and in dict */
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"argument for %.200s%s given by name ('%U') "
|
||||
"and position (%d)",
|
||||
(parser->fname == NULL) ? "function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()",
|
||||
keyword, i+1);
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
/* make sure there are no extraneous keyword arguments */
|
||||
j = 0;
|
||||
while (1) {
|
||||
int match;
|
||||
if (kwargs != NULL) {
|
||||
if (!PyDict_Next(kwargs, &j, &keyword, &value))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (j >= PyTuple_GET_SIZE(kwnames))
|
||||
break;
|
||||
keyword = PyTuple_GET_ITEM(kwnames, j);
|
||||
value = kwstack[j];
|
||||
j++;
|
||||
}
|
||||
|
||||
match = PySequence_Contains(kwtuple, keyword);
|
||||
if (match <= 0) {
|
||||
if (!match) {
|
||||
if (!p_kwargs) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"'%S' is an invalid keyword "
|
||||
"argument for %.200s%s",
|
||||
keyword,
|
||||
(parser->fname == NULL) ? "this function" : parser->fname,
|
||||
(parser->fname == NULL) ? "" : "()");
|
||||
goto latefail;
|
||||
} else {
|
||||
if (PyDict_SetItem(*p_kwargs, keyword, value) < 0) {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
goto latefail;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
/* Handle failures that have happened after we have tried to
|
||||
* create *args and **kwargs, if they exist. */
|
||||
latefail:
|
||||
if (p_args) {
|
||||
Py_XDECREF(*p_args);
|
||||
}
|
||||
if (p_kwargs) {
|
||||
Py_XDECREF(*p_kwargs);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
skipitem_fast(const char **p_format, va_list *p_va)
|
||||
{
|
||||
const char *format = *p_format;
|
||||
char c = *format++;
|
||||
|
||||
if (p_va != NULL) {
|
||||
(void) va_arg(*p_va, PyObject **);
|
||||
}
|
||||
|
||||
*p_format = format;
|
||||
}
|
||||
|
||||
#endif
|
||||
13
.venv/lib/python3.8/site-packages/mypyc/lib-rt/init.c
Normal file
13
.venv/lib/python3.8/site-packages/mypyc/lib-rt/init.c
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
struct ExcDummyStruct _CPy_ExcDummyStruct = { PyObject_HEAD_INIT(NULL) };
|
||||
PyObject *_CPy_ExcDummy = (PyObject *)&_CPy_ExcDummyStruct;
|
||||
|
||||
// Because its dynamic linker is more restricted than linux/OS X,
|
||||
// Windows doesn't allow initializing globals with values from
|
||||
// other dynamic libraries. This means we need to initialize
|
||||
// things at load time.
|
||||
void CPy_Init(void) {
|
||||
_CPy_ExcDummyStruct.ob_base.ob_type = &PyBaseObject_Type;
|
||||
}
|
||||
494
.venv/lib/python3.8/site-packages/mypyc/lib-rt/int_ops.c
Normal file
494
.venv/lib/python3.8/site-packages/mypyc/lib-rt/int_ops.c
Normal file
|
|
@ -0,0 +1,494 @@
|
|||
// Int primitive operations (tagged arbitrary-precision integers)
|
||||
//
|
||||
// These are registered in mypyc.primitives.int_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
#ifndef _WIN32
|
||||
// On 64-bit Linux and macOS, ssize_t and long are both 64 bits, and
|
||||
// PyLong_FromLong is faster than PyLong_FromSsize_t, so use the faster one
|
||||
#define CPyLong_FromSsize_t PyLong_FromLong
|
||||
#else
|
||||
// On 64-bit Windows, ssize_t is 64 bits but long is 32 bits, so we
|
||||
// can't use the above trick
|
||||
#define CPyLong_FromSsize_t PyLong_FromSsize_t
|
||||
#endif
|
||||
|
||||
CPyTagged CPyTagged_FromSsize_t(Py_ssize_t value) {
|
||||
// We use a Python object if the value shifted left by 1 is too
|
||||
// large for Py_ssize_t
|
||||
if (unlikely(CPyTagged_TooBig(value))) {
|
||||
PyObject *object = PyLong_FromSsize_t(value);
|
||||
return ((CPyTagged)object) | CPY_INT_TAG;
|
||||
} else {
|
||||
return value << 1;
|
||||
}
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_FromObject(PyObject *object) {
|
||||
int overflow;
|
||||
// The overflow check knows about CPyTagged's width
|
||||
Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
|
||||
if (unlikely(overflow != 0)) {
|
||||
Py_INCREF(object);
|
||||
return ((CPyTagged)object) | CPY_INT_TAG;
|
||||
} else {
|
||||
return value << 1;
|
||||
}
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_StealFromObject(PyObject *object) {
|
||||
int overflow;
|
||||
// The overflow check knows about CPyTagged's width
|
||||
Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
|
||||
if (unlikely(overflow != 0)) {
|
||||
return ((CPyTagged)object) | CPY_INT_TAG;
|
||||
} else {
|
||||
Py_DECREF(object);
|
||||
return value << 1;
|
||||
}
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_BorrowFromObject(PyObject *object) {
|
||||
int overflow;
|
||||
// The overflow check knows about CPyTagged's width
|
||||
Py_ssize_t value = CPyLong_AsSsize_tAndOverflow(object, &overflow);
|
||||
if (unlikely(overflow != 0)) {
|
||||
return ((CPyTagged)object) | CPY_INT_TAG;
|
||||
} else {
|
||||
return value << 1;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyTagged_AsObject(CPyTagged x) {
|
||||
PyObject *value;
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
value = CPyTagged_LongAsObject(x);
|
||||
Py_INCREF(value);
|
||||
} else {
|
||||
value = CPyLong_FromSsize_t(CPyTagged_ShortAsSsize_t(x));
|
||||
if (value == NULL) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
PyObject *CPyTagged_StealAsObject(CPyTagged x) {
|
||||
PyObject *value;
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
value = CPyTagged_LongAsObject(x);
|
||||
} else {
|
||||
value = CPyLong_FromSsize_t(CPyTagged_ShortAsSsize_t(x));
|
||||
if (value == NULL) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
Py_ssize_t CPyTagged_AsSsize_t(CPyTagged x) {
|
||||
if (likely(CPyTagged_CheckShort(x))) {
|
||||
return CPyTagged_ShortAsSsize_t(x);
|
||||
} else {
|
||||
return PyLong_AsSsize_t(CPyTagged_LongAsObject(x));
|
||||
}
|
||||
}
|
||||
|
||||
CPy_NOINLINE
|
||||
void CPyTagged_IncRef(CPyTagged x) {
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
Py_INCREF(CPyTagged_LongAsObject(x));
|
||||
}
|
||||
}
|
||||
|
||||
CPy_NOINLINE
|
||||
void CPyTagged_DecRef(CPyTagged x) {
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
Py_DECREF(CPyTagged_LongAsObject(x));
|
||||
}
|
||||
}
|
||||
|
||||
CPy_NOINLINE
|
||||
void CPyTagged_XDecRef(CPyTagged x) {
|
||||
if (unlikely(CPyTagged_CheckLong(x))) {
|
||||
Py_XDECREF(CPyTagged_LongAsObject(x));
|
||||
}
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_Negate(CPyTagged num) {
|
||||
if (CPyTagged_CheckShort(num)
|
||||
&& num != (CPyTagged) ((Py_ssize_t)1 << (CPY_INT_BITS - 1))) {
|
||||
// The only possibility of an overflow error happening when negating a short is if we
|
||||
// attempt to negate the most negative number.
|
||||
return -num;
|
||||
}
|
||||
PyObject *num_obj = CPyTagged_AsObject(num);
|
||||
PyObject *result = PyNumber_Negative(num_obj);
|
||||
if (result == NULL) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
Py_DECREF(num_obj);
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_Add(CPyTagged left, CPyTagged right) {
|
||||
// TODO: Use clang/gcc extension __builtin_saddll_overflow instead.
|
||||
if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
|
||||
CPyTagged sum = left + right;
|
||||
if (likely(!CPyTagged_IsAddOverflow(sum, left, right))) {
|
||||
return sum;
|
||||
}
|
||||
}
|
||||
PyObject *left_obj = CPyTagged_AsObject(left);
|
||||
PyObject *right_obj = CPyTagged_AsObject(right);
|
||||
PyObject *result = PyNumber_Add(left_obj, right_obj);
|
||||
if (result == NULL) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
Py_DECREF(left_obj);
|
||||
Py_DECREF(right_obj);
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_Subtract(CPyTagged left, CPyTagged right) {
|
||||
// TODO: Use clang/gcc extension __builtin_saddll_overflow instead.
|
||||
if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
|
||||
CPyTagged diff = left - right;
|
||||
if (likely(!CPyTagged_IsSubtractOverflow(diff, left, right))) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
PyObject *left_obj = CPyTagged_AsObject(left);
|
||||
PyObject *right_obj = CPyTagged_AsObject(right);
|
||||
PyObject *result = PyNumber_Subtract(left_obj, right_obj);
|
||||
if (result == NULL) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
Py_DECREF(left_obj);
|
||||
Py_DECREF(right_obj);
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_Multiply(CPyTagged left, CPyTagged right) {
|
||||
// TODO: Consider using some clang/gcc extension
|
||||
if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) {
|
||||
if (!CPyTagged_IsMultiplyOverflow(left, right)) {
|
||||
return left * CPyTagged_ShortAsSsize_t(right);
|
||||
}
|
||||
}
|
||||
PyObject *left_obj = CPyTagged_AsObject(left);
|
||||
PyObject *right_obj = CPyTagged_AsObject(right);
|
||||
PyObject *result = PyNumber_Multiply(left_obj, right_obj);
|
||||
if (result == NULL) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
Py_DECREF(left_obj);
|
||||
Py_DECREF(right_obj);
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_FloorDivide(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left)
|
||||
&& CPyTagged_CheckShort(right)
|
||||
&& !CPyTagged_MaybeFloorDivideFault(left, right)) {
|
||||
Py_ssize_t result = CPyTagged_ShortAsSsize_t(left) / CPyTagged_ShortAsSsize_t(right);
|
||||
if (((Py_ssize_t)left < 0) != (((Py_ssize_t)right) < 0)) {
|
||||
if (result * right != left) {
|
||||
// Round down
|
||||
result--;
|
||||
}
|
||||
}
|
||||
return result << 1;
|
||||
}
|
||||
PyObject *left_obj = CPyTagged_AsObject(left);
|
||||
PyObject *right_obj = CPyTagged_AsObject(right);
|
||||
PyObject *result = PyNumber_FloorDivide(left_obj, right_obj);
|
||||
Py_DECREF(left_obj);
|
||||
Py_DECREF(right_obj);
|
||||
// Handle exceptions honestly because it could be ZeroDivisionError
|
||||
if (result == NULL) {
|
||||
return CPY_INT_TAG;
|
||||
} else {
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_Remainder(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)
|
||||
&& !CPyTagged_MaybeRemainderFault(left, right)) {
|
||||
Py_ssize_t result = (Py_ssize_t)left % (Py_ssize_t)right;
|
||||
if (((Py_ssize_t)right < 0) != ((Py_ssize_t)left < 0) && result != 0) {
|
||||
result += right;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
PyObject *left_obj = CPyTagged_AsObject(left);
|
||||
PyObject *right_obj = CPyTagged_AsObject(right);
|
||||
PyObject *result = PyNumber_Remainder(left_obj, right_obj);
|
||||
Py_DECREF(left_obj);
|
||||
Py_DECREF(right_obj);
|
||||
// Handle exceptions honestly because it could be ZeroDivisionError
|
||||
if (result == NULL) {
|
||||
return CPY_INT_TAG;
|
||||
} else {
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
}
|
||||
|
||||
bool CPyTagged_IsEq_(CPyTagged left, CPyTagged right) {
|
||||
if (CPyTagged_CheckShort(right)) {
|
||||
return false;
|
||||
} else {
|
||||
int result = PyObject_RichCompareBool(CPyTagged_LongAsObject(left),
|
||||
CPyTagged_LongAsObject(right), Py_EQ);
|
||||
if (result == -1) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
bool CPyTagged_IsLt_(CPyTagged left, CPyTagged right) {
|
||||
PyObject *left_obj = CPyTagged_AsObject(left);
|
||||
PyObject *right_obj = CPyTagged_AsObject(right);
|
||||
int result = PyObject_RichCompareBool(left_obj, right_obj, Py_LT);
|
||||
Py_DECREF(left_obj);
|
||||
Py_DECREF(right_obj);
|
||||
if (result == -1) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *CPyLong_FromStrWithBase(PyObject *o, CPyTagged base) {
|
||||
Py_ssize_t base_size_t = CPyTagged_AsSsize_t(base);
|
||||
return PyLong_FromUnicodeObject(o, base_size_t);
|
||||
}
|
||||
|
||||
PyObject *CPyLong_FromStr(PyObject *o) {
|
||||
CPyTagged base = CPyTagged_FromSsize_t(10);
|
||||
return CPyLong_FromStrWithBase(o, base);
|
||||
}
|
||||
|
||||
PyObject *CPyLong_FromFloat(PyObject *o) {
|
||||
if (PyLong_Check(o)) {
|
||||
CPy_INCREF(o);
|
||||
return o;
|
||||
} else {
|
||||
return PyLong_FromDouble(PyFloat_AS_DOUBLE(o));
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyBool_Str(bool b) {
|
||||
return PyObject_Str(b ? Py_True : Py_False);
|
||||
}
|
||||
|
||||
static void CPyLong_NormalizeUnsigned(PyLongObject *v) {
|
||||
Py_ssize_t i = v->ob_base.ob_size;
|
||||
while (i > 0 && v->ob_digit[i - 1] == 0)
|
||||
i--;
|
||||
v->ob_base.ob_size = i;
|
||||
}
|
||||
|
||||
// Bitwise op '&', '|' or '^' using the generic (slow) API
|
||||
static CPyTagged GenericBitwiseOp(CPyTagged a, CPyTagged b, char op) {
|
||||
PyObject *aobj = CPyTagged_AsObject(a);
|
||||
PyObject *bobj = CPyTagged_AsObject(b);
|
||||
PyObject *r;
|
||||
if (op == '&') {
|
||||
r = PyNumber_And(aobj, bobj);
|
||||
} else if (op == '|') {
|
||||
r = PyNumber_Or(aobj, bobj);
|
||||
} else {
|
||||
r = PyNumber_Xor(aobj, bobj);
|
||||
}
|
||||
if (unlikely(r == NULL)) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
Py_DECREF(aobj);
|
||||
Py_DECREF(bobj);
|
||||
return CPyTagged_StealFromObject(r);
|
||||
}
|
||||
|
||||
// Return pointer to digits of a PyLong object. If it's a short
|
||||
// integer, place digits in the buffer buf instead to avoid memory
|
||||
// allocation (it's assumed to be big enough). Return the number of
|
||||
// digits in *size. *size is negative if the integer is negative.
|
||||
static digit *GetIntDigits(CPyTagged n, Py_ssize_t *size, digit *buf) {
|
||||
if (CPyTagged_CheckShort(n)) {
|
||||
Py_ssize_t val = CPyTagged_ShortAsSsize_t(n);
|
||||
bool neg = val < 0;
|
||||
int len = 1;
|
||||
if (neg) {
|
||||
val = -val;
|
||||
}
|
||||
buf[0] = val & PyLong_MASK;
|
||||
if (val > PyLong_MASK) {
|
||||
val >>= PyLong_SHIFT;
|
||||
buf[1] = val & PyLong_MASK;
|
||||
if (val > PyLong_MASK) {
|
||||
buf[2] = val >> PyLong_SHIFT;
|
||||
len = 3;
|
||||
} else {
|
||||
len = 2;
|
||||
}
|
||||
}
|
||||
*size = neg ? -len : len;
|
||||
return buf;
|
||||
} else {
|
||||
PyLongObject *obj = (PyLongObject *)CPyTagged_LongAsObject(n);
|
||||
*size = obj->ob_base.ob_size;
|
||||
return obj->ob_digit;
|
||||
}
|
||||
}
|
||||
|
||||
// Shared implementation of bitwise '&', '|' and '^' (specified by op) for at least
|
||||
// one long operand. This is somewhat optimized for performance.
|
||||
static CPyTagged BitwiseLongOp(CPyTagged a, CPyTagged b, char op) {
|
||||
// Directly access the digits, as there is no fast C API function for this.
|
||||
digit abuf[3];
|
||||
digit bbuf[3];
|
||||
Py_ssize_t asize;
|
||||
Py_ssize_t bsize;
|
||||
digit *adigits = GetIntDigits(a, &asize, abuf);
|
||||
digit *bdigits = GetIntDigits(b, &bsize, bbuf);
|
||||
|
||||
PyLongObject *r;
|
||||
if (unlikely(asize < 0 || bsize < 0)) {
|
||||
// Negative operand. This is slower, but bitwise ops on them are pretty rare.
|
||||
return GenericBitwiseOp(a, b, op);
|
||||
}
|
||||
// Optimized implementation for two non-negative integers.
|
||||
// Swap a and b as needed to ensure a is no longer than b.
|
||||
if (asize > bsize) {
|
||||
digit *tmp = adigits;
|
||||
adigits = bdigits;
|
||||
bdigits = tmp;
|
||||
Py_ssize_t tmp_size = asize;
|
||||
asize = bsize;
|
||||
bsize = tmp_size;
|
||||
}
|
||||
r = _PyLong_New(op == '&' ? asize : bsize);
|
||||
if (unlikely(r == NULL)) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
Py_ssize_t i;
|
||||
if (op == '&') {
|
||||
for (i = 0; i < asize; i++) {
|
||||
r->ob_digit[i] = adigits[i] & bdigits[i];
|
||||
}
|
||||
} else {
|
||||
if (op == '|') {
|
||||
for (i = 0; i < asize; i++) {
|
||||
r->ob_digit[i] = adigits[i] | bdigits[i];
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < asize; i++) {
|
||||
r->ob_digit[i] = adigits[i] ^ bdigits[i];
|
||||
}
|
||||
}
|
||||
for (; i < bsize; i++) {
|
||||
r->ob_digit[i] = bdigits[i];
|
||||
}
|
||||
}
|
||||
CPyLong_NormalizeUnsigned(r);
|
||||
return CPyTagged_StealFromObject((PyObject *)r);
|
||||
}
|
||||
|
||||
// Bitwise '&'
|
||||
CPyTagged CPyTagged_And(CPyTagged left, CPyTagged right) {
|
||||
if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
|
||||
return left & right;
|
||||
}
|
||||
return BitwiseLongOp(left, right, '&');
|
||||
}
|
||||
|
||||
// Bitwise '|'
|
||||
CPyTagged CPyTagged_Or(CPyTagged left, CPyTagged right) {
|
||||
if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
|
||||
return left | right;
|
||||
}
|
||||
return BitwiseLongOp(left, right, '|');
|
||||
}
|
||||
|
||||
// Bitwise '^'
|
||||
CPyTagged CPyTagged_Xor(CPyTagged left, CPyTagged right) {
|
||||
if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) {
|
||||
return left ^ right;
|
||||
}
|
||||
return BitwiseLongOp(left, right, '^');
|
||||
}
|
||||
|
||||
// Bitwise '~'
|
||||
CPyTagged CPyTagged_Invert(CPyTagged num) {
|
||||
if (likely(CPyTagged_CheckShort(num) && num != CPY_TAGGED_ABS_MIN)) {
|
||||
return ~num & ~CPY_INT_TAG;
|
||||
} else {
|
||||
PyObject *obj = CPyTagged_AsObject(num);
|
||||
PyObject *result = PyNumber_Invert(obj);
|
||||
if (unlikely(result == NULL)) {
|
||||
CPyError_OutOfMemory();
|
||||
}
|
||||
Py_DECREF(obj);
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
}
|
||||
|
||||
// Bitwise '>>'
|
||||
CPyTagged CPyTagged_Rshift(CPyTagged left, CPyTagged right) {
|
||||
if (likely(CPyTagged_CheckShort(left)
|
||||
&& CPyTagged_CheckShort(right)
|
||||
&& (Py_ssize_t)right >= 0)) {
|
||||
CPyTagged count = CPyTagged_ShortAsSsize_t(right);
|
||||
if (unlikely(count >= CPY_INT_BITS)) {
|
||||
if ((Py_ssize_t)left >= 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return CPyTagged_ShortFromInt(-1);
|
||||
}
|
||||
}
|
||||
return ((Py_ssize_t)left >> count) & ~CPY_INT_TAG;
|
||||
} else {
|
||||
// Long integer or negative shift -- use generic op
|
||||
PyObject *lobj = CPyTagged_AsObject(left);
|
||||
PyObject *robj = CPyTagged_AsObject(right);
|
||||
PyObject *result = PyNumber_Rshift(lobj, robj);
|
||||
Py_DECREF(lobj);
|
||||
Py_DECREF(robj);
|
||||
if (result == NULL) {
|
||||
// Propagate error (could be negative shift count)
|
||||
return CPY_INT_TAG;
|
||||
}
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool IsShortLshiftOverflow(Py_ssize_t short_int, Py_ssize_t shift) {
|
||||
return ((Py_ssize_t)(short_int << shift) >> shift) != short_int;
|
||||
}
|
||||
|
||||
// Bitwise '<<'
|
||||
CPyTagged CPyTagged_Lshift(CPyTagged left, CPyTagged right) {
|
||||
if (likely(CPyTagged_CheckShort(left)
|
||||
&& CPyTagged_CheckShort(right)
|
||||
&& (Py_ssize_t)right >= 0
|
||||
&& right < CPY_INT_BITS * 2)) {
|
||||
CPyTagged shift = CPyTagged_ShortAsSsize_t(right);
|
||||
if (!IsShortLshiftOverflow(left, shift))
|
||||
// Short integers, no overflow
|
||||
return left << shift;
|
||||
}
|
||||
// Long integer or out of range shift -- use generic op
|
||||
PyObject *lobj = CPyTagged_AsObject(left);
|
||||
PyObject *robj = CPyTagged_AsObject(right);
|
||||
PyObject *result = PyNumber_Lshift(lobj, robj);
|
||||
Py_DECREF(lobj);
|
||||
Py_DECREF(robj);
|
||||
if (result == NULL) {
|
||||
// Propagate error (could be negative shift count)
|
||||
return CPY_INT_TAG;
|
||||
}
|
||||
return CPyTagged_StealFromObject(result);
|
||||
}
|
||||
228
.venv/lib/python3.8/site-packages/mypyc/lib-rt/list_ops.c
Normal file
228
.venv/lib/python3.8/site-packages/mypyc/lib-rt/list_ops.c
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
// List primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.list_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
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_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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
785
.venv/lib/python3.8/site-packages/mypyc/lib-rt/misc_ops.c
Normal file
785
.venv/lib/python3.8/site-packages/mypyc/lib-rt/misc_ops.c
Normal file
|
|
@ -0,0 +1,785 @@
|
|||
// Misc primitive operations + C helpers
|
||||
//
|
||||
// These are registered in mypyc.primitives.misc_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
PyObject *CPy_GetCoro(PyObject *obj)
|
||||
{
|
||||
// If the type has an __await__ method, call it,
|
||||
// otherwise, fallback to calling __iter__.
|
||||
PyAsyncMethods* async_struct = Py_TYPE(obj)->tp_as_async;
|
||||
if (async_struct != NULL && async_struct->am_await != NULL) {
|
||||
return (async_struct->am_await)(obj);
|
||||
} else {
|
||||
// TODO: We should check that the type is a generator decorated with
|
||||
// asyncio.coroutine
|
||||
return PyObject_GetIter(obj);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPyIter_Send(PyObject *iter, PyObject *val)
|
||||
{
|
||||
// Do a send, or a next if second arg is None.
|
||||
// (This behavior is to match the PEP 380 spec for yield from.)
|
||||
_Py_IDENTIFIER(send);
|
||||
if (Py_IsNone(val)) {
|
||||
return CPyIter_Next(iter);
|
||||
} else {
|
||||
return _PyObject_CallMethodIdOneArg(iter, &PyId_send, val);
|
||||
}
|
||||
}
|
||||
|
||||
// A somewhat hairy implementation of specifically most of the error handling
|
||||
// in `yield from` error handling. The point here is to reduce code size.
|
||||
//
|
||||
// This implements most of the bodies of the `except` blocks in the
|
||||
// pseudocode in PEP 380.
|
||||
//
|
||||
// Returns true (1) if a StopIteration was received and we should return.
|
||||
// Returns false (0) if a value should be yielded.
|
||||
// In both cases the value is stored in outp.
|
||||
// Signals an error (2) if the an exception should be propagated.
|
||||
int CPy_YieldFromErrorHandle(PyObject *iter, PyObject **outp)
|
||||
{
|
||||
_Py_IDENTIFIER(close);
|
||||
_Py_IDENTIFIER(throw);
|
||||
PyObject *exc_type = CPy_ExcState()->exc_type;
|
||||
PyObject *type, *value, *traceback;
|
||||
PyObject *_m;
|
||||
PyObject *res;
|
||||
*outp = NULL;
|
||||
|
||||
if (PyErr_GivenExceptionMatches(exc_type, PyExc_GeneratorExit)) {
|
||||
_m = _PyObject_GetAttrId(iter, &PyId_close);
|
||||
if (_m) {
|
||||
res = PyObject_CallFunctionObjArgs(_m, NULL);
|
||||
Py_DECREF(_m);
|
||||
if (!res)
|
||||
return 2;
|
||||
Py_DECREF(res);
|
||||
} else if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
} else {
|
||||
_m = _PyObject_GetAttrId(iter, &PyId_throw);
|
||||
if (_m) {
|
||||
_CPy_GetExcInfo(&type, &value, &traceback);
|
||||
res = PyObject_CallFunctionObjArgs(_m, type, value, traceback, NULL);
|
||||
Py_DECREF(type);
|
||||
Py_DECREF(value);
|
||||
Py_DECREF(traceback);
|
||||
Py_DECREF(_m);
|
||||
if (res) {
|
||||
*outp = res;
|
||||
return 0;
|
||||
} else {
|
||||
res = CPy_FetchStopIterationValue();
|
||||
if (res) {
|
||||
*outp = res;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
} else if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
CPy_Reraise();
|
||||
return 2;
|
||||
}
|
||||
|
||||
PyObject *CPy_FetchStopIterationValue(void)
|
||||
{
|
||||
PyObject *val = NULL;
|
||||
_PyGen_FetchStopIterationValue(&val);
|
||||
return val;
|
||||
}
|
||||
|
||||
static bool _CPy_IsSafeMetaClass(PyTypeObject *metaclass) {
|
||||
// mypyc classes can't work with metaclasses in
|
||||
// general. Through some various nasty hacks we *do*
|
||||
// manage to work with TypingMeta and its friends.
|
||||
if (metaclass == &PyType_Type)
|
||||
return true;
|
||||
PyObject *module = PyObject_GetAttrString((PyObject *)metaclass, "__module__");
|
||||
if (!module) {
|
||||
PyErr_Clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool matches = false;
|
||||
if (PyUnicode_CompareWithASCIIString(module, "typing") == 0 &&
|
||||
(strcmp(metaclass->tp_name, "TypingMeta") == 0
|
||||
|| strcmp(metaclass->tp_name, "GenericMeta") == 0
|
||||
|| strcmp(metaclass->tp_name, "_ProtocolMeta") == 0)) {
|
||||
matches = true;
|
||||
} else if (PyUnicode_CompareWithASCIIString(module, "typing_extensions") == 0 &&
|
||||
strcmp(metaclass->tp_name, "_ProtocolMeta") == 0) {
|
||||
matches = true;
|
||||
} else if (PyUnicode_CompareWithASCIIString(module, "abc") == 0 &&
|
||||
strcmp(metaclass->tp_name, "ABCMeta") == 0) {
|
||||
matches = true;
|
||||
}
|
||||
Py_DECREF(module);
|
||||
return matches;
|
||||
}
|
||||
|
||||
// Create a heap type based on a template non-heap type.
|
||||
// This is super hacky and maybe we should suck it up and use PyType_FromSpec instead.
|
||||
// We allow bases to be NULL to represent just inheriting from object.
|
||||
// We don't support NULL bases and a non-type metaclass.
|
||||
PyObject *CPyType_FromTemplate(PyObject *template,
|
||||
PyObject *orig_bases,
|
||||
PyObject *modname) {
|
||||
PyTypeObject *template_ = (PyTypeObject *)template;
|
||||
PyHeapTypeObject *t = NULL;
|
||||
PyTypeObject *dummy_class = NULL;
|
||||
PyObject *name = NULL;
|
||||
PyObject *bases = NULL;
|
||||
PyObject *slots;
|
||||
|
||||
// If the type of the class (the metaclass) is NULL, we default it
|
||||
// to being type. (This allows us to avoid needing to initialize
|
||||
// it explicitly on windows.)
|
||||
if (!Py_TYPE(template_)) {
|
||||
Py_SET_TYPE(template_, &PyType_Type);
|
||||
}
|
||||
PyTypeObject *metaclass = Py_TYPE(template_);
|
||||
|
||||
if (orig_bases) {
|
||||
bases = update_bases(orig_bases);
|
||||
// update_bases doesn't increment the refcount if nothing changes,
|
||||
// so we do it to make sure we have distinct "references" to both
|
||||
if (bases == orig_bases)
|
||||
Py_INCREF(bases);
|
||||
|
||||
// Find the appropriate metaclass from our base classes. We
|
||||
// care about this because Generic uses a metaclass prior to
|
||||
// Python 3.7.
|
||||
metaclass = _PyType_CalculateMetaclass(metaclass, bases);
|
||||
if (!metaclass)
|
||||
goto error;
|
||||
|
||||
if (!_CPy_IsSafeMetaClass(metaclass)) {
|
||||
PyErr_SetString(PyExc_TypeError, "mypyc classes can't have a metaclass");
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
name = PyUnicode_FromString(template_->tp_name);
|
||||
if (!name)
|
||||
goto error;
|
||||
|
||||
// If there is a metaclass other than type, we would like to call
|
||||
// its __new__ function. Unfortunately there doesn't seem to be a
|
||||
// good way to mix a C extension class and creating it via a
|
||||
// metaclass. We need to do it anyways, though, in order to
|
||||
// support subclassing Generic[T] prior to Python 3.7.
|
||||
//
|
||||
// We solve this with a kind of atrocious hack: create a parallel
|
||||
// class using the metaclass, determine the bases of the real
|
||||
// class by pulling them out of the parallel class, creating the
|
||||
// real class, and then merging its dict back into the original
|
||||
// class. There are lots of cases where this won't really work,
|
||||
// but for the case of GenericMeta setting a bunch of properties
|
||||
// on the class we should be fine.
|
||||
if (metaclass != &PyType_Type) {
|
||||
assert(bases && "non-type metaclasses require non-NULL bases");
|
||||
|
||||
PyObject *ns = PyDict_New();
|
||||
if (!ns)
|
||||
goto error;
|
||||
|
||||
if (bases != orig_bases) {
|
||||
if (PyDict_SetItemString(ns, "__orig_bases__", orig_bases) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
dummy_class = (PyTypeObject *)PyObject_CallFunctionObjArgs(
|
||||
(PyObject *)metaclass, name, bases, ns, NULL);
|
||||
Py_DECREF(ns);
|
||||
if (!dummy_class)
|
||||
goto error;
|
||||
|
||||
Py_DECREF(bases);
|
||||
bases = dummy_class->tp_bases;
|
||||
Py_INCREF(bases);
|
||||
}
|
||||
|
||||
// Allocate the type and then copy the main stuff in.
|
||||
t = (PyHeapTypeObject*)PyType_GenericAlloc(&PyType_Type, 0);
|
||||
if (!t)
|
||||
goto error;
|
||||
memcpy((char *)t + sizeof(PyVarObject),
|
||||
(char *)template_ + sizeof(PyVarObject),
|
||||
sizeof(PyTypeObject) - sizeof(PyVarObject));
|
||||
|
||||
if (bases != orig_bases) {
|
||||
if (PyObject_SetAttrString((PyObject *)t, "__orig_bases__", orig_bases) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Having tp_base set is I think required for stuff to get
|
||||
// inherited in PyType_Ready, which we needed for subclassing
|
||||
// BaseException. XXX: Taking the first element is wrong I think though.
|
||||
if (bases) {
|
||||
t->ht_type.tp_base = (PyTypeObject *)PyTuple_GET_ITEM(bases, 0);
|
||||
Py_INCREF((PyObject *)t->ht_type.tp_base);
|
||||
}
|
||||
|
||||
t->ht_name = name;
|
||||
Py_INCREF(name);
|
||||
t->ht_qualname = name;
|
||||
t->ht_type.tp_bases = bases;
|
||||
// references stolen so NULL these out
|
||||
bases = name = NULL;
|
||||
|
||||
if (PyType_Ready((PyTypeObject *)t) < 0)
|
||||
goto error;
|
||||
|
||||
assert(t->ht_type.tp_base != NULL);
|
||||
|
||||
// XXX: This is a terrible hack to work around a cpython check on
|
||||
// the mro. It was needed for mypy.stats. I need to investigate
|
||||
// what is actually going on here.
|
||||
Py_INCREF(metaclass);
|
||||
Py_SET_TYPE(t, metaclass);
|
||||
|
||||
if (dummy_class) {
|
||||
if (PyDict_Merge(t->ht_type.tp_dict, dummy_class->tp_dict, 0) != 0)
|
||||
goto error;
|
||||
// This is the *really* tasteless bit. GenericMeta's __new__
|
||||
// in certain versions of typing sets _gorg to point back to
|
||||
// the class. We need to override it to keep it from pointing
|
||||
// to the proxy.
|
||||
if (PyDict_SetItemString(t->ht_type.tp_dict, "_gorg", (PyObject *)t) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
// Reject anything that would give us a nontrivial __slots__,
|
||||
// because the layout will conflict
|
||||
slots = PyObject_GetAttrString((PyObject *)t, "__slots__");
|
||||
if (slots) {
|
||||
// don't fail on an empty __slots__
|
||||
int is_true = PyObject_IsTrue(slots);
|
||||
Py_DECREF(slots);
|
||||
if (is_true > 0)
|
||||
PyErr_SetString(PyExc_TypeError, "mypyc classes can't have __slots__");
|
||||
if (is_true != 0)
|
||||
goto error;
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
if (PyObject_SetAttrString((PyObject *)t, "__module__", modname) < 0)
|
||||
goto error;
|
||||
|
||||
if (init_subclass((PyTypeObject *)t, NULL))
|
||||
goto error;
|
||||
|
||||
Py_XDECREF(dummy_class);
|
||||
|
||||
return (PyObject *)t;
|
||||
|
||||
error:
|
||||
Py_XDECREF(t);
|
||||
Py_XDECREF(bases);
|
||||
Py_XDECREF(dummy_class);
|
||||
Py_XDECREF(name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int _CPy_UpdateObjFromDict(PyObject *obj, PyObject *dict)
|
||||
{
|
||||
Py_ssize_t pos = 0;
|
||||
PyObject *key, *value;
|
||||
while (PyDict_Next(dict, &pos, &key, &value)) {
|
||||
if (PyObject_SetAttr(obj, key, value) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Support for our partial built-in support for dataclasses.
|
||||
*
|
||||
* Take a class we want to make a dataclass, remove any descriptors
|
||||
* for annotated attributes, swap in the actual values of the class
|
||||
* variables invoke dataclass, and then restore all of the
|
||||
* descriptors.
|
||||
*
|
||||
* The purpose of all this is that dataclasses uses the values of
|
||||
* class variables to drive which attributes are required and what the
|
||||
* default values/factories are for optional attributes. This means
|
||||
* that the class dict needs to contain those values instead of getset
|
||||
* descriptors for the attributes when we invoke dataclass.
|
||||
*
|
||||
* We need to remove descriptors for attributes even when there is no
|
||||
* default value for them, or else dataclass will think the descriptor
|
||||
* is the default value. We remove only the attributes, since we don't
|
||||
* want dataclasses to try generating functions when they are already
|
||||
* implemented.
|
||||
*
|
||||
* Args:
|
||||
* dataclass_dec: The decorator to apply
|
||||
* tp: The class we are making a dataclass
|
||||
* dict: The dictionary containing values that dataclasses needs
|
||||
* annotations: The type annotation dictionary
|
||||
*/
|
||||
int
|
||||
CPyDataclass_SleightOfHand(PyObject *dataclass_dec, PyObject *tp,
|
||||
PyObject *dict, PyObject *annotations) {
|
||||
PyTypeObject *ttp = (PyTypeObject *)tp;
|
||||
Py_ssize_t pos;
|
||||
PyObject *res;
|
||||
|
||||
/* Make a copy of the original class __dict__ */
|
||||
PyObject *orig_dict = PyDict_Copy(ttp->tp_dict);
|
||||
if (!orig_dict) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Delete anything that had an annotation */
|
||||
pos = 0;
|
||||
PyObject *key;
|
||||
while (PyDict_Next(annotations, &pos, &key, NULL)) {
|
||||
if (PyObject_DelAttr(tp, key) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
/* Copy in all the attributes that we want dataclass to see */
|
||||
if (_CPy_UpdateObjFromDict(tp, dict) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Run the @dataclass descriptor */
|
||||
res = PyObject_CallFunctionObjArgs(dataclass_dec, tp, NULL);
|
||||
if (!res) {
|
||||
goto fail;
|
||||
}
|
||||
Py_DECREF(res);
|
||||
|
||||
/* Copy back the original contents of the dict */
|
||||
if (_CPy_UpdateObjFromDict(tp, orig_dict) != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Py_DECREF(orig_dict);
|
||||
return 1;
|
||||
|
||||
fail:
|
||||
Py_XDECREF(orig_dict);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Support for pickling; reusable getstate and setstate functions
|
||||
PyObject *
|
||||
CPyPickle_SetState(PyObject *obj, PyObject *state)
|
||||
{
|
||||
if (_CPy_UpdateObjFromDict(obj, state) != 0) {
|
||||
return NULL;
|
||||
}
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
CPyPickle_GetState(PyObject *obj)
|
||||
{
|
||||
PyObject *attrs = NULL, *state = NULL;
|
||||
|
||||
attrs = PyObject_GetAttrString((PyObject *)Py_TYPE(obj), "__mypyc_attrs__");
|
||||
if (!attrs) {
|
||||
goto fail;
|
||||
}
|
||||
if (!PyTuple_Check(attrs)) {
|
||||
PyErr_SetString(PyExc_TypeError, "__mypyc_attrs__ is not a tuple");
|
||||
goto fail;
|
||||
}
|
||||
state = PyDict_New();
|
||||
if (!state) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Collect all the values of attributes in __mypyc_attrs__
|
||||
// Attributes that are missing we just ignore
|
||||
int i;
|
||||
for (i = 0; i < PyTuple_GET_SIZE(attrs); i++) {
|
||||
PyObject *key = PyTuple_GET_ITEM(attrs, i);
|
||||
PyObject *value = PyObject_GetAttr(obj, key);
|
||||
if (!value) {
|
||||
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
PyErr_Clear();
|
||||
continue;
|
||||
}
|
||||
goto fail;
|
||||
}
|
||||
int result = PyDict_SetItem(state, key, value);
|
||||
Py_DECREF(value);
|
||||
if (result != 0) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
Py_DECREF(attrs);
|
||||
|
||||
return state;
|
||||
fail:
|
||||
Py_XDECREF(attrs);
|
||||
Py_XDECREF(state);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CPyTagged CPyTagged_Id(PyObject *o) {
|
||||
return CPyTagged_FromSsize_t((Py_ssize_t)o);
|
||||
}
|
||||
|
||||
#define MAX_INT_CHARS 22
|
||||
#define _PyUnicode_LENGTH(op) \
|
||||
(((PyASCIIObject *)(op))->length)
|
||||
|
||||
// using snprintf or PyUnicode_FromFormat was way slower than
|
||||
// boxing the int and calling PyObject_Str on it, so we implement our own
|
||||
static int fmt_ssize_t(char *out, Py_ssize_t n) {
|
||||
bool neg = n < 0;
|
||||
if (neg) n = -n;
|
||||
|
||||
// buf gets filled backward and then we copy it forward
|
||||
char buf[MAX_INT_CHARS];
|
||||
int i = 0;
|
||||
do {
|
||||
buf[i] = (n % 10) + '0';
|
||||
n /= 10;
|
||||
i++;
|
||||
} while (n);
|
||||
|
||||
|
||||
int len = i;
|
||||
int j = 0;
|
||||
if (neg) {
|
||||
out[j++] = '-';
|
||||
len++;
|
||||
}
|
||||
|
||||
for (; j < len; j++, i--) {
|
||||
out[j] = buf[i-1];
|
||||
}
|
||||
out[j] = '\0';
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static PyObject *CPyTagged_ShortToStr(Py_ssize_t n) {
|
||||
PyObject *obj = PyUnicode_New(MAX_INT_CHARS, 127);
|
||||
if (!obj) return NULL;
|
||||
int len = fmt_ssize_t((char *)PyUnicode_1BYTE_DATA(obj), n);
|
||||
_PyUnicode_LENGTH(obj) = len;
|
||||
return obj;
|
||||
}
|
||||
|
||||
PyObject *CPyTagged_Str(CPyTagged n) {
|
||||
if (CPyTagged_CheckShort(n)) {
|
||||
return CPyTagged_ShortToStr(CPyTagged_ShortAsSsize_t(n));
|
||||
} else {
|
||||
return PyObject_Str(CPyTagged_AsObject(n));
|
||||
}
|
||||
}
|
||||
|
||||
void CPyDebug_Print(const char *msg) {
|
||||
printf("%s\n", msg);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int CPySequence_CheckUnpackCount(PyObject *sequence, Py_ssize_t expected) {
|
||||
Py_ssize_t actual = Py_SIZE(sequence);
|
||||
if (unlikely(actual != expected)) {
|
||||
if (actual < expected) {
|
||||
PyErr_Format(PyExc_ValueError, "not enough values to unpack (expected %zd, got %zd)",
|
||||
expected, actual);
|
||||
} else {
|
||||
PyErr_Format(PyExc_ValueError, "too many values to unpack (expected %zd)", expected);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Parse an integer (size_t) encoded as a variable-length binary sequence.
|
||||
static const char *parse_int(const char *s, size_t *len) {
|
||||
Py_ssize_t n = 0;
|
||||
while ((unsigned char)*s >= 0x80) {
|
||||
n = (n << 7) + (*s & 0x7f);
|
||||
s++;
|
||||
}
|
||||
n = (n << 7) | *s++;
|
||||
*len = n;
|
||||
return s;
|
||||
}
|
||||
|
||||
// Initialize static constant array of literal values
|
||||
int CPyStatics_Initialize(PyObject **statics,
|
||||
const char * const *strings,
|
||||
const char * const *bytestrings,
|
||||
const char * const *ints,
|
||||
const double *floats,
|
||||
const double *complex_numbers,
|
||||
const int *tuples) {
|
||||
PyObject **result = statics;
|
||||
// Start with some hard-coded values
|
||||
*result++ = Py_None;
|
||||
Py_INCREF(Py_None);
|
||||
*result++ = Py_False;
|
||||
Py_INCREF(Py_False);
|
||||
*result++ = Py_True;
|
||||
Py_INCREF(Py_True);
|
||||
if (strings) {
|
||||
for (; **strings != '\0'; strings++) {
|
||||
size_t num;
|
||||
const char *data = *strings;
|
||||
data = parse_int(data, &num);
|
||||
while (num-- > 0) {
|
||||
size_t len;
|
||||
data = parse_int(data, &len);
|
||||
PyObject *obj = PyUnicode_FromStringAndSize(data, len);
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PyUnicode_InternInPlace(&obj);
|
||||
*result++ = obj;
|
||||
data += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (bytestrings) {
|
||||
for (; **bytestrings != '\0'; bytestrings++) {
|
||||
size_t num;
|
||||
const char *data = *bytestrings;
|
||||
data = parse_int(data, &num);
|
||||
while (num-- > 0) {
|
||||
size_t len;
|
||||
data = parse_int(data, &len);
|
||||
PyObject *obj = PyBytes_FromStringAndSize(data, len);
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*result++ = obj;
|
||||
data += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ints) {
|
||||
for (; **ints != '\0'; ints++) {
|
||||
size_t num;
|
||||
const char *data = *ints;
|
||||
data = parse_int(data, &num);
|
||||
while (num-- > 0) {
|
||||
char *end;
|
||||
PyObject *obj = PyLong_FromString(data, &end, 10);
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
data = end;
|
||||
data++;
|
||||
*result++ = obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (floats) {
|
||||
size_t num = (size_t)*floats++;
|
||||
while (num-- > 0) {
|
||||
PyObject *obj = PyFloat_FromDouble(*floats++);
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*result++ = obj;
|
||||
}
|
||||
}
|
||||
if (complex_numbers) {
|
||||
size_t num = (size_t)*complex_numbers++;
|
||||
while (num-- > 0) {
|
||||
double real = *complex_numbers++;
|
||||
double imag = *complex_numbers++;
|
||||
PyObject *obj = PyComplex_FromDoubles(real, imag);
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*result++ = obj;
|
||||
}
|
||||
}
|
||||
if (tuples) {
|
||||
int num = *tuples++;
|
||||
while (num-- > 0) {
|
||||
int num_items = *tuples++;
|
||||
PyObject *obj = PyTuple_New(num_items);
|
||||
if (obj == NULL) {
|
||||
return -1;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < num_items; i++) {
|
||||
PyObject *item = statics[*tuples++];
|
||||
Py_INCREF(item);
|
||||
PyTuple_SET_ITEM(obj, i, item);
|
||||
}
|
||||
*result++ = obj;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call super(type(self), self)
|
||||
PyObject *
|
||||
CPy_Super(PyObject *builtins, PyObject *self) {
|
||||
PyObject *super_type = PyObject_GetAttrString(builtins, "super");
|
||||
if (!super_type)
|
||||
return NULL;
|
||||
PyObject *result = PyObject_CallFunctionObjArgs(
|
||||
super_type, (PyObject*)Py_TYPE(self), self, NULL);
|
||||
Py_DECREF(super_type);
|
||||
return result;
|
||||
}
|
||||
|
||||
// This helper function is a simplification of cpython/ceval.c/import_from()
|
||||
PyObject *CPyImport_ImportFrom(PyObject *module, PyObject *package_name,
|
||||
PyObject *import_name, PyObject *as_name) {
|
||||
// check if the imported module has an attribute by that name
|
||||
PyObject *x = PyObject_GetAttr(module, import_name);
|
||||
if (x == NULL) {
|
||||
// if not, attempt to import a submodule with that name
|
||||
PyObject *fullmodname = PyUnicode_FromFormat("%U.%U", package_name, import_name);
|
||||
if (fullmodname == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// The following code is a simplification of cpython/import.c/PyImport_GetModule()
|
||||
x = PyObject_GetItem(module, fullmodname);
|
||||
Py_DECREF(fullmodname);
|
||||
if (x == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
return x;
|
||||
|
||||
fail:
|
||||
PyErr_Clear();
|
||||
PyObject *package_path = PyModule_GetFilenameObject(module);
|
||||
PyObject *errmsg = PyUnicode_FromFormat("cannot import name %R from %R (%S)",
|
||||
import_name, package_name, package_path);
|
||||
// NULL checks for errmsg and package_name done by PyErr_SetImportError.
|
||||
PyErr_SetImportError(errmsg, package_name, package_path);
|
||||
Py_DECREF(package_path);
|
||||
Py_DECREF(errmsg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// From CPython
|
||||
static PyObject *
|
||||
CPy_BinopTypeError(PyObject *left, PyObject *right, const char *op) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"unsupported operand type(s) for %.100s: "
|
||||
"'%.100s' and '%.100s'",
|
||||
op,
|
||||
Py_TYPE(left)->tp_name,
|
||||
Py_TYPE(right)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *
|
||||
CPy_CallReverseOpMethod(PyObject *left,
|
||||
PyObject *right,
|
||||
const char *op,
|
||||
_Py_Identifier *method) {
|
||||
// Look up reverse method
|
||||
PyObject *m = _PyObject_GetAttrId(right, method);
|
||||
if (m == NULL) {
|
||||
// If reverse method not defined, generate TypeError instead AttributeError
|
||||
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
|
||||
CPy_BinopTypeError(left, right, op);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// Call reverse method
|
||||
PyObject *result = PyObject_CallOneArg(m, left);
|
||||
Py_DECREF(m);
|
||||
return result;
|
||||
}
|
||||
|
||||
PyObject *CPySingledispatch_RegisterFunction(PyObject *singledispatch_func,
|
||||
PyObject *cls,
|
||||
PyObject *func) {
|
||||
PyObject *registry = PyObject_GetAttrString(singledispatch_func, "registry");
|
||||
PyObject *register_func = NULL;
|
||||
PyObject *typing = NULL;
|
||||
PyObject *get_type_hints = NULL;
|
||||
PyObject *type_hints = NULL;
|
||||
|
||||
if (registry == NULL) goto fail;
|
||||
if (func == NULL) {
|
||||
// one argument case
|
||||
if (PyType_Check(cls)) {
|
||||
// passed a class
|
||||
// bind cls to the first argument so that register gets called again with both the
|
||||
// class and the function
|
||||
register_func = PyObject_GetAttrString(singledispatch_func, "register");
|
||||
if (register_func == NULL) goto fail;
|
||||
return PyMethod_New(register_func, cls);
|
||||
}
|
||||
// passed a function
|
||||
PyObject *annotations = PyFunction_GetAnnotations(cls);
|
||||
const char *invalid_first_arg_msg =
|
||||
"Invalid first argument to `register()`: %R. "
|
||||
"Use either `@register(some_class)` or plain `@register` "
|
||||
"on an annotated function.";
|
||||
|
||||
if (annotations == NULL) {
|
||||
PyErr_Format(PyExc_TypeError, invalid_first_arg_msg, cls);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Py_INCREF(annotations);
|
||||
|
||||
func = cls;
|
||||
typing = PyImport_ImportModule("typing");
|
||||
if (typing == NULL) goto fail;
|
||||
get_type_hints = PyObject_GetAttrString(typing, "get_type_hints");
|
||||
|
||||
type_hints = PyObject_CallOneArg(get_type_hints, func);
|
||||
PyObject *argname;
|
||||
Py_ssize_t pos = 0;
|
||||
if (!PyDict_Next(type_hints, &pos, &argname, &cls)) {
|
||||
// the functools implementation raises the same type error if annotations is an empty dict
|
||||
PyErr_Format(PyExc_TypeError, invalid_first_arg_msg, cls);
|
||||
goto fail;
|
||||
}
|
||||
if (!PyType_Check(cls)) {
|
||||
const char *invalid_annotation_msg = "Invalid annotation for %R. %R is not a class.";
|
||||
PyErr_Format(PyExc_TypeError, invalid_annotation_msg, argname, cls);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (PyDict_SetItem(registry, cls, func) == -1) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// clear the cache so we consider the newly added function when dispatching
|
||||
PyObject *dispatch_cache = PyObject_GetAttrString(singledispatch_func, "dispatch_cache");
|
||||
if (dispatch_cache == NULL) goto fail;
|
||||
PyDict_Clear(dispatch_cache);
|
||||
|
||||
Py_INCREF(func);
|
||||
return func;
|
||||
|
||||
fail:
|
||||
Py_XDECREF(registry);
|
||||
Py_XDECREF(register_func);
|
||||
Py_XDECREF(typing);
|
||||
Py_XDECREF(get_type_hints);
|
||||
Py_XDECREF(type_hints);
|
||||
return NULL;
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
#include <Python.h>
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_{modname}(void)
|
||||
{{
|
||||
PyObject *tmp;
|
||||
if (!(tmp = PyImport_ImportModule("{libname}"))) return NULL;
|
||||
Py_DECREF(tmp);
|
||||
void *init_func = PyCapsule_Import("{libname}.init_{full_modname}", 0);
|
||||
if (!init_func) {{
|
||||
return NULL;
|
||||
}}
|
||||
return ((PyObject *(*)(void))init_func)();
|
||||
}}
|
||||
|
||||
// distutils sometimes spuriously tells cl to export CPyInit___init__,
|
||||
// so provide that so it chills out
|
||||
PyMODINIT_FUNC PyInit___init__(void) {{ return PyInit_{modname}(); }}
|
||||
66
.venv/lib/python3.8/site-packages/mypyc/lib-rt/mypyc_util.h
Normal file
66
.venv/lib/python3.8/site-packages/mypyc/lib-rt/mypyc_util.h
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
#ifndef MYPYC_UTIL_H
|
||||
#define MYPYC_UTIL_H
|
||||
|
||||
#include <Python.h>
|
||||
#include <frameobject.h>
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define likely(x) __builtin_expect((x),1)
|
||||
#define unlikely(x) __builtin_expect((x),0)
|
||||
#define CPy_Unreachable() __builtin_unreachable()
|
||||
#else
|
||||
#define likely(x) (x)
|
||||
#define unlikely(x) (x)
|
||||
#define CPy_Unreachable() abort()
|
||||
#endif
|
||||
|
||||
#if defined(__clang__) || defined(__GNUC__)
|
||||
#define CPy_NOINLINE __attribute__((noinline))
|
||||
#elif defined(_MSC_VER)
|
||||
#define CPy_NOINLINE __declspec(noinline)
|
||||
#else
|
||||
#define CPy_NOINLINE
|
||||
#endif
|
||||
|
||||
// INCREF and DECREF that assert the pointer is not NULL.
|
||||
// asserts are disabled in release builds so there shouldn't be a perf hit.
|
||||
// I'm honestly kind of surprised that this isn't done by default.
|
||||
#define CPy_INCREF(p) do { assert(p); Py_INCREF(p); } while (0)
|
||||
#define CPy_DECREF(p) do { assert(p); Py_DECREF(p); } while (0)
|
||||
// Here just for consistency
|
||||
#define CPy_XDECREF(p) Py_XDECREF(p)
|
||||
|
||||
// Tagged integer -- our representation of Python 'int' objects.
|
||||
// Small enough integers are represented as unboxed integers (shifted
|
||||
// left by 1); larger integers (larger than 63 bits on a 64-bit
|
||||
// platform) are stored as a tagged pointer (PyObject *)
|
||||
// representing a Python int object, with the lowest bit set.
|
||||
// Tagged integers are always normalized. A small integer *must not*
|
||||
// have the tag bit set.
|
||||
typedef size_t CPyTagged;
|
||||
|
||||
typedef size_t CPyPtr;
|
||||
|
||||
#define CPY_INT_BITS (CHAR_BIT * sizeof(CPyTagged))
|
||||
|
||||
#define CPY_TAGGED_MAX (((Py_ssize_t)1 << (CPY_INT_BITS - 2)) - 1)
|
||||
#define CPY_TAGGED_MIN (-((Py_ssize_t)1 << (CPY_INT_BITS - 2)))
|
||||
#define CPY_TAGGED_ABS_MIN (0-(size_t)CPY_TAGGED_MIN)
|
||||
|
||||
typedef PyObject CPyModule;
|
||||
|
||||
// Tag bit used for long integers
|
||||
#define CPY_INT_TAG 1
|
||||
|
||||
typedef void (*CPyVTableItem)(void);
|
||||
|
||||
static inline CPyTagged CPyTagged_ShortFromInt(int x) {
|
||||
return x << 1;
|
||||
}
|
||||
|
||||
static inline CPyTagged CPyTagged_ShortFromSsize_t(Py_ssize_t x) {
|
||||
return x << 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,407 @@
|
|||
// Header file providing new C API functions to old Python versions.
|
||||
//
|
||||
// File distributed under the Zero Clause BSD (0BSD) license.
|
||||
// Copyright Contributors to the pythoncapi_compat project.
|
||||
//
|
||||
// Homepage:
|
||||
// https://github.com/pythoncapi/pythoncapi_compat
|
||||
//
|
||||
// Latest version:
|
||||
// https://raw.githubusercontent.com/pythoncapi/pythoncapi_compat/master/pythoncapi_compat.h
|
||||
//
|
||||
// SPDX-License-Identifier: 0BSD
|
||||
|
||||
#ifndef PYTHONCAPI_COMPAT
|
||||
#define PYTHONCAPI_COMPAT
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <Python.h>
|
||||
#include "frameobject.h" // PyFrameObject, PyFrame_GetBack()
|
||||
|
||||
|
||||
// Compatibility with Visual Studio 2013 and older which don't support
|
||||
// the inline keyword in C (only in C++): use __inline instead.
|
||||
#if (defined(_MSC_VER) && _MSC_VER < 1900 \
|
||||
&& !defined(__cplusplus) && !defined(inline))
|
||||
# define PYCAPI_COMPAT_INLINE(TYPE static __inline TYPE
|
||||
#else
|
||||
# define PYCAPI_COMPAT_STATIC_INLINE(TYPE) static inline TYPE
|
||||
#endif
|
||||
|
||||
|
||||
// C++ compatibility
|
||||
#ifdef __cplusplus
|
||||
# define PYCAPI_COMPAT_CAST(TYPE, EXPR) reinterpret_cast<TYPE>(EXPR)
|
||||
# define PYCAPI_COMPAT_NULL nullptr
|
||||
#else
|
||||
# define PYCAPI_COMPAT_CAST(TYPE, EXPR) (TYPE)(EXPR)
|
||||
# define PYCAPI_COMPAT_NULL NULL
|
||||
#endif
|
||||
|
||||
// Cast argument to PyObject* type.
|
||||
#ifndef _PyObject_CAST
|
||||
# define _PyObject_CAST(op) PYCAPI_COMPAT_CAST(PyObject*, op)
|
||||
#endif
|
||||
#ifndef _PyObject_CAST_CONST
|
||||
# define _PyObject_CAST_CONST(op) PYCAPI_COMPAT_CAST(const PyObject*, op)
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-42262 added Py_NewRef() to Python 3.10.0a3
|
||||
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
|
||||
_Py_NewRef(PyObject *obj)
|
||||
{
|
||||
Py_INCREF(obj);
|
||||
return obj;
|
||||
}
|
||||
#define Py_NewRef(obj) _Py_NewRef(_PyObject_CAST(obj))
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-42262 added Py_XNewRef() to Python 3.10.0a3
|
||||
#if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_XNewRef)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
|
||||
_Py_XNewRef(PyObject *obj)
|
||||
{
|
||||
Py_XINCREF(obj);
|
||||
return obj;
|
||||
}
|
||||
#define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj))
|
||||
#endif
|
||||
|
||||
|
||||
// See https://bugs.python.org/issue42522
|
||||
#if !defined(_Py_StealRef)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
|
||||
__Py_StealRef(PyObject *obj)
|
||||
{
|
||||
Py_DECREF(obj);
|
||||
return obj;
|
||||
}
|
||||
#define _Py_StealRef(obj) __Py_StealRef(_PyObject_CAST(obj))
|
||||
#endif
|
||||
|
||||
|
||||
// See https://bugs.python.org/issue42522
|
||||
#if !defined(_Py_XStealRef)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
|
||||
__Py_XStealRef(PyObject *obj)
|
||||
{
|
||||
Py_XDECREF(obj);
|
||||
return obj;
|
||||
}
|
||||
#define _Py_XStealRef(obj) __Py_XStealRef(_PyObject_CAST(obj))
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4
|
||||
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(void)
|
||||
_Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt)
|
||||
{
|
||||
ob->ob_refcnt = refcnt;
|
||||
}
|
||||
#define Py_SET_REFCNT(ob, refcnt) _Py_SET_REFCNT(_PyObject_CAST(ob), refcnt)
|
||||
#endif
|
||||
|
||||
|
||||
// Py_SETREF() and Py_XSETREF() were added to Python 3.5.2.
|
||||
// It is excluded from the limited C API.
|
||||
#if (PY_VERSION_HEX < 0x03050200 && !defined(Py_SETREF)) && !defined(Py_LIMITED_API)
|
||||
#define Py_SETREF(op, op2) \
|
||||
do { \
|
||||
PyObject *_py_tmp = _PyObject_CAST(op); \
|
||||
(op) = (op2); \
|
||||
Py_DECREF(_py_tmp); \
|
||||
} while (0)
|
||||
|
||||
#define Py_XSETREF(op, op2) \
|
||||
do { \
|
||||
PyObject *_py_tmp = _PyObject_CAST(op); \
|
||||
(op) = (op2); \
|
||||
Py_XDECREF(_py_tmp); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-43753 added Py_Is(), Py_IsNone(), Py_IsTrue() and Py_IsFalse()
|
||||
// to Python 3.10.0b1.
|
||||
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_Is)
|
||||
# define Py_Is(x, y) ((x) == (y))
|
||||
#endif
|
||||
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsNone)
|
||||
# define Py_IsNone(x) Py_Is(x, Py_None)
|
||||
#endif
|
||||
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsTrue)
|
||||
# define Py_IsTrue(x) Py_Is(x, Py_True)
|
||||
#endif
|
||||
#if PY_VERSION_HEX < 0x030A00B1 && !defined(Py_IsFalse)
|
||||
# define Py_IsFalse(x) Py_Is(x, Py_False)
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39573 added Py_SET_TYPE() to Python 3.9.0a4
|
||||
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(void)
|
||||
_Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
|
||||
{
|
||||
ob->ob_type = type;
|
||||
}
|
||||
#define Py_SET_TYPE(ob, type) _Py_SET_TYPE(_PyObject_CAST(ob), type)
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39573 added Py_SET_SIZE() to Python 3.9.0a4
|
||||
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_SIZE)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(void)
|
||||
_Py_SET_SIZE(PyVarObject *ob, Py_ssize_t size)
|
||||
{
|
||||
ob->ob_size = size;
|
||||
}
|
||||
#define Py_SET_SIZE(ob, size) _Py_SET_SIZE((PyVarObject*)(ob), size)
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
|
||||
#if PY_VERSION_HEX < 0x030900B1
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyCodeObject*)
|
||||
PyFrame_GetCode(PyFrameObject *frame)
|
||||
{
|
||||
assert(frame != PYCAPI_COMPAT_NULL);
|
||||
assert(frame->f_code != PYCAPI_COMPAT_NULL);
|
||||
return PYCAPI_COMPAT_CAST(PyCodeObject*, Py_NewRef(frame->f_code));
|
||||
}
|
||||
#endif
|
||||
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyCodeObject*)
|
||||
_PyFrame_GetCodeBorrow(PyFrameObject *frame)
|
||||
{
|
||||
return PYCAPI_COMPAT_CAST(PyCodeObject *,
|
||||
_Py_StealRef(PyFrame_GetCode(frame)));
|
||||
}
|
||||
|
||||
|
||||
// bpo-40421 added PyFrame_GetCode() to Python 3.9.0b1
|
||||
#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
|
||||
PyFrame_GetBack(PyFrameObject *frame)
|
||||
{
|
||||
assert(frame != PYCAPI_COMPAT_NULL);
|
||||
return PYCAPI_COMPAT_CAST(PyFrameObject*, Py_XNewRef(frame->f_back));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
|
||||
_PyFrame_GetBackBorrow(PyFrameObject *frame)
|
||||
{
|
||||
return PYCAPI_COMPAT_CAST(PyFrameObject *,
|
||||
_Py_XStealRef(PyFrame_GetBack(frame)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5
|
||||
#if PY_VERSION_HEX < 0x030900A5
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyInterpreterState *)
|
||||
PyThreadState_GetInterpreter(PyThreadState *tstate)
|
||||
{
|
||||
assert(tstate != PYCAPI_COMPAT_NULL);
|
||||
return tstate->interp;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1
|
||||
#if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
|
||||
PyThreadState_GetFrame(PyThreadState *tstate)
|
||||
{
|
||||
assert(tstate != PYCAPI_COMPAT_NULL);
|
||||
return PYCAPI_COMPAT_CAST(PyFrameObject *, Py_XNewRef(tstate->frame));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyFrameObject*)
|
||||
_PyThreadState_GetFrameBorrow(PyThreadState *tstate)
|
||||
{
|
||||
return PYCAPI_COMPAT_CAST(PyFrameObject*,
|
||||
_Py_XStealRef(PyThreadState_GetFrame(tstate)));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5
|
||||
#if PY_VERSION_HEX < 0x030900A5
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyInterpreterState*)
|
||||
PyInterpreterState_Get(void)
|
||||
{
|
||||
PyThreadState *tstate;
|
||||
PyInterpreterState *interp;
|
||||
|
||||
tstate = PyThreadState_GET();
|
||||
if (tstate == PYCAPI_COMPAT_NULL) {
|
||||
Py_FatalError("GIL released (tstate is NULL)");
|
||||
}
|
||||
interp = tstate->interp;
|
||||
if (interp == PYCAPI_COMPAT_NULL) {
|
||||
Py_FatalError("no current interpreter");
|
||||
}
|
||||
return interp;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a6
|
||||
#if 0x030700A1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(uint64_t)
|
||||
PyThreadState_GetID(PyThreadState *tstate)
|
||||
{
|
||||
assert(tstate != PYCAPI_COMPAT_NULL);
|
||||
return tstate->id;
|
||||
}
|
||||
#endif
|
||||
|
||||
// bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2
|
||||
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(void)
|
||||
PyThreadState_EnterTracing(PyThreadState *tstate)
|
||||
{
|
||||
tstate->tracing++;
|
||||
#if PY_VERSION_HEX >= 0x030A00A1
|
||||
tstate->cframe->use_tracing = 0;
|
||||
#else
|
||||
tstate->use_tracing = 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
// bpo-43760 added PyThreadState_LeaveTracing() to Python 3.11.0a2
|
||||
#if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(void)
|
||||
PyThreadState_LeaveTracing(PyThreadState *tstate)
|
||||
{
|
||||
int use_tracing = (tstate->c_tracefunc != PYCAPI_COMPAT_NULL
|
||||
|| tstate->c_profilefunc != PYCAPI_COMPAT_NULL);
|
||||
tstate->tracing--;
|
||||
#if PY_VERSION_HEX >= 0x030A00A1
|
||||
tstate->cframe->use_tracing = use_tracing;
|
||||
#else
|
||||
tstate->use_tracing = use_tracing;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-37194 added PyObject_CallNoArgs() to Python 3.9.0a1
|
||||
#if PY_VERSION_HEX < 0x030900A1
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
|
||||
PyObject_CallNoArgs(PyObject *func)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(func, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39245 made PyObject_CallOneArg() public (previously called
|
||||
// _PyObject_CallOneArg) in Python 3.9.0a4
|
||||
#if PY_VERSION_HEX < 0x030900A4
|
||||
PYCAPI_COMPAT_STATIC_INLINE(PyObject*)
|
||||
PyObject_CallOneArg(PyObject *func, PyObject *arg)
|
||||
{
|
||||
return PyObject_CallFunctionObjArgs(func, arg, NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-1635741 added PyModule_AddObjectRef() to Python 3.10.0a3
|
||||
#if PY_VERSION_HEX < 0x030A00A3
|
||||
PYCAPI_COMPAT_STATIC_INLINE(int)
|
||||
PyModule_AddObjectRef(PyObject *mod, const char *name, PyObject *value)
|
||||
{
|
||||
int res;
|
||||
Py_XINCREF(value);
|
||||
res = PyModule_AddObject(mod, name, value);
|
||||
if (res < 0) {
|
||||
Py_XDECREF(value);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-40024 added PyModule_AddType() to Python 3.9.0a5
|
||||
#if PY_VERSION_HEX < 0x030900A5
|
||||
PYCAPI_COMPAT_STATIC_INLINE(int)
|
||||
PyModule_AddType(PyObject *mod, PyTypeObject *type)
|
||||
{
|
||||
const char *name, *dot;
|
||||
|
||||
if (PyType_Ready(type) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// inline _PyType_Name()
|
||||
name = type->tp_name;
|
||||
assert(name != PYCAPI_COMPAT_NULL);
|
||||
dot = strrchr(name, '.');
|
||||
if (dot != PYCAPI_COMPAT_NULL) {
|
||||
name = dot + 1;
|
||||
}
|
||||
|
||||
return PyModule_AddObjectRef(mod, name, _PyObject_CAST(type));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-40241 added PyObject_GC_IsTracked() to Python 3.9.0a6.
|
||||
// bpo-4688 added _PyObject_GC_IS_TRACKED() to Python 2.7.0a2.
|
||||
#if PY_VERSION_HEX < 0x030900A6 && !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(int)
|
||||
PyObject_GC_IsTracked(PyObject* obj)
|
||||
{
|
||||
return (PyObject_IS_GC(obj) && _PyObject_GC_IS_TRACKED(obj));
|
||||
}
|
||||
#endif
|
||||
|
||||
// bpo-40241 added PyObject_GC_IsFinalized() to Python 3.9.0a6.
|
||||
// bpo-18112 added _PyGCHead_FINALIZED() to Python 3.4.0 final.
|
||||
#if PY_VERSION_HEX < 0x030900A6 && PY_VERSION_HEX >= 0x030400F0 && !defined(PYPY_VERSION)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(int)
|
||||
PyObject_GC_IsFinalized(PyObject *obj)
|
||||
{
|
||||
PyGC_Head *gc = PYCAPI_COMPAT_CAST(PyGC_Head *, obj) - 1;
|
||||
return (PyObject_IS_GC(obj) && _PyGCHead_FINALIZED(gc));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// bpo-39573 added Py_IS_TYPE() to Python 3.9.0a4
|
||||
#if PY_VERSION_HEX < 0x030900A4 && !defined(Py_IS_TYPE)
|
||||
PYCAPI_COMPAT_STATIC_INLINE(int)
|
||||
_Py_IS_TYPE(const PyObject *ob, const PyTypeObject *type) {
|
||||
return ob->ob_type == type;
|
||||
}
|
||||
#define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST_CONST(ob), type)
|
||||
#endif
|
||||
|
||||
|
||||
// Py_UNUSED() was added to Python 3.4.0b2.
|
||||
#if PY_VERSION_HEX < 0x030400B2 && !defined(Py_UNUSED)
|
||||
# if defined(__GNUC__) || defined(__clang__)
|
||||
# define Py_UNUSED(name) _unused_ ## name __attribute__((unused))
|
||||
# else
|
||||
# define Py_UNUSED(name) _unused_ ## name
|
||||
# endif
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // PYTHONCAPI_COMPAT
|
||||
419
.venv/lib/python3.8/site-packages/mypyc/lib-rt/pythonsupport.h
Normal file
419
.venv/lib/python3.8/site-packages/mypyc/lib-rt/pythonsupport.h
Normal file
|
|
@ -0,0 +1,419 @@
|
|||
// Collects code that was copied in from cpython, for a couple of different reasons:
|
||||
// * We wanted to modify it to produce a more efficient version for our uses
|
||||
// * We needed to call it and it was static :(
|
||||
// * We wanted to call it and needed to backport it
|
||||
|
||||
#ifndef CPY_PYTHONSUPPORT_H
|
||||
#define CPY_PYTHONSUPPORT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <Python.h>
|
||||
#include "pythoncapi_compat.h"
|
||||
#include <frameobject.h>
|
||||
#include <assert.h>
|
||||
#include "mypyc_util.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#if 0
|
||||
} // why isn't emacs smart enough to not indent this
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Adapted from bltinmodule.c in Python 3.7.0
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 7
|
||||
_Py_IDENTIFIER(__mro_entries__);
|
||||
static PyObject*
|
||||
update_bases(PyObject *bases)
|
||||
{
|
||||
Py_ssize_t i, j;
|
||||
PyObject *base, *meth, *new_base, *result, *new_bases = NULL;
|
||||
PyObject *stack[1] = {bases};
|
||||
assert(PyTuple_Check(bases));
|
||||
|
||||
Py_ssize_t nargs = PyTuple_GET_SIZE(bases);
|
||||
for (i = 0; i < nargs; i++) {
|
||||
base = PyTuple_GET_ITEM(bases, i);
|
||||
if (PyType_Check(base)) {
|
||||
if (new_bases) {
|
||||
/* If we already have made a replacement, then we append every normal base,
|
||||
otherwise just skip it. */
|
||||
if (PyList_Append(new_bases, base) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (_PyObject_LookupAttrId(base, &PyId___mro_entries__, &meth) < 0) {
|
||||
goto error;
|
||||
}
|
||||
if (!meth) {
|
||||
if (new_bases) {
|
||||
if (PyList_Append(new_bases, base) < 0) {
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
new_base = _PyObject_FastCall(meth, stack, 1);
|
||||
Py_DECREF(meth);
|
||||
if (!new_base) {
|
||||
goto error;
|
||||
}
|
||||
if (!PyTuple_Check(new_base)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__mro_entries__ must return a tuple");
|
||||
Py_DECREF(new_base);
|
||||
goto error;
|
||||
}
|
||||
if (!new_bases) {
|
||||
/* If this is a first successful replacement, create new_bases list and
|
||||
copy previously encountered bases. */
|
||||
if (!(new_bases = PyList_New(i))) {
|
||||
goto error;
|
||||
}
|
||||
for (j = 0; j < i; j++) {
|
||||
base = PyTuple_GET_ITEM(bases, j);
|
||||
PyList_SET_ITEM(new_bases, j, base);
|
||||
Py_INCREF(base);
|
||||
}
|
||||
}
|
||||
j = PyList_GET_SIZE(new_bases);
|
||||
if (PyList_SetSlice(new_bases, j, j, new_base) < 0) {
|
||||
goto error;
|
||||
}
|
||||
Py_DECREF(new_base);
|
||||
}
|
||||
if (!new_bases) {
|
||||
return bases;
|
||||
}
|
||||
result = PyList_AsTuple(new_bases);
|
||||
Py_DECREF(new_bases);
|
||||
return result;
|
||||
|
||||
error:
|
||||
Py_XDECREF(new_bases);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
static PyObject*
|
||||
update_bases(PyObject *bases)
|
||||
{
|
||||
return bases;
|
||||
}
|
||||
#endif
|
||||
|
||||
// From Python 3.7's typeobject.c
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 6
|
||||
_Py_IDENTIFIER(__init_subclass__);
|
||||
static int
|
||||
init_subclass(PyTypeObject *type, PyObject *kwds)
|
||||
{
|
||||
PyObject *super, *func, *result;
|
||||
PyObject *args[2] = {(PyObject *)type, (PyObject *)type};
|
||||
|
||||
super = _PyObject_FastCall((PyObject *)&PySuper_Type, args, 2);
|
||||
if (super == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
func = _PyObject_GetAttrId(super, &PyId___init_subclass__);
|
||||
Py_DECREF(super);
|
||||
if (func == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = _PyObject_FastCallDict(func, NULL, 0, kwds);
|
||||
Py_DECREF(func);
|
||||
if (result == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_DECREF(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
static int
|
||||
init_subclass(PyTypeObject *type, PyObject *kwds)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Adapted from longobject.c in Python 3.7.0
|
||||
|
||||
/* This function adapted from PyLong_AsLongLongAndOverflow, but with
|
||||
* some safety checks removed and specialized to only work for objects
|
||||
* that are already longs.
|
||||
* About half of the win this provides, though, just comes from being
|
||||
* able to inline the function, which in addition to saving function call
|
||||
* overhead allows the out-parameter overflow flag to be collapsed into
|
||||
* control flow.
|
||||
* Additionally, we check against the possible range of CPyTagged, not of
|
||||
* Py_ssize_t. */
|
||||
static inline Py_ssize_t
|
||||
CPyLong_AsSsize_tAndOverflow(PyObject *vv, int *overflow)
|
||||
{
|
||||
/* This version by Tim Peters */
|
||||
PyLongObject *v = (PyLongObject *)vv;
|
||||
size_t x, prev;
|
||||
Py_ssize_t res;
|
||||
Py_ssize_t i;
|
||||
int sign;
|
||||
|
||||
*overflow = 0;
|
||||
|
||||
res = -1;
|
||||
i = Py_SIZE(v);
|
||||
|
||||
if (likely(i == 1)) {
|
||||
res = v->ob_digit[0];
|
||||
} else if (likely(i == 0)) {
|
||||
res = 0;
|
||||
} else if (i == -1) {
|
||||
res = -(sdigit)v->ob_digit[0];
|
||||
} else {
|
||||
sign = 1;
|
||||
x = 0;
|
||||
if (i < 0) {
|
||||
sign = -1;
|
||||
i = -(i);
|
||||
}
|
||||
while (--i >= 0) {
|
||||
prev = x;
|
||||
x = (x << PyLong_SHIFT) + v->ob_digit[i];
|
||||
if ((x >> PyLong_SHIFT) != prev) {
|
||||
*overflow = sign;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
/* Haven't lost any bits, but casting to long requires extra
|
||||
* care (see comment above).
|
||||
*/
|
||||
if (x <= (size_t)CPY_TAGGED_MAX) {
|
||||
res = (Py_ssize_t)x * sign;
|
||||
}
|
||||
else if (sign < 0 && x == CPY_TAGGED_ABS_MIN) {
|
||||
res = CPY_TAGGED_MIN;
|
||||
}
|
||||
else {
|
||||
*overflow = sign;
|
||||
/* res is already set to -1 */
|
||||
}
|
||||
}
|
||||
exit:
|
||||
return res;
|
||||
}
|
||||
|
||||
// Adapted from listobject.c in Python 3.7.0
|
||||
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;
|
||||
|
||||
/* Bypass realloc() when a previous overallocation is large enough
|
||||
to accommodate the newsize. If the newsize falls lower than half
|
||||
the allocated size, then proceed with the realloc() to shrink the list.
|
||||
*/
|
||||
if (allocated >= newsize && newsize >= (allocated >> 1)) {
|
||||
assert(self->ob_item != NULL || newsize == 0);
|
||||
Py_SET_SIZE(self, newsize);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* This over-allocates proportional to the list size, making room
|
||||
* for additional growth. The over-allocation is mild, but is
|
||||
* enough to give linear-time amortized behavior over a long
|
||||
* sequence of appends() in the presence of a poorly-performing
|
||||
* system realloc().
|
||||
* The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
|
||||
* Note: new_allocated won't overflow because the largest possible value
|
||||
* is PY_SSIZE_T_MAX * (9 / 8) + 6 which always fits in a size_t.
|
||||
*/
|
||||
new_allocated = (size_t)newsize + (newsize >> 3) + (newsize < 9 ? 3 : 6);
|
||||
if (new_allocated > (size_t)PY_SSIZE_T_MAX / sizeof(PyObject *)) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (newsize == 0)
|
||||
new_allocated = 0;
|
||||
num_allocated_bytes = new_allocated * sizeof(PyObject *);
|
||||
items = (PyObject **)PyMem_Realloc(self->ob_item, num_allocated_bytes);
|
||||
if (items == NULL) {
|
||||
PyErr_NoMemory();
|
||||
return -1;
|
||||
}
|
||||
self->ob_item = items;
|
||||
Py_SET_SIZE(self, newsize);
|
||||
self->allocated = new_allocated;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Changed to use PyList_SetSlice instead of the internal list_ass_slice
|
||||
static PyObject *
|
||||
list_pop_impl(PyListObject *self, Py_ssize_t index)
|
||||
{
|
||||
PyObject *v;
|
||||
int status;
|
||||
|
||||
if (Py_SIZE(self) == 0) {
|
||||
/* Special-case most common failure cause */
|
||||
PyErr_SetString(PyExc_IndexError, "pop from empty list");
|
||||
return NULL;
|
||||
}
|
||||
if (index < 0)
|
||||
index += Py_SIZE(self);
|
||||
if (index < 0 || index >= Py_SIZE(self)) {
|
||||
PyErr_SetString(PyExc_IndexError, "pop index out of range");
|
||||
return NULL;
|
||||
}
|
||||
v = self->ob_item[index];
|
||||
if (index == Py_SIZE(self) - 1) {
|
||||
status = list_resize(self, Py_SIZE(self) - 1);
|
||||
if (status >= 0)
|
||||
return v; /* and v now owns the reference the list had */
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
Py_INCREF(v);
|
||||
status = PyList_SetSlice((PyObject *)self, index, index+1, (PyObject *)NULL);
|
||||
if (status < 0) {
|
||||
Py_DECREF(v);
|
||||
return NULL;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
// Tweaked to directly use CPyTagged
|
||||
static CPyTagged
|
||||
list_count(PyListObject *self, PyObject *value)
|
||||
{
|
||||
Py_ssize_t count = 0;
|
||||
Py_ssize_t i;
|
||||
|
||||
for (i = 0; i < Py_SIZE(self); i++) {
|
||||
int cmp = PyObject_RichCompareBool(self->ob_item[i], value, Py_EQ);
|
||||
if (cmp > 0)
|
||||
count++;
|
||||
else if (cmp < 0)
|
||||
return CPY_INT_TAG;
|
||||
}
|
||||
return CPyTagged_ShortFromSsize_t(count);
|
||||
}
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 8
|
||||
static PyObject *
|
||||
_PyDict_GetItemStringWithError(PyObject *v, const char *key)
|
||||
{
|
||||
PyObject *kv, *rv;
|
||||
kv = PyUnicode_FromString(key);
|
||||
if (kv == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
rv = PyDict_GetItemWithError(v, kv);
|
||||
Py_DECREF(kv);
|
||||
return rv;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 6
|
||||
/* _PyUnicode_EqualToASCIIString got added in 3.5.3 (argh!) so we can't actually know
|
||||
* whether it will be present at runtime, so we just assume we don't have it in 3.5. */
|
||||
#define CPyUnicode_EqualToASCIIString(x, y) (PyUnicode_CompareWithASCIIString((x), (y)) == 0)
|
||||
#elif PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >= 6
|
||||
#define CPyUnicode_EqualToASCIIString(x, y) _PyUnicode_EqualToASCIIString(x, y)
|
||||
#endif
|
||||
|
||||
// Adapted from genobject.c in Python 3.7.2
|
||||
// Copied because it wasn't in 3.5.2 and it is undocumented anyways.
|
||||
/*
|
||||
* Set StopIteration with specified value. Value can be arbitrary object
|
||||
* or NULL.
|
||||
*
|
||||
* Returns 0 if StopIteration is set and -1 if any other exception is set.
|
||||
*/
|
||||
static int
|
||||
CPyGen_SetStopIterationValue(PyObject *value)
|
||||
{
|
||||
PyObject *e;
|
||||
|
||||
if (value == NULL ||
|
||||
(!PyTuple_Check(value) && !PyExceptionInstance_Check(value)))
|
||||
{
|
||||
/* Delay exception instantiation if we can */
|
||||
PyErr_SetObject(PyExc_StopIteration, value);
|
||||
return 0;
|
||||
}
|
||||
/* Construct an exception instance manually with
|
||||
* PyObject_CallFunctionObjArgs and pass it to PyErr_SetObject.
|
||||
*
|
||||
* We do this to handle a situation when "value" is a tuple, in which
|
||||
* case PyErr_SetObject would set the value of StopIteration to
|
||||
* the first element of the tuple.
|
||||
*
|
||||
* (See PyErr_SetObject/_PyErr_CreateException code for details.)
|
||||
*/
|
||||
e = PyObject_CallFunctionObjArgs(PyExc_StopIteration, value, NULL);
|
||||
if (e == NULL) {
|
||||
return -1;
|
||||
}
|
||||
PyErr_SetObject(PyExc_StopIteration, e);
|
||||
Py_DECREF(e);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Copied from dictobject.c and dictobject.h, these are not Public before
|
||||
// Python 3.8. Also remove some error checks that we do in the callers.
|
||||
typedef struct {
|
||||
PyObject_HEAD
|
||||
PyDictObject *dv_dict;
|
||||
} _CPyDictViewObject;
|
||||
|
||||
static PyObject *
|
||||
_CPyDictView_New(PyObject *dict, PyTypeObject *type)
|
||||
{
|
||||
_CPyDictViewObject *dv = PyObject_GC_New(_CPyDictViewObject, type);
|
||||
if (dv == NULL)
|
||||
return NULL;
|
||||
Py_INCREF(dict);
|
||||
dv->dv_dict = (PyDictObject *)dict;
|
||||
PyObject_GC_Track(dv);
|
||||
return (PyObject *)dv;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION >=10
|
||||
static int
|
||||
_CPyObject_HasAttrId(PyObject *v, _Py_Identifier *name) {
|
||||
PyObject *tmp = NULL;
|
||||
int result = _PyObject_LookupAttrId(v, name, &tmp);
|
||||
if (tmp) {
|
||||
Py_DECREF(tmp);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
#define _CPyObject_HasAttrId _PyObject_HasAttrId
|
||||
#endif
|
||||
|
||||
#if PY_MAJOR_VERSION >= 3 && PY_MINOR_VERSION < 9
|
||||
// OneArgs and NoArgs functions got added in 3.9
|
||||
#define _PyObject_CallMethodIdNoArgs(self, name) \
|
||||
_PyObject_CallMethodIdObjArgs((self), (name), NULL)
|
||||
#define _PyObject_CallMethodIdOneArg(self, name, arg) \
|
||||
_PyObject_CallMethodIdObjArgs((self), (name), (arg), NULL)
|
||||
#define PyObject_CallNoArgs(callable) \
|
||||
PyObject_CallFunctionObjArgs((callable), NULL)
|
||||
#define PyObject_CallOneArg(callable, arg) \
|
||||
PyObject_CallFunctionObjArgs((callable), (arg), NULL)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
17
.venv/lib/python3.8/site-packages/mypyc/lib-rt/set_ops.c
Normal file
17
.venv/lib/python3.8/site-packages/mypyc/lib-rt/set_ops.c
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
// Set primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.set_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
bool CPySet_Remove(PyObject *set, PyObject *key) {
|
||||
int success = PySet_Discard(set, key);
|
||||
if (success == 1) {
|
||||
return true;
|
||||
}
|
||||
if (success == 0) {
|
||||
_PyErr_SetKeyError(key);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
27
.venv/lib/python3.8/site-packages/mypyc/lib-rt/setup.py
Normal file
27
.venv/lib/python3.8/site-packages/mypyc/lib-rt/setup.py
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
"""Build script for mypyc C runtime library unit tests.
|
||||
|
||||
The tests are written in C++ and use the Google Test framework.
|
||||
"""
|
||||
|
||||
from distutils.core import setup, Extension
|
||||
import sys
|
||||
|
||||
if sys.platform == 'darwin':
|
||||
kwargs = {'language': 'c++'}
|
||||
compile_args = []
|
||||
else:
|
||||
kwargs = {} # type: ignore
|
||||
compile_args = ['--std=c++11']
|
||||
|
||||
setup(name='test_capi',
|
||||
version='0.1',
|
||||
ext_modules=[Extension(
|
||||
'test_capi',
|
||||
['test_capi.cc', 'init.c', 'int_ops.c', 'list_ops.c', 'exc_ops.c', 'generic_ops.c'],
|
||||
depends=['CPy.h', 'mypyc_util.h', 'pythonsupport.h'],
|
||||
extra_compile_args=['-Wno-unused-function', '-Wno-sign-compare'] + compile_args,
|
||||
library_dirs=['../external/googletest/make'],
|
||||
libraries=['gtest'],
|
||||
include_dirs=['../external/googletest', '../external/googletest/include'],
|
||||
**kwargs
|
||||
)])
|
||||
241
.venv/lib/python3.8/site-packages/mypyc/lib-rt/str_ops.c
Normal file
241
.venv/lib/python3.8/site-packages/mypyc/lib-rt/str_ops.c
Normal file
|
|
@ -0,0 +1,241 @@
|
|||
// String primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.str_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
PyObject *CPyStr_GetItem(PyObject *str, CPyTagged index) {
|
||||
if (PyUnicode_READY(str) != -1) {
|
||||
if (CPyTagged_CheckShort(index)) {
|
||||
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
||||
Py_ssize_t size = PyUnicode_GET_LENGTH(str);
|
||||
if (n < 0)
|
||||
n += size;
|
||||
if (n < 0 || n >= size) {
|
||||
PyErr_SetString(PyExc_IndexError, "string index out of range");
|
||||
return NULL;
|
||||
}
|
||||
enum PyUnicode_Kind kind = (enum PyUnicode_Kind)PyUnicode_KIND(str);
|
||||
void *data = PyUnicode_DATA(str);
|
||||
Py_UCS4 ch = PyUnicode_READ(kind, data, n);
|
||||
PyObject *unicode = PyUnicode_New(1, ch);
|
||||
if (unicode == NULL)
|
||||
return NULL;
|
||||
|
||||
if (PyUnicode_KIND(unicode) == PyUnicode_1BYTE_KIND) {
|
||||
PyUnicode_1BYTE_DATA(unicode)[0] = (Py_UCS1)ch;
|
||||
} else if (PyUnicode_KIND(unicode) == PyUnicode_2BYTE_KIND) {
|
||||
PyUnicode_2BYTE_DATA(unicode)[0] = (Py_UCS2)ch;
|
||||
} else {
|
||||
assert(PyUnicode_KIND(unicode) == PyUnicode_4BYTE_KIND);
|
||||
PyUnicode_4BYTE_DATA(unicode)[0] = ch;
|
||||
}
|
||||
return unicode;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
PyObject *index_obj = CPyTagged_AsObject(index);
|
||||
return PyObject_GetItem(str, index_obj);
|
||||
}
|
||||
}
|
||||
|
||||
// A simplification of _PyUnicode_JoinArray() from CPython 3.9.6
|
||||
PyObject *CPyStr_Build(Py_ssize_t len, ...) {
|
||||
Py_ssize_t i;
|
||||
va_list args;
|
||||
|
||||
// Calculate the total amount of space and check
|
||||
// whether all components have the same kind.
|
||||
Py_ssize_t sz = 0;
|
||||
Py_UCS4 maxchar = 0;
|
||||
int use_memcpy = 1; // Use memcpy by default
|
||||
PyObject *last_obj = NULL;
|
||||
|
||||
va_start(args, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
PyObject *item = va_arg(args, PyObject *);
|
||||
if (!PyUnicode_Check(item)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"sequence item %zd: expected str instance,"
|
||||
" %.80s found",
|
||||
i, Py_TYPE(item)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
if (PyUnicode_READY(item) == -1)
|
||||
return NULL;
|
||||
|
||||
size_t add_sz = PyUnicode_GET_LENGTH(item);
|
||||
Py_UCS4 item_maxchar = PyUnicode_MAX_CHAR_VALUE(item);
|
||||
maxchar = Py_MAX(maxchar, item_maxchar);
|
||||
|
||||
// Using size_t to avoid overflow during arithmetic calculation
|
||||
if (add_sz > (size_t)(PY_SSIZE_T_MAX - sz)) {
|
||||
PyErr_SetString(PyExc_OverflowError,
|
||||
"join() result is too long for a Python string");
|
||||
return NULL;
|
||||
}
|
||||
sz += add_sz;
|
||||
|
||||
// If these strings have different kind, we would call
|
||||
// _PyUnicode_FastCopyCharacters() in the following part.
|
||||
if (use_memcpy && last_obj != NULL) {
|
||||
if (PyUnicode_KIND(last_obj) != PyUnicode_KIND(item))
|
||||
use_memcpy = 0;
|
||||
}
|
||||
last_obj = item;
|
||||
}
|
||||
va_end(args);
|
||||
|
||||
// Construct the string
|
||||
PyObject *res = PyUnicode_New(sz, maxchar);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
|
||||
if (use_memcpy) {
|
||||
unsigned char *res_data = PyUnicode_1BYTE_DATA(res);
|
||||
unsigned int kind = PyUnicode_KIND(res);
|
||||
|
||||
va_start(args, len);
|
||||
for (i = 0; i < len; ++i) {
|
||||
PyObject *item = va_arg(args, PyObject *);
|
||||
Py_ssize_t itemlen = PyUnicode_GET_LENGTH(item);
|
||||
if (itemlen != 0) {
|
||||
memcpy(res_data, PyUnicode_DATA(item), kind * itemlen);
|
||||
res_data += kind * itemlen;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
assert(res_data == PyUnicode_1BYTE_DATA(res) + kind * PyUnicode_GET_LENGTH(res));
|
||||
} else {
|
||||
Py_ssize_t res_offset = 0;
|
||||
|
||||
va_start(args, len);
|
||||
for (i = 0; i < len; ++i) {
|
||||
PyObject *item = va_arg(args, PyObject *);
|
||||
Py_ssize_t itemlen = PyUnicode_GET_LENGTH(item);
|
||||
if (itemlen != 0) {
|
||||
_PyUnicode_FastCopyCharacters(res, res_offset, item, 0, itemlen);
|
||||
res_offset += itemlen;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
assert(res_offset == PyUnicode_GET_LENGTH(res));
|
||||
}
|
||||
|
||||
assert(_PyUnicode_CheckConsistency(res, 1));
|
||||
return res;
|
||||
}
|
||||
|
||||
PyObject *CPyStr_Split(PyObject *str, PyObject *sep, CPyTagged max_split) {
|
||||
Py_ssize_t temp_max_split = CPyTagged_AsSsize_t(max_split);
|
||||
if (temp_max_split == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
||||
return NULL;
|
||||
}
|
||||
return PyUnicode_Split(str, sep, temp_max_split);
|
||||
}
|
||||
|
||||
PyObject *CPyStr_Replace(PyObject *str, PyObject *old_substr,
|
||||
PyObject *new_substr, CPyTagged max_replace) {
|
||||
Py_ssize_t temp_max_replace = CPyTagged_AsSsize_t(max_replace);
|
||||
if (temp_max_replace == -1 && PyErr_Occurred()) {
|
||||
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
||||
return NULL;
|
||||
}
|
||||
return PyUnicode_Replace(str, old_substr, new_substr, temp_max_replace);
|
||||
}
|
||||
|
||||
bool CPyStr_Startswith(PyObject *self, PyObject *subobj) {
|
||||
Py_ssize_t start = 0;
|
||||
Py_ssize_t end = PyUnicode_GET_LENGTH(self);
|
||||
return PyUnicode_Tailmatch(self, subobj, start, end, -1);
|
||||
}
|
||||
|
||||
bool CPyStr_Endswith(PyObject *self, PyObject *subobj) {
|
||||
Py_ssize_t start = 0;
|
||||
Py_ssize_t end = PyUnicode_GET_LENGTH(self);
|
||||
return PyUnicode_Tailmatch(self, subobj, start, end, 1);
|
||||
}
|
||||
|
||||
/* This does a dodgy attempt to append in place */
|
||||
PyObject *CPyStr_Append(PyObject *o1, PyObject *o2) {
|
||||
PyUnicode_Append(&o1, o2);
|
||||
return o1;
|
||||
}
|
||||
|
||||
PyObject *CPyStr_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end) {
|
||||
if (likely(PyUnicode_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 += PyUnicode_GET_LENGTH(obj);
|
||||
if (startn < 0) {
|
||||
startn = 0;
|
||||
}
|
||||
}
|
||||
if (endn < 0) {
|
||||
endn += PyUnicode_GET_LENGTH(obj);
|
||||
if (endn < 0) {
|
||||
endn = 0;
|
||||
}
|
||||
}
|
||||
return PyUnicode_Substring(obj, startn, endn);
|
||||
}
|
||||
return CPyObject_GetSlice(obj, start, end);
|
||||
}
|
||||
|
||||
/* Check if the given string is true (i.e. it's length isn't zero) */
|
||||
bool CPyStr_IsTrue(PyObject *obj) {
|
||||
Py_ssize_t length = PyUnicode_GET_LENGTH(obj);
|
||||
return length != 0;
|
||||
}
|
||||
|
||||
Py_ssize_t CPyStr_Size_size_t(PyObject *str) {
|
||||
if (PyUnicode_READY(str) != -1) {
|
||||
return PyUnicode_GET_LENGTH(str);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
PyObject *CPy_Decode(PyObject *obj, PyObject *encoding, PyObject *errors) {
|
||||
const char *enc = NULL;
|
||||
const char *err = NULL;
|
||||
if (encoding) {
|
||||
enc = PyUnicode_AsUTF8AndSize(encoding, NULL);
|
||||
if (!enc) return NULL;
|
||||
}
|
||||
if (errors) {
|
||||
err = PyUnicode_AsUTF8AndSize(errors, NULL);
|
||||
if (!err) return NULL;
|
||||
}
|
||||
if (PyBytes_Check(obj)) {
|
||||
return PyUnicode_Decode(((PyBytesObject *)obj)->ob_sval,
|
||||
((PyVarObject *)obj)->ob_size,
|
||||
enc, err);
|
||||
} else {
|
||||
return PyUnicode_FromEncodedObject(obj, enc, err);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPy_Encode(PyObject *obj, PyObject *encoding, PyObject *errors) {
|
||||
const char *enc = NULL;
|
||||
const char *err = NULL;
|
||||
if (encoding) {
|
||||
enc = PyUnicode_AsUTF8AndSize(encoding, NULL);
|
||||
if (!enc) return NULL;
|
||||
}
|
||||
if (errors) {
|
||||
err = PyUnicode_AsUTF8AndSize(errors, NULL);
|
||||
if (!err) return NULL;
|
||||
}
|
||||
if (PyUnicode_Check(obj)) {
|
||||
return PyUnicode_AsEncodedString(obj, enc, err);
|
||||
} else {
|
||||
PyErr_BadArgument();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
585
.venv/lib/python3.8/site-packages/mypyc/lib-rt/test_capi.cc
Normal file
585
.venv/lib/python3.8/site-packages/mypyc/lib-rt/test_capi.cc
Normal file
|
|
@ -0,0 +1,585 @@
|
|||
// Test cases
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
static PyObject *moduleDict;
|
||||
|
||||
static PyObject *int_from_str(const char *str) {
|
||||
return PyLong_FromString(str, 0, 10);
|
||||
}
|
||||
|
||||
static std::string str_from_object(PyObject *x) {
|
||||
PyObject *str = PyObject_Str(x);
|
||||
const char *utf8 = PyUnicode_AsUTF8(str);
|
||||
return std::string(utf8);
|
||||
}
|
||||
|
||||
static std::string str_from_int(CPyTagged x) {
|
||||
return str_from_object(CPyTagged_AsObject(x));
|
||||
}
|
||||
|
||||
static bool is_py_equal(PyObject *x, PyObject *y) {
|
||||
int result = PyObject_RichCompareBool(x, y, Py_EQ);
|
||||
if (result < 0) {
|
||||
std::cout << "ERROR: Rich compare failed";
|
||||
}
|
||||
return result == 1;
|
||||
}
|
||||
|
||||
static bool is_int_equal(CPyTagged x, CPyTagged y) {
|
||||
if (CPyTagged_CheckShort(x)) {
|
||||
return x == y;
|
||||
} else if (CPyTagged_CheckShort(y)) {
|
||||
return false;
|
||||
} else {
|
||||
return is_py_equal(CPyTagged_LongAsObject(x), CPyTagged_LongAsObject(y));
|
||||
}
|
||||
}
|
||||
|
||||
static void fail(std::string message) {
|
||||
std::cerr << message << "\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static PyObject *eval(std::string expr) {
|
||||
PyObject *dict = PyDict_New();
|
||||
auto result = PyRun_String(expr.c_str(), Py_eval_input, moduleDict, dict);
|
||||
Py_DECREF(dict);
|
||||
if (result == 0) {
|
||||
fail("Python exception");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static CPyTagged eval_int(std::string expr) {
|
||||
auto o = eval(expr);
|
||||
EXPECT_TRUE(PyLong_Check(o));
|
||||
return CPyTagged_FromObject(o);
|
||||
}
|
||||
|
||||
static PyObject *empty_list() {
|
||||
PyObject *list = PyList_New(0);
|
||||
EXPECT_TRUE(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
static void list_append(PyObject *list, std::string expr) {
|
||||
PyObject *obj = eval(expr);
|
||||
int result = PyList_Append(list, obj);
|
||||
EXPECT_TRUE(result == 0);
|
||||
}
|
||||
|
||||
class CAPITest : public ::testing::Test {
|
||||
protected:
|
||||
PyObject *max_short;
|
||||
PyObject *min_short;
|
||||
PyObject *min_pos_long;
|
||||
PyObject *max_neg_long;
|
||||
Py_ssize_t c_max_short;
|
||||
Py_ssize_t c_min_short;
|
||||
Py_ssize_t c_min_pos_long;
|
||||
Py_ssize_t c_max_neg_long;
|
||||
|
||||
virtual void SetUp() {
|
||||
if (!moduleDict) {
|
||||
fail("Could not find module dictionary");
|
||||
}
|
||||
|
||||
c_max_short = CPY_TAGGED_MAX; // 2**62-1
|
||||
c_min_pos_long = c_max_short + 1; // 2**62
|
||||
c_min_short = CPY_TAGGED_MIN; // -2**62
|
||||
c_max_neg_long = c_min_short - 1; // -(2**62+1)
|
||||
max_short = PyLong_FromSsize_t(c_max_short);
|
||||
min_pos_long = PyLong_FromSsize_t(c_min_pos_long);
|
||||
min_short = PyLong_FromSsize_t(c_min_short);
|
||||
max_neg_long = PyLong_FromSsize_t(c_max_neg_long);
|
||||
}
|
||||
|
||||
virtual void TearDown() {
|
||||
Py_DECREF(max_short);
|
||||
Py_DECREF(min_pos_long);
|
||||
Py_DECREF(min_short);
|
||||
Py_DECREF(max_neg_long);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(CAPITest, test_cint_conversions) {
|
||||
EXPECT_EQ(CPyTagged_ShortFromInt(0), 0);
|
||||
EXPECT_EQ(CPyTagged_ShortFromInt(3), 6);
|
||||
EXPECT_EQ(CPyTagged_ShortFromInt(-5), -10);
|
||||
EXPECT_EQ(CPyTagged_ShortAsSsize_t(0), 0);
|
||||
EXPECT_EQ(CPyTagged_ShortAsSsize_t(6), 3);
|
||||
EXPECT_EQ(CPyTagged_ShortAsSsize_t(-10), -5);
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_is_long_int) {
|
||||
EXPECT_TRUE(CPyTagged_CheckLong(1));
|
||||
EXPECT_TRUE(CPyTagged_CheckLong(15));
|
||||
EXPECT_FALSE(CPyTagged_CheckLong(0));
|
||||
EXPECT_FALSE(CPyTagged_CheckLong(6));
|
||||
EXPECT_FALSE(CPyTagged_CheckLong(-4));
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_is_short_int) {
|
||||
EXPECT_FALSE(CPyTagged_CheckShort(1));
|
||||
EXPECT_FALSE(CPyTagged_CheckShort(15));
|
||||
EXPECT_TRUE(CPyTagged_CheckShort(0));
|
||||
EXPECT_TRUE(CPyTagged_CheckShort(6));
|
||||
EXPECT_TRUE(CPyTagged_CheckShort(-4));
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_obj_to_short_int) {
|
||||
EXPECT_EQ(CPyTagged_FromObject(int_from_str("0")), CPyTagged_ShortFromInt(0));
|
||||
EXPECT_EQ(CPyTagged_FromObject(int_from_str("1234")), CPyTagged_ShortFromInt(1234));
|
||||
EXPECT_EQ(CPyTagged_FromObject(int_from_str("-1234")), CPyTagged_ShortFromInt(-1234));
|
||||
|
||||
EXPECT_EQ(CPyTagged_FromObject(max_short), CPyTagged_ShortFromSsize_t(c_max_short));
|
||||
EXPECT_EQ(CPyTagged_FromObject(min_short), CPyTagged_ShortFromSsize_t(c_min_short));
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_obj_to_long_int) {
|
||||
// A value larger than 2**64
|
||||
PyObject *large = int_from_str("18464758493694263305");
|
||||
PyObject *small = int_from_str("-18464758493694263305");
|
||||
CPyTagged x;
|
||||
|
||||
x = CPyTagged_FromObject(large);
|
||||
ASSERT_TRUE(CPyTagged_CheckLong(x));
|
||||
EXPECT_TRUE(is_py_equal(large, CPyTagged_LongAsObject(x)));
|
||||
|
||||
x = CPyTagged_FromObject(small);
|
||||
ASSERT_TRUE(CPyTagged_CheckLong(x));
|
||||
EXPECT_TRUE(is_py_equal(small, CPyTagged_LongAsObject(x)));
|
||||
|
||||
x = CPyTagged_FromObject(min_pos_long);
|
||||
ASSERT_TRUE(CPyTagged_CheckLong(x));
|
||||
EXPECT_TRUE(is_py_equal(min_pos_long, CPyTagged_LongAsObject(x)));
|
||||
|
||||
x = CPyTagged_FromObject(max_neg_long);
|
||||
ASSERT_TRUE(CPyTagged_CheckLong(x));
|
||||
EXPECT_TRUE(is_py_equal(max_neg_long, CPyTagged_LongAsObject(x)));
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_short_int_to_obj) {
|
||||
EXPECT_TRUE(is_py_equal(CPyTagged_AsObject(CPyTagged_ShortFromInt(0)), int_from_str("0")));
|
||||
EXPECT_TRUE(is_py_equal(CPyTagged_AsObject(CPyTagged_ShortFromInt(1234)),
|
||||
int_from_str("1234")));
|
||||
EXPECT_TRUE(is_py_equal(CPyTagged_AsObject(CPyTagged_ShortFromInt(-1234)),
|
||||
int_from_str("-1234")));
|
||||
EXPECT_TRUE(is_py_equal(CPyTagged_AsObject(CPyTagged_ShortFromSsize_t(c_max_short)),
|
||||
max_short));
|
||||
EXPECT_TRUE(is_py_equal(CPyTagged_AsObject(CPyTagged_ShortFromSsize_t(c_min_short)),
|
||||
min_short));
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_long_int_to_obj) {
|
||||
// A value larger than 2**64
|
||||
PyObject *large = int_from_str("18464758493694263305");
|
||||
PyObject *small = int_from_str("-18464758493694263305");
|
||||
PyObject *x;
|
||||
|
||||
x = CPyTagged_AsObject(CPyTagged_FromObject(large));
|
||||
EXPECT_TRUE(is_py_equal(large, x));
|
||||
x = CPyTagged_AsObject(CPyTagged_FromObject(small));
|
||||
EXPECT_TRUE(is_py_equal(small, x));
|
||||
x = CPyTagged_AsObject(CPyTagged_FromObject(min_pos_long));
|
||||
EXPECT_TRUE(is_py_equal(min_pos_long, x));
|
||||
x = CPyTagged_AsObject(CPyTagged_FromObject(max_neg_long));
|
||||
EXPECT_TRUE(is_py_equal(max_neg_long, x));
|
||||
}
|
||||
|
||||
#define EXPECT_INT_EQUAL(x, y) \
|
||||
do { \
|
||||
if (!is_int_equal(x, y)) \
|
||||
std::cout << "Failure: " << str_from_int(x) << " != " << str_from_int(y) << \
|
||||
"\n"; \
|
||||
EXPECT_TRUE(is_int_equal(x, y)); \
|
||||
} while (false)
|
||||
|
||||
#define ASSERT_ADD(x, y, result) \
|
||||
EXPECT_TRUE(is_int_equal(CPyTagged_Add(eval_int(x), eval_int(y)), eval_int(result)))
|
||||
|
||||
TEST_F(CAPITest, test_add_short_int) {
|
||||
ASSERT_ADD("13", "8", "21");
|
||||
ASSERT_ADD("-13", "8", "-5");
|
||||
ASSERT_ADD("13", "-7", "6");
|
||||
ASSERT_ADD("13", "-14", "-1");
|
||||
ASSERT_ADD("-3", "-5", "-8");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_add_long_ints) {
|
||||
ASSERT_ADD("2**64", "2**65", "2**64 + 2**65");
|
||||
ASSERT_ADD("2**64", "-2**65", "2**64 - 2**65");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_add_long_and_short) {
|
||||
ASSERT_ADD("1", "2**65", "1 + 2**65");
|
||||
ASSERT_ADD("2**65", "1", "1 + 2**65");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_add_short_overflow) {
|
||||
// Overfloat
|
||||
ASSERT_ADD("2**62 - 1", "1", "2**62");
|
||||
ASSERT_ADD("-2**62", "-1", "-2**62 - 1");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_add_short_edge_cases) {
|
||||
// Close but not quite overflow
|
||||
ASSERT_ADD("2**62 - 2", "1", "2**62 - 1");
|
||||
ASSERT_ADD("-2**62 + 1", "-1", "-2**62");
|
||||
// Max magnitudes
|
||||
ASSERT_ADD("2**62 - 1", "2**62 - 1", "2**63 - 2");
|
||||
ASSERT_ADD("2**62 - 1", "-2**62", "-1");
|
||||
}
|
||||
|
||||
#define ASSERT_SUBTRACT(x, y, result) \
|
||||
EXPECT_TRUE(is_int_equal(CPyTagged_Subtract(eval_int(x), eval_int(y)), eval_int(result)))
|
||||
|
||||
TEST_F(CAPITest, test_subtract_short_int) {
|
||||
ASSERT_SUBTRACT("13", "8", "5");
|
||||
ASSERT_SUBTRACT("8", "13", "-5");
|
||||
ASSERT_SUBTRACT("-13", "8", "-21");
|
||||
ASSERT_SUBTRACT("13", "-7", "20");
|
||||
ASSERT_SUBTRACT("-3", "-5", "2");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_subtract_long_int) {
|
||||
ASSERT_SUBTRACT("2**65", "2**64", "2**65 - 2**64");
|
||||
ASSERT_SUBTRACT("2**65", "-2**64", "2**65 + 2**64");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_subtract_long_and_short) {
|
||||
ASSERT_SUBTRACT("1", "2**65", "1 - 2**65");
|
||||
ASSERT_SUBTRACT("2**65", "1", "2**65 - 1");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_subtract_short_overflow) {
|
||||
ASSERT_SUBTRACT("2**62-1", "-1", "2**62");
|
||||
ASSERT_SUBTRACT("-2**62", "1", "-2**62 - 1");
|
||||
ASSERT_SUBTRACT("0", "-2**62", "2**62");
|
||||
ASSERT_SUBTRACT("1", "-2**62 + 1", "2**62");
|
||||
ASSERT_SUBTRACT("-2", "2**62 - 1", "-2**62 - 1");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_subtract_short_edge_cases) {
|
||||
// Close but not quite overflow
|
||||
ASSERT_SUBTRACT("2**62 - 2", "-1", "2**62 - 1");
|
||||
ASSERT_SUBTRACT("-2**62 + 1", "1", "-2**62");
|
||||
// Max magnitudes
|
||||
ASSERT_SUBTRACT("2**62 - 1", "-2**62", "2**63 - 1");
|
||||
ASSERT_SUBTRACT("-2**62", "2**62 - 1", "-2**63 + 1");
|
||||
}
|
||||
|
||||
#define ASSERT_MULTIPLY(x, y, result) \
|
||||
EXPECT_TRUE(is_int_equal(CPyTagged_Multiply(eval_int(x), eval_int(y)), eval_int(result)))
|
||||
|
||||
TEST_F(CAPITest, test_multiply_int) {
|
||||
ASSERT_MULTIPLY("0", "0", "0");
|
||||
ASSERT_MULTIPLY("3", "5", "15");
|
||||
ASSERT_MULTIPLY("2**40", "2**40", "2**80");
|
||||
ASSERT_MULTIPLY("2**30-1", "2**30-1", "(2**30-1)**2");
|
||||
ASSERT_MULTIPLY("2**30", "2**30-1", "2**30 * (2**30-1)");
|
||||
ASSERT_MULTIPLY("2**30-1", "2**30", "2**30 * (2**30-1)");
|
||||
ASSERT_MULTIPLY("2**15", "2**15-1", "2**15 * (2**15-1)");
|
||||
ASSERT_MULTIPLY("2**15-1", "2**15", "2**15 * (2**15-1)");
|
||||
ASSERT_MULTIPLY("3", "-5", "-15");
|
||||
ASSERT_MULTIPLY("-3", "5", "-15");
|
||||
ASSERT_MULTIPLY("-3", "-5", "15");
|
||||
}
|
||||
|
||||
#define ASSERT_FLOOR_DIV(x, y, result) \
|
||||
EXPECT_INT_EQUAL(CPyTagged_FloorDivide(eval_int(x), eval_int(y)), eval_int(result))
|
||||
|
||||
TEST_F(CAPITest, test_floor_divide_short_int) {
|
||||
ASSERT_FLOOR_DIV("18", "6", "3");
|
||||
ASSERT_FLOOR_DIV("17", "6", "2");
|
||||
ASSERT_FLOOR_DIV("12", "6", "2");
|
||||
ASSERT_FLOOR_DIV("15", "5", "3");
|
||||
ASSERT_FLOOR_DIV("14", "5", "2");
|
||||
ASSERT_FLOOR_DIV("11", "5", "2");
|
||||
ASSERT_FLOOR_DIV("-18", "6", "-3");
|
||||
ASSERT_FLOOR_DIV("-13", "6", "-3");
|
||||
ASSERT_FLOOR_DIV("-12", "6", "-2");
|
||||
ASSERT_FLOOR_DIV("18", "-6", "-3");
|
||||
ASSERT_FLOOR_DIV("13", "-6", "-3");
|
||||
ASSERT_FLOOR_DIV("12", "-6", "-2");
|
||||
ASSERT_FLOOR_DIV("-3", "-3", "1");
|
||||
ASSERT_FLOOR_DIV("-5", "-3", "1");
|
||||
ASSERT_FLOOR_DIV("-6", "-3", "2");
|
||||
|
||||
ASSERT_FLOOR_DIV("2**60", "3", "2**60 // 3");
|
||||
ASSERT_FLOOR_DIV("-2**62", "-1", "2**62");
|
||||
ASSERT_FLOOR_DIV("-2**62", "1", "-2**62");
|
||||
ASSERT_FLOOR_DIV("2**62 - 1", "1", "2**62 - 1");
|
||||
ASSERT_FLOOR_DIV("2**62 - 1", "-1", "-2**62 + 1");
|
||||
ASSERT_FLOOR_DIV("2**60", "3", "2**60 // 3");
|
||||
ASSERT_FLOOR_DIV("-2**30", "-1", "2**30");
|
||||
ASSERT_FLOOR_DIV("-2**30", "1", "-2**30");
|
||||
ASSERT_FLOOR_DIV("2**30 - 1", "1", "2**30 - 1");
|
||||
ASSERT_FLOOR_DIV("2**30 - 1", "-1", "-2**30 + 1");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_floor_divide_long_int) {
|
||||
ASSERT_FLOOR_DIV("2**100", "3", "2**100 // 3");
|
||||
ASSERT_FLOOR_DIV("3", "2**100", "0");
|
||||
ASSERT_FLOOR_DIV("2**100", "2**70 // 3", "2**100 // (2**70 // 3)");
|
||||
}
|
||||
|
||||
#define ASSERT_REMAINDER(x, y, result) \
|
||||
EXPECT_INT_EQUAL(CPyTagged_Remainder(eval_int(x), eval_int(y)), eval_int(result))
|
||||
|
||||
TEST_F(CAPITest, test_remainder_short_int) {
|
||||
ASSERT_REMAINDER("18", "6", "0");
|
||||
ASSERT_REMAINDER("17", "6", "5");
|
||||
ASSERT_REMAINDER("13", "6", "1");
|
||||
ASSERT_REMAINDER("12", "6", "0");
|
||||
ASSERT_REMAINDER("15", "5", "0");
|
||||
ASSERT_REMAINDER("14", "5", "4");
|
||||
ASSERT_REMAINDER("11", "5", "1");
|
||||
ASSERT_REMAINDER("-18", "6", "0");
|
||||
ASSERT_REMAINDER("-13", "6", "5");
|
||||
ASSERT_REMAINDER("-12", "6", "0");
|
||||
ASSERT_REMAINDER("18", "-6", "0");
|
||||
ASSERT_REMAINDER("13", "-6", "-5");
|
||||
ASSERT_REMAINDER("12", "-6", "0");
|
||||
ASSERT_REMAINDER("-3", "-3", "0");
|
||||
ASSERT_REMAINDER("-5", "-3", "-2");
|
||||
ASSERT_REMAINDER("-6", "-3", "0");
|
||||
|
||||
ASSERT_REMAINDER("-1", "2**62 - 1", "2**62 - 2");
|
||||
ASSERT_REMAINDER("1", "-2**62", "-2**62 + 1");
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_remainder_long_int) {
|
||||
ASSERT_REMAINDER("2**100", "3", "2**100 % 3");
|
||||
ASSERT_REMAINDER("3", "2**100", "3");
|
||||
ASSERT_REMAINDER("2**100", "2**70 // 3", "2**100 % (2**70 // 3)");
|
||||
}
|
||||
|
||||
#define INT_EQ(x, y) \
|
||||
CPyTagged_IsEq(eval_int(x), eval_int(y))
|
||||
|
||||
TEST_F(CAPITest, test_int_equality) {
|
||||
EXPECT_TRUE(INT_EQ("0", "0"));
|
||||
EXPECT_TRUE(INT_EQ("5", "5"));
|
||||
EXPECT_TRUE(INT_EQ("-7", "-7"));
|
||||
EXPECT_TRUE(INT_EQ("2**65 + 0x1234", "2**65 + 0x1234"));
|
||||
EXPECT_TRUE(INT_EQ("-2**65 + 0x1234", "-2**65 + 0x1234"));
|
||||
EXPECT_FALSE(INT_EQ("0", "1"));
|
||||
EXPECT_FALSE(INT_EQ("5", "4"));
|
||||
EXPECT_FALSE(INT_EQ("-7", "7"));
|
||||
EXPECT_FALSE(INT_EQ("-7", "-6"));
|
||||
EXPECT_FALSE(INT_EQ("-7", "-5"));
|
||||
EXPECT_FALSE(INT_EQ("2**65 + 0x1234", "2**65 + 0x1233"));
|
||||
EXPECT_FALSE(INT_EQ("2**65 + 0x1234", "2**66 + 0x1234"));
|
||||
EXPECT_FALSE(INT_EQ("2**65 + 0x1234", "-2**65 - 0x1234"));
|
||||
EXPECT_FALSE(INT_EQ("-2**65 + 0x1234", "-2**65 + 0x1233"));
|
||||
}
|
||||
|
||||
#define INT_NE(x, y) \
|
||||
CPyTagged_IsNe(eval_int(x), eval_int(y))
|
||||
|
||||
TEST_F(CAPITest, test_int_non_equality) {
|
||||
EXPECT_FALSE(INT_NE("0", "0"));
|
||||
EXPECT_FALSE(INT_NE("5", "5"));
|
||||
EXPECT_FALSE(INT_NE("-7", "-7"));
|
||||
EXPECT_FALSE(INT_NE("2**65 + 0x1234", "2**65 + 0x1234"));
|
||||
EXPECT_FALSE(INT_NE("-2**65 + 0x1234", "-2**65 + 0x1234"));
|
||||
EXPECT_TRUE(INT_NE("0", "1"));
|
||||
EXPECT_TRUE(INT_NE("5", "4"));
|
||||
EXPECT_TRUE(INT_NE("-7", "7"));
|
||||
EXPECT_TRUE(INT_NE("-7", "-6"));
|
||||
EXPECT_TRUE(INT_NE("-7", "-5"));
|
||||
EXPECT_TRUE(INT_NE("2**65 + 0x1234", "2**65 + 0x1233"));
|
||||
EXPECT_TRUE(INT_NE("2**65 + 0x1234", "2**66 + 0x1234"));
|
||||
EXPECT_TRUE(INT_NE("2**65 + 0x1234", "-2**65 - 0x1234"));
|
||||
EXPECT_TRUE(INT_NE("-2**65 + 0x1234", "-2**65 + 0x1233"));
|
||||
}
|
||||
|
||||
#define INT_LT(x, y) \
|
||||
CPyTagged_IsLt(eval_int(x), eval_int(y))
|
||||
|
||||
TEST_F(CAPITest, test_int_less_than) {
|
||||
EXPECT_TRUE(INT_LT("0", "5"));
|
||||
EXPECT_TRUE(INT_LT("4", "5"));
|
||||
EXPECT_TRUE(INT_LT("-3", "1"));
|
||||
EXPECT_TRUE(INT_LT("-3", "0"));
|
||||
EXPECT_TRUE(INT_LT("-3", "-2"));
|
||||
|
||||
EXPECT_FALSE(INT_LT("5", "0"));
|
||||
EXPECT_FALSE(INT_LT("5", "4"));
|
||||
EXPECT_FALSE(INT_LT("1", "-3"));
|
||||
EXPECT_FALSE(INT_LT("0", "-3"));
|
||||
EXPECT_FALSE(INT_LT("-2", "-3"));
|
||||
EXPECT_FALSE(INT_LT("-3", "-3"));
|
||||
EXPECT_FALSE(INT_LT("3", "3"));
|
||||
|
||||
EXPECT_TRUE(INT_LT("5", "2**65"));
|
||||
EXPECT_TRUE(INT_LT("-2**65", "-5"));
|
||||
EXPECT_TRUE(INT_LT("-2**66", "2**65"));
|
||||
EXPECT_TRUE(INT_LT("2**65", "2**66"));
|
||||
EXPECT_TRUE(INT_LT("-2**66", "-2**65"));
|
||||
|
||||
EXPECT_FALSE(INT_LT("2**65", "5"));
|
||||
EXPECT_FALSE(INT_LT("-5", "-2**65"));
|
||||
EXPECT_FALSE(INT_LT("2**65", "-2**66"));
|
||||
EXPECT_FALSE(INT_LT("2**66", "2**65"));
|
||||
EXPECT_FALSE(INT_LT("-2**65", "-2**66"));
|
||||
EXPECT_FALSE(INT_LT("-2**65", "-2**65"));
|
||||
EXPECT_FALSE(INT_LT("2**65", "2**65"));
|
||||
}
|
||||
|
||||
#define INT_GE(x, y) \
|
||||
CPyTagged_IsGe(eval_int(x), eval_int(y))
|
||||
|
||||
TEST_F(CAPITest, test_int_greater_than_or_equal) {
|
||||
EXPECT_TRUE(INT_GE("3", "2"));
|
||||
EXPECT_TRUE(INT_GE("3", "3"));
|
||||
EXPECT_FALSE(INT_GE("3", "4"));
|
||||
EXPECT_TRUE(INT_GE("3", "-4"));
|
||||
EXPECT_TRUE(INT_GE("-3", "-4"));
|
||||
EXPECT_TRUE(INT_GE("-3", "-3"));
|
||||
EXPECT_FALSE(INT_GE("-3", "-2"));
|
||||
EXPECT_FALSE(INT_GE("-3", "2"));
|
||||
|
||||
EXPECT_TRUE(INT_GE("2**65", "2**65"));
|
||||
EXPECT_TRUE(INT_GE("2**65", "2**65 - 1"));
|
||||
EXPECT_FALSE(INT_GE("2**65", "2**65 + 1"));
|
||||
EXPECT_TRUE(INT_GE("2**65", "2**60"));
|
||||
}
|
||||
|
||||
#define INT_GT(x, y) \
|
||||
CPyTagged_IsGt(eval_int(x), eval_int(y))
|
||||
|
||||
TEST_F(CAPITest, test_int_greater_than) {
|
||||
EXPECT_TRUE(INT_GT("5", "0"));
|
||||
EXPECT_TRUE(INT_GT("5", "4"));
|
||||
EXPECT_FALSE(INT_GT("5", "5"));
|
||||
EXPECT_FALSE(INT_GT("5", "6"));
|
||||
|
||||
EXPECT_TRUE(INT_GT("1", "-3"));
|
||||
EXPECT_FALSE(INT_GT("-3", "1"));
|
||||
|
||||
EXPECT_TRUE(INT_GT("0", "-3"));
|
||||
EXPECT_TRUE(INT_GT("-2", "-3"));
|
||||
EXPECT_FALSE(INT_GT("-2", "-2"));
|
||||
EXPECT_FALSE(INT_GT("-2", "-1"));
|
||||
|
||||
EXPECT_TRUE(INT_GT("2**65", "5"));
|
||||
EXPECT_TRUE(INT_GT("2**65", "2**65 - 1"));
|
||||
EXPECT_FALSE(INT_GT("2**65", "2**65"));
|
||||
EXPECT_FALSE(INT_GT("2**65", "2**65 + 1"));
|
||||
|
||||
EXPECT_FALSE(INT_GT("-2**65", "1"));
|
||||
EXPECT_TRUE(INT_GT("-2**65", "-2**65 - 1"));
|
||||
EXPECT_FALSE(INT_GT("-2**65", "-2**65"));
|
||||
EXPECT_FALSE(INT_GT("-2**65", "-2**65 + 1"));
|
||||
}
|
||||
|
||||
#define INT_LE(x, y) \
|
||||
CPyTagged_IsLe(eval_int(x), eval_int(y))
|
||||
|
||||
TEST_F(CAPITest, test_int_less_than_or_equal) {
|
||||
EXPECT_TRUE(INT_LE("0", "5"));
|
||||
EXPECT_TRUE(INT_LE("5", "6"));
|
||||
EXPECT_TRUE(INT_LE("5", "5"));
|
||||
EXPECT_FALSE(INT_LE("5", "4"));
|
||||
|
||||
EXPECT_FALSE(INT_LE("1", "-3"));
|
||||
EXPECT_TRUE(INT_LE("-3", "1"));
|
||||
|
||||
EXPECT_TRUE(INT_LT("-3", "0"));
|
||||
EXPECT_TRUE(INT_LE("-2", "-1"));
|
||||
EXPECT_TRUE(INT_LE("-2", "-2"));
|
||||
EXPECT_FALSE(INT_LT("-2", "-3"));
|
||||
|
||||
EXPECT_TRUE(INT_LE("5", "2**65"));
|
||||
EXPECT_FALSE(INT_LE("2**65", "5"));
|
||||
EXPECT_TRUE(INT_LE("2**65", "2**65 + 1"));
|
||||
EXPECT_TRUE(INT_LE("2**65", "2**65"));
|
||||
EXPECT_FALSE(INT_LE("2**65", "2**65 - 1"));
|
||||
|
||||
EXPECT_TRUE(INT_LE("-2**65", "1"));
|
||||
EXPECT_FALSE(INT_LE("1", "-2**65"));
|
||||
EXPECT_TRUE(INT_LE("-2**65", "-2**65 + 1"));
|
||||
EXPECT_TRUE(INT_LE("-2**65", "-2**65"));
|
||||
EXPECT_FALSE(INT_LE("-2**65", "-2**65 - 1"));
|
||||
}
|
||||
|
||||
#define list_get_eq(list, index, value) \
|
||||
is_py_equal(CPyList_GetItem(list, eval_int(index)), eval(value))
|
||||
|
||||
TEST_F(CAPITest, test_list_get) {
|
||||
auto l = empty_list();
|
||||
list_append(l, "3");
|
||||
list_append(l, "5");
|
||||
list_append(l, "7");
|
||||
EXPECT_TRUE(list_get_eq(l, "0", "3"));
|
||||
EXPECT_TRUE(list_get_eq(l, "1", "5"));
|
||||
EXPECT_TRUE(list_get_eq(l, "2", "7"));
|
||||
EXPECT_TRUE(list_get_eq(l, "-1", "7"));
|
||||
EXPECT_TRUE(list_get_eq(l, "-2", "5"));
|
||||
EXPECT_TRUE(list_get_eq(l, "-3", "3"));
|
||||
}
|
||||
|
||||
TEST_F(CAPITest, test_tagged_as_long_long) {
|
||||
auto s = eval_int("3");
|
||||
auto neg = eval_int("-1");
|
||||
auto l = eval_int("2**128");
|
||||
EXPECT_TRUE(CPyTagged_AsSsize_t(s) == 3);
|
||||
EXPECT_FALSE(PyErr_Occurred());
|
||||
EXPECT_TRUE(CPyTagged_AsSsize_t(neg) == -1);
|
||||
EXPECT_FALSE(PyErr_Occurred());
|
||||
EXPECT_TRUE(CPyTagged_AsSsize_t(l) == -1);
|
||||
EXPECT_TRUE(PyErr_Occurred());
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
|
||||
////
|
||||
// Python module glue to drive the C-API tests.
|
||||
//
|
||||
// The reason we have this as an extension module instead of a
|
||||
// standalone binary is because building an extension module is pretty
|
||||
// well behaved (just specify it with distutils/setuptools and it will
|
||||
// get compiled and linked against the running python) while linking a
|
||||
// library against libpython is a huge non-standard
|
||||
// PITA: python-config locations are janky and it behaves in weird
|
||||
// ways that I don't understand, while this works very cleanly.
|
||||
|
||||
static PyObject *run_tests(PyObject *dummy, PyObject *should_be_null) {
|
||||
// Fake command line arguments. We could arrange to actually pass
|
||||
// in command line arguments (either real ones or ones given as
|
||||
// arguments) but have not bothered.
|
||||
int argc = 1;
|
||||
char asdf[] = "test_capi"; // InitGoogleTest wants char** which means it can't be const...
|
||||
char *argv[] = {asdf, NULL};
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return PyLong_FromLong(RUN_ALL_TESTS());
|
||||
}
|
||||
|
||||
|
||||
static PyMethodDef test_methods[] = {
|
||||
{"run_tests", run_tests, METH_NOARGS, "Run the C API tests"},
|
||||
{NULL, NULL, 0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef test_module = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
"test_capi",
|
||||
NULL,
|
||||
-1,
|
||||
test_methods
|
||||
};
|
||||
|
||||
PyMODINIT_FUNC
|
||||
PyInit_test_capi(void)
|
||||
{
|
||||
PyObject *module = PyModule_Create(&test_module);
|
||||
if (module) {
|
||||
moduleDict = PyModule_GetDict(module);
|
||||
}
|
||||
return module;
|
||||
}
|
||||
61
.venv/lib/python3.8/site-packages/mypyc/lib-rt/tuple_ops.c
Normal file
61
.venv/lib/python3.8/site-packages/mypyc/lib-rt/tuple_ops.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
// Tuple primitive operations
|
||||
//
|
||||
// These are registered in mypyc.primitives.tuple_ops.
|
||||
|
||||
#include <Python.h>
|
||||
#include "CPy.h"
|
||||
|
||||
PyObject *CPySequenceTuple_GetItem(PyObject *tuple, CPyTagged index) {
|
||||
if (CPyTagged_CheckShort(index)) {
|
||||
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
||||
Py_ssize_t size = PyTuple_GET_SIZE(tuple);
|
||||
if (n >= 0) {
|
||||
if (n >= size) {
|
||||
PyErr_SetString(PyExc_IndexError, "tuple index out of range");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
n += size;
|
||||
if (n < 0) {
|
||||
PyErr_SetString(PyExc_IndexError, "tuple index out of range");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
PyObject *result = PyTuple_GET_ITEM(tuple, n);
|
||||
Py_INCREF(result);
|
||||
return result;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PyObject *CPySequenceTuple_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end) {
|
||||
if (likely(PyTuple_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 += PyTuple_GET_SIZE(obj);
|
||||
}
|
||||
if (endn < 0) {
|
||||
endn += PyTuple_GET_SIZE(obj);
|
||||
}
|
||||
return PyTuple_GetSlice(obj, startn, endn);
|
||||
}
|
||||
return CPyObject_GetSlice(obj, start, end);
|
||||
}
|
||||
|
||||
// PyTuple_SET_ITEM does no error checking,
|
||||
// and should only be used to fill in brand new tuples.
|
||||
bool CPySequenceTuple_SetItemUnsafe(PyObject *tuple, CPyTagged index, PyObject *value)
|
||||
{
|
||||
if (CPyTagged_CheckShort(index)) {
|
||||
Py_ssize_t n = CPyTagged_ShortAsSsize_t(index);
|
||||
PyTuple_SET_ITEM(tuple, n, value);
|
||||
return true;
|
||||
} else {
|
||||
PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue