././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8627238 librt-0.11.0/0000755000175100017510000000000015200142335012346 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/CPy.h0000644000175100017510000011202315200142331013205 0ustar00runnerrunner// Mypyc C API #ifndef CPY_CPY_H #define CPY_CPY_H #include #include #include #include #include #include #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; #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; #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; #endif // System-wide empty tuple constant extern PyObject * __mypyc_empty_tuple__; static inline PyObject *CPyTuple_LoadEmptyTupleConstant(void) { #if !CPY_3_12_FEATURES Py_INCREF(__mypyc_empty_tuple__); #endif return __mypyc_empty_tuple__; } // 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_FromVoidPtr(void *ptr); CPyTagged CPyTagged_FromInt64(int64_t value); 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); bool CPyTagged_IsEq_(CPyTagged left, CPyTagged right); bool CPyTagged_IsLt_(CPyTagged left, CPyTagged right); 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_BitwiseLongOp_(CPyTagged a, CPyTagged b, char op); CPyTagged CPyTagged_Rshift_(CPyTagged left, CPyTagged right); CPyTagged CPyTagged_Lshift_(CPyTagged left, CPyTagged right); CPyTagged CPyTagged_BitLength(CPyTagged self); PyObject *CPyTagged_ToBytes(CPyTagged self, Py_ssize_t length, PyObject *byteorder, int signed_flag); PyObject *CPyTagged_ToBigEndianBytes(CPyTagged self, Py_ssize_t length, int signed_flag); PyObject *CPyTagged_ToLittleEndianBytes(CPyTagged self, Py_ssize_t length, int signed_flag); PyObject *CPyTagged_Str(CPyTagged n); PyObject *CPyTagged_AsciiBytes(CPyTagged n); CPyTagged CPyTagged_FromFloat(double f); PyObject *CPyLong_FromStrWithBase(PyObject *o, CPyTagged base); PyObject *CPyLong_FromStr(PyObject *o); PyObject *CPyBool_Str(bool b); int64_t CPyLong_AsInt64_(PyObject *o); int64_t CPyInt64_Divide(int64_t x, int64_t y); int64_t CPyInt64_Remainder(int64_t x, int64_t y); int32_t CPyLong_AsInt32_(PyObject *o); int32_t CPyInt32_Divide(int32_t x, int32_t y); int32_t CPyInt32_Remainder(int32_t x, int32_t y); void CPyInt32_Overflow(void); int16_t CPyLong_AsInt16_(PyObject *o); int16_t CPyInt16_Divide(int16_t x, int16_t y); int16_t CPyInt16_Remainder(int16_t x, int16_t y); void CPyInt16_Overflow(void); uint8_t CPyLong_AsUInt8_(PyObject *o); void CPyUInt8_Overflow(void); double CPyTagged_TrueDivide(CPyTagged x, CPyTagged y); 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 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; } } static inline 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; } } static inline 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; } } 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_TooBigInt64(int64_t value) { // Micro-optimized for the common case where it fits. return (uint64_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); } } static inline int64_t CPyLong_AsInt64(PyObject *o) { if (likely(PyLong_Check(o))) { PyLongObject *lobj = (PyLongObject *)o; #if CPY_3_12_FEATURES if (likely(PyUnstable_Long_IsCompact(lobj))) { return PyUnstable_Long_CompactValue(lobj); } #else Py_ssize_t size = Py_SIZE(lobj); if (likely(size == 1)) { // Fast path return CPY_LONG_DIGIT(lobj, 0); } else if (likely(size == 0)) { return 0; } #endif } // Slow path return CPyLong_AsInt64_(o); } static inline int32_t CPyLong_AsInt32(PyObject *o) { if (likely(PyLong_Check(o))) { #if CPY_3_12_FEATURES PyLongObject *lobj = (PyLongObject *)o; size_t tag = CPY_LONG_TAG(lobj); if (likely(tag == (1 << CPY_NON_SIZE_BITS))) { // Fast path return CPY_LONG_DIGIT(lobj, 0); } else if (likely(tag == CPY_SIGN_ZERO)) { return 0; } #else PyLongObject *lobj = (PyLongObject *)o; Py_ssize_t size = lobj->ob_base.ob_size; if (likely(size == 1)) { // Fast path return CPY_LONG_DIGIT(lobj, 0); } else if (likely(size == 0)) { return 0; } #endif } // Slow path return CPyLong_AsInt32_(o); } static inline int16_t CPyLong_AsInt16(PyObject *o) { if (likely(PyLong_Check(o))) { #if CPY_3_12_FEATURES PyLongObject *lobj = (PyLongObject *)o; size_t tag = CPY_LONG_TAG(lobj); if (likely(tag == (1 << CPY_NON_SIZE_BITS))) { // Fast path digit x = CPY_LONG_DIGIT(lobj, 0); if (x < 0x8000) return x; } else if (likely(tag == CPY_SIGN_ZERO)) { return 0; } #else PyLongObject *lobj = (PyLongObject *)o; Py_ssize_t size = lobj->ob_base.ob_size; if (likely(size == 1)) { // Fast path digit x = lobj->ob_digit[0]; if (x < 0x8000) return x; } else if (likely(size == 0)) { return 0; } #endif } // Slow path return CPyLong_AsInt16_(o); } static inline uint8_t CPyLong_AsUInt8(PyObject *o) { if (likely(PyLong_Check(o))) { #if CPY_3_12_FEATURES PyLongObject *lobj = (PyLongObject *)o; size_t tag = CPY_LONG_TAG(lobj); if (likely(tag == (1 << CPY_NON_SIZE_BITS))) { // Fast path digit x = CPY_LONG_DIGIT(lobj, 0); if (x < 256) return x; } else if (likely(tag == CPY_SIGN_ZERO)) { return 0; } #else PyLongObject *lobj = (PyLongObject *)o; Py_ssize_t size = lobj->ob_base.ob_size; if (likely(size == 1)) { // Fast path digit x = lobj->ob_digit[0]; if (x < 256) return x; } else if (likely(size == 0)) { return 0; } #endif } // Slow path return CPyLong_AsUInt8_(o); } static inline CPyTagged CPyTagged_Negate(CPyTagged num) { if (likely(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; } return CPyTagged_Negate_(num); } static inline 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; } } return CPyTagged_Add_(left, right); } static inline 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; } } return CPyTagged_Subtract_(left, right); } static inline CPyTagged CPyTagged_Multiply(CPyTagged left, CPyTagged right) { // TODO: Consider using some clang/gcc extension to check for overflow if (CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right)) { if (!CPyTagged_IsMultiplyOverflow(left, right)) { return left * CPyTagged_ShortAsSsize_t(right); } } return CPyTagged_Multiply_(left, right); } static inline 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; } return CPyTagged_FloorDivide_(left, right); } static inline 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; } return CPyTagged_Remainder_(left, right); } // Bitwise '~' static inline CPyTagged CPyTagged_Invert(CPyTagged num) { if (likely(CPyTagged_CheckShort(num) && num != CPY_TAGGED_ABS_MIN)) { return ~num & ~CPY_INT_TAG; } return CPyTagged_Invert_(num); } // Bitwise '&' static inline CPyTagged CPyTagged_And(CPyTagged left, CPyTagged right) { if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) { return left & right; } return CPyTagged_BitwiseLongOp_(left, right, '&'); } // Bitwise '|' static inline CPyTagged CPyTagged_Or(CPyTagged left, CPyTagged right) { if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) { return left | right; } return CPyTagged_BitwiseLongOp_(left, right, '|'); } // Bitwise '^' static inline CPyTagged CPyTagged_Xor(CPyTagged left, CPyTagged right) { if (likely(CPyTagged_CheckShort(left) && CPyTagged_CheckShort(right))) { return left ^ right; } return CPyTagged_BitwiseLongOp_(left, right, '^'); } // Bitwise '>>' static inline 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; } return CPyTagged_Rshift_(left, right); } static inline bool IsShortLshiftOverflow(Py_ssize_t short_int, Py_ssize_t shift) { return ((Py_ssize_t)(short_int << shift) >> shift) != short_int; } // Bitwise '<<' static inline 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; } return CPyTagged_Lshift_(left, right); } // Float operations double CPyFloat_FloorDivide(double x, double y); double CPyFloat_Pow(double x, double y); double CPyFloat_Sin(double x); double CPyFloat_Cos(double x); double CPyFloat_Tan(double x); double CPyFloat_Sqrt(double x); double CPyFloat_Exp(double x); double CPyFloat_Log(double x); CPyTagged CPyFloat_Floor(double x); CPyTagged CPyFloat_Ceil(double x); double CPyFloat_FromTagged(CPyTagged x); bool CPyFloat_IsInf(double x); bool CPyFloat_IsNaN(double x); // 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(void *p) { CPy_XDECREF((PyObject *)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 *CPyNumber_InPlacePower(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_GetItemShort(PyObject *list, CPyTagged index); PyObject *CPyList_GetItemBorrow(PyObject *list, CPyTagged index); PyObject *CPyList_GetItemShortBorrow(PyObject *list, CPyTagged index); PyObject *CPyList_GetItemInt64(PyObject *list, int64_t index); PyObject *CPyList_GetItemInt64Borrow(PyObject *list, int64_t index); bool CPyList_SetItem(PyObject *list, CPyTagged index, PyObject *value); void CPyList_SetItemUnsafe(PyObject *list, Py_ssize_t index, PyObject *value); bool CPyList_SetItemInt64(PyObject *list, int64_t 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_Sort(PyObject *seq); PyObject *CPySequence_Multiply(PyObject *seq, CPyTagged t_size); PyObject *CPySequence_RMultiply(CPyTagged t_size, PyObject *seq); PyObject *CPySequence_InPlaceMultiply(PyObject *seq, CPyTagged t_size); PyObject *CPyList_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end); char CPyList_Clear(PyObject *list); PyObject *CPyList_Copy(PyObject *list); int CPySequence_Check(PyObject *obj); // 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); int CPyMapping_Check(PyObject *obj); // Check that dictionary didn't change size during iteration. static inline char CPyDict_CheckSize(PyObject *dict, Py_ssize_t size) { if (!PyDict_CheckExact(dict)) { // Dict subclasses will be checked by Python runtime. return 1; } Py_ssize_t dict_size = PyDict_Size(dict); if (size != dict_size) { PyErr_SetString(PyExc_RuntimeError, "dictionary changed size during iteration"); return 0; } return 1; } // Str operations // Macros for strip type. These values are copied from CPython. #define LEFTSTRIP 0 #define RIGHTSTRIP 1 #define BOTHSTRIP 2 char CPyStr_Equal(PyObject *str1, PyObject *str2); char CPyStr_EqualLiteral(PyObject *str, PyObject *literal_str, Py_ssize_t literal_length); PyObject *CPyStr_Build(Py_ssize_t len, ...); PyObject *CPyStr_GetItem(PyObject *str, CPyTagged index); PyObject *CPyStr_GetItemUnsafe(PyObject *str, Py_ssize_t index); CPyTagged CPyStr_Find(PyObject *str, PyObject *substr, CPyTagged start, int direction); CPyTagged CPyStr_FindWithEnd(PyObject *str, PyObject *substr, CPyTagged start, CPyTagged end, int direction); PyObject *CPyStr_Split(PyObject *str, PyObject *sep, CPyTagged max_split); PyObject *CPyStr_RSplit(PyObject *str, PyObject *sep, CPyTagged max_split); PyObject *_CPyStr_Strip(PyObject *self, int strip_type, PyObject *sep); static inline PyObject *CPyStr_Strip(PyObject *self, PyObject *sep) { return _CPyStr_Strip(self, BOTHSTRIP, sep); } static inline PyObject *CPyStr_LStrip(PyObject *self, PyObject *sep) { return _CPyStr_Strip(self, LEFTSTRIP, sep); } static inline PyObject *CPyStr_RStrip(PyObject *self, PyObject *sep) { return _CPyStr_Strip(self, RIGHTSTRIP, sep); } 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); int CPyStr_Startswith(PyObject *self, PyObject *subobj); int CPyStr_Endswith(PyObject *self, PyObject *subobj); PyObject *CPyStr_Removeprefix(PyObject *self, PyObject *prefix); PyObject *CPyStr_Removesuffix(PyObject *self, PyObject *suffix); 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_DecodeUTF8(PyObject *bytes); PyObject *CPy_DecodeASCII(PyObject *bytes); PyObject *CPy_DecodeLatin1(PyObject *bytes); PyObject *CPy_Encode(PyObject *obj, PyObject *encoding, PyObject *errors); Py_ssize_t CPyStr_Count(PyObject *unicode, PyObject *substring, CPyTagged start); Py_ssize_t CPyStr_CountFull(PyObject *unicode, PyObject *substring, CPyTagged start, CPyTagged end); CPyTagged CPyStr_Ord(PyObject *obj); PyObject *CPyStr_Multiply(PyObject *str, CPyTagged count); PyObject *CPyStr_Lower(PyObject *str); PyObject *CPyStr_Upper(PyObject *str); bool CPyStr_IsSpace(PyObject *str); bool CPyStr_IsAlnum(PyObject *str); bool CPyStr_IsDigit(PyObject *str); // 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); CPyTagged CPyBytes_Ord(PyObject *obj); PyObject *CPyBytes_Multiply(PyObject *bytes, CPyTagged count); int CPyBytes_Startswith(PyObject *self, PyObject *subobj); int CPyBytes_Endswith(PyObject *self, PyObject *subobj); 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); PyObject *CPySequenceTuple_GetItemUnsafe(PyObject *tuple, Py_ssize_t index); void CPySequenceTuple_SetItemUnsafe(PyObject *tuple, Py_ssize_t 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_NoErrOccurred(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. #define CPy_ExcState() PyThreadState_GET()->exc_info 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); void CPy_TypeErrorTraceback(const char *filename, const char *funcname, int line, PyObject *globals, const char *expected, PyObject *value); void CPy_AttributeError(const char *filename, const char *funcname, const char *classname, const char *attrname, int line, PyObject *globals); // Misc operations #define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN(op, dealloc) #define CPy_TRASHCAN_END(op) Py_TRASHCAN_END // 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_TYPE(PyObject *obj) { PyObject *result = (PyObject *)Py_TYPE(obj); Py_INCREF(result); return result; } PyObject *CPy_CalculateMetaclass(PyObject *type, PyObject *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_FromTemplateWrapper(PyObject *template_, PyObject *orig_bases, PyObject *modname); bool CPy_InitSubclass(PyObject *type); int CPyDataclass_SleightOfHand(PyObject *dataclass_dec, PyObject *tp, PyObject *dict, PyObject *annotations, PyObject *dataclass_type); PyObject *CPyPickle_SetState(PyObject *obj, PyObject *state); PyObject *CPyPickle_GetState(PyObject *obj); CPyTagged CPyTagged_Id(PyObject *o); void CPyDebug_Print(const char *msg); void CPyDebug_PrintObject(PyObject *obj); 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, const int *frozensets); PyObject *CPy_Super(PyObject *builtins, PyObject *self); PyObject *CPy_CallReverseOpMethod(PyObject *left, PyObject *right, const char *op, PyObject *method); bool CPyImport_ImportMany(PyObject *modules, CPyModule **statics[], PyObject *globals, PyObject *tb_path, PyObject *tb_function, Py_ssize_t *tb_lines); PyObject *CPyImport_ImportFromMany(PyObject *mod_id, PyObject *names, PyObject *as_names, PyObject *globals); PyObject *CPyImport_GetNativeAttrs(PyObject *mod_id, PyObject *names, PyObject *as_names, PyObject *globals); PyObject *CPyImport_ImportNative(PyObject *module_name, PyObject *(*init_only_fn)(void), int (*exec_fn)(PyObject *), CPyModule **module_static, PyObject *shared_lib_file, PyObject *ext_suffix, Py_ssize_t is_package); int CPyImport_SetDunderAttrs(PyObject *module, PyObject *module_name, PyObject *shared_lib_file, PyObject *ext_suffix, Py_ssize_t is_package); PyObject *CPySingledispatch_RegisterFunction(PyObject *singledispatch_func, PyObject *cls, PyObject *func); PyObject *CPy_GetAIter(PyObject *obj); PyObject *CPy_GetANext(PyObject *aiter); void CPy_SetTypeAliasTypeComputeFunction(PyObject *alias, PyObject *compute_value); void CPyTrace_LogEvent(const char *location, const char *line, const char *op, const char *details); static inline PyObject *CPyObject_GenericGetAttr(PyObject *self, PyObject *name) { return _PyObject_GenericGetAttrWithDict(self, name, NULL, 1); } static inline int CPyObject_GenericSetAttr(PyObject *self, PyObject *name, PyObject *value) { return _PyObject_GenericSetAttrWithDict(self, name, value, NULL); } PyObject *CPy_SetupObject(PyObject *type); typedef struct { PyCMethodObject func; PyObject *func_name; PyObject *func_code; } CPyFunction; PyObject* CPyFunction_New(PyObject *module, const char *filename, const char *funcname, PyCFunction func, int func_flags, const char *func_doc, int first_line, int code_flags, bool has_self_arg); PyObject* CPyFunction_get_name(PyObject *op, void *context); int CPyFunction_set_name(PyObject *op, PyObject *value, void *context); PyObject* CPyFunction_get_code(PyObject *op, void *context); PyObject* CPyFunction_get_defaults(PyObject *op, void *context); PyObject* CPyFunction_get_kwdefaults(PyObject *op, void *context); PyObject* CPyFunction_get_annotations(PyObject *op, void *context); int CPyFunction_set_annotations(PyObject *op, PyObject *value, void *context); #if CPY_3_11_FEATURES PyObject *CPy_GetName(PyObject *obj); #endif #if CPY_3_14_FEATURES void CPy_SetImmortal(PyObject *obj); #endif #ifdef __cplusplus } #endif #endif // CPY_CPY_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/LICENSE0000644000175100017510000003076515200142320013360 0ustar00runnerrunnerMypyc runtime library is licensed under the terms of the MIT license, reproduced below. = = = = = The MIT License Copyright (c) 2025 Mypyc contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. = = = = = Portions of mypy and mypyc are licensed under different licenses. The files mypyc/lib-rt/pythonsupport.h, mypyc/lib-rt/getargs.c and mypyc/lib-rt/getargsfast.c are licensed under the PSF 2 License, reproduced below. = = = = = PYTHON SOFTWARE FOUNDATION LICENSE VERSION 2 -------------------------------------------- 1. This LICENSE AGREEMENT is between the Python Software Foundation ("PSF"), and the Individual or Organization ("Licensee") accessing and otherwise using this software ("Python") in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, PSF hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python alone or in any derivative version, provided, however, that PSF's License Agreement and PSF's notice of copyright, i.e., "Copyright (c) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012 Python Software Foundation; All Rights Reserved" are retained in Python alone or in any derivative version prepared by Licensee. 3. In the event Licensee prepares a derivative work that is based on or incorporates Python or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python. 4. PSF is making Python available to Licensee on an "AS IS" basis. PSF MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, PSF MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. PSF SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between PSF and Licensee. This License Agreement does not grant permission to use PSF trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By copying, installing or otherwise using Python, Licensee agrees to be bound by the terms and conditions of this License Agreement. BEOPEN.COM LICENSE AGREEMENT FOR PYTHON 2.0 ------------------------------------------- BEOPEN PYTHON OPEN SOURCE LICENSE AGREEMENT VERSION 1 1. This LICENSE AGREEMENT is between BeOpen.com ("BeOpen"), having an office at 160 Saratoga Avenue, Santa Clara, CA 95051, and the Individual or Organization ("Licensee") accessing and otherwise using this software in source or binary form and its associated documentation ("the Software"). 2. Subject to the terms and conditions of this BeOpen Python License Agreement, BeOpen hereby grants Licensee a non-exclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use the Software alone or in any derivative version, provided, however, that the BeOpen Python License is retained in the Software, alone or in any derivative version prepared by Licensee. 3. BeOpen is making the Software available to Licensee on an "AS IS" basis. BEOPEN MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, BEOPEN MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF THE SOFTWARE WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 4. BEOPEN SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF THE SOFTWARE FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THE SOFTWARE, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 5. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 6. This License Agreement shall be governed by and interpreted in all respects by the law of the State of California, excluding conflict of law provisions. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between BeOpen and Licensee. This License Agreement does not grant permission to use BeOpen trademarks or trade names in a trademark sense to endorse or promote products or services of Licensee, or any third party. As an exception, the "BeOpen Python" logos available at http://www.pythonlabs.com/logos.html may be used according to the permissions granted on that web page. 7. By copying, installing or otherwise using the software, Licensee agrees to be bound by the terms and conditions of this License Agreement. CNRI LICENSE AGREEMENT FOR PYTHON 1.6.1 --------------------------------------- 1. This LICENSE AGREEMENT is between the Corporation for National Research Initiatives, having an office at 1895 Preston White Drive, Reston, VA 20191 ("CNRI"), and the Individual or Organization ("Licensee") accessing and otherwise using Python 1.6.1 software in source or binary form and its associated documentation. 2. Subject to the terms and conditions of this License Agreement, CNRI hereby grants Licensee a nonexclusive, royalty-free, world-wide license to reproduce, analyze, test, perform and/or display publicly, prepare derivative works, distribute, and otherwise use Python 1.6.1 alone or in any derivative version, provided, however, that CNRI's License Agreement and CNRI's notice of copyright, i.e., "Copyright (c) 1995-2001 Corporation for National Research Initiatives; All Rights Reserved" are retained in Python 1.6.1 alone or in any derivative version prepared by Licensee. Alternately, in lieu of CNRI's License Agreement, Licensee may substitute the following text (omitting the quotes): "Python 1.6.1 is made available subject to the terms and conditions in CNRI's License Agreement. This Agreement together with Python 1.6.1 may be located on the Internet using the following unique, persistent identifier (known as a handle): 1895.22/1013. This Agreement may also be obtained from a proxy server on the Internet using the following URL: http://hdl.handle.net/1895.22/1013". 3. In the event Licensee prepares a derivative work that is based on or incorporates Python 1.6.1 or any part thereof, and wants to make the derivative work available to others as provided herein, then Licensee hereby agrees to include in any such work a brief summary of the changes made to Python 1.6.1. 4. CNRI is making Python 1.6.1 available to Licensee on an "AS IS" basis. CNRI MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, CNRI MAKES NO AND DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF PYTHON 1.6.1 WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. 5. CNRI SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF PYTHON 1.6.1 FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING PYTHON 1.6.1, OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF THE POSSIBILITY THEREOF. 6. This License Agreement will automatically terminate upon a material breach of its terms and conditions. 7. This License Agreement shall be governed by the federal intellectual property law of the United States, including without limitation the federal copyright law, and, to the extent such U.S. federal law does not apply, by the law of the Commonwealth of Virginia, excluding Virginia's conflict of law provisions. Notwithstanding the foregoing, with regard to derivative works based on Python 1.6.1 that incorporate non-separable material that was previously distributed under the GNU General Public License (GPL), the law of the Commonwealth of Virginia shall govern this License Agreement only as to issues arising under or with respect to Paragraphs 4, 5, and 7 of this License Agreement. Nothing in this License Agreement shall be deemed to create any relationship of agency, partnership, or joint venture between CNRI and Licensee. This License Agreement does not grant permission to use CNRI trademarks or trade name in a trademark sense to endorse or promote products or services of Licensee, or any third party. 8. By clicking on the "ACCEPT" button where indicated, or by copying, installing or otherwise using Python 1.6.1, Licensee agrees to be bound by the terms and conditions of this License Agreement. ACCEPT CWI LICENSE AGREEMENT FOR PYTHON 0.9.0 THROUGH 1.2 -------------------------------------------------- Copyright (c) 1991 - 1995, Stichting Mathematisch Centrum Amsterdam, The Netherlands. All rights reserved. Permission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and that both that copyright notice and this permission notice appear in supporting documentation, and that the name of Stichting Mathematisch Centrum or CWI not be used in advertising or publicity pertaining to distribution of the software without specific, written prior permission. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. = = = = = Files under lib-rt/base64 are licensed under the following license. = = = = = Copyright (c) 2005-2007, Nick Galbreath Copyright (c) 2015-2018, Wojciech Muła Copyright (c) 2016-2017, Matthieu Darbois Copyright (c) 2013-2022, Alfred Klomp All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/MANIFEST.in0000644000175100017510000000034315200142320014076 0ustar00runnerrunner# Headers are not included by default. recursive-include . *.h recursive-include . *.c # This is a (shared) dependency of setup.py include build_setup.py # Add smoke tests to validate build from sources. include smoke_tests.py ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8626976 librt-0.11.0/PKG-INFO0000644000175100017510000000242215200142335013443 0ustar00runnerrunnerMetadata-Version: 2.4 Name: librt Version: 0.11.0 Summary: Mypyc runtime library Author-email: Jukka Lehtosalo , Ivan Levkivskyi License-Expression: MIT Project-URL: Homepage, https://github.com/mypyc/librt Project-URL: Issues, https://github.com/mypyc/mypyc/issues Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 Classifier: Topic :: Software Development Classifier: Typing :: Typed Requires-Python: >=3.9 Description-Content-Type: text/x-rst License-File: LICENSE Dynamic: license-file Mypyc runtime library ===================== This library contains efficient C implementations of various Python standard library classes and functions. Mypyc can use these fast implementations when compiling Python code to native extension modules. Mypyc compiler is a part of `mypy distribution `__. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/README.md0000644000175100017510000000641215200142320013622 0ustar00runnerrunner# librt: mypyc runtime library [![Stable Version](https://img.shields.io/pypi/v/librt?color=blue)](https://pypi.org/project/librt/) [![Downloads](https://img.shields.io/pypi/dm/librt)](https://pypistats.org/packages/librt) [![Build Status](https://github.com/mypyc/librt/actions/workflows/buildwheels.yml/badge.svg)](https://github.com/mypyc/librt/actions) [![Checked with mypy](https://www.mypy-lang.org/static/mypy_badge.svg)](https://mypy-lang.org/) This library contains basic functionality that is useful in code compiled using mypyc, and efficient C implementations of various Python standard library classes and functions. Mypyc can produce faster extensions when you use `librt` in the code you compile. `librt` also contains some internal library features used by mypy. This repository is only used to build and publish the mypyc runtime library. Development happens in the [mypy repository](https://github.com/python/mypy). Code is then perodically synced from the `mypyc/lib-rt` [subdirectory in the mypy repository](https://github.com/python/mypy/tree/master/mypyc/lib-rt). Report any issues in the [mypyc issue tracker](https://github.com/mypyc/mypyc/issues). ## Developer notes Since this repo should be kept in sync with `mypy`, it has an unusual directory structure. If you want to install from sources, it is recommended to use `sdist` wheel. If you want to install directly form the repo, you will need to execute `cp -r lib-rt/* .` before install. See [issue #17](https://github.com/mypyc/librt/issues/17) for discussion. Unfortunatelly PyPy is not supported. If you develop a library that supports PyPy and you need `librt` only as a `mypy` dependency, you can skip PyPy in your CI matrix when type checking (since results of type checking will be identical on e.g. CPython 3.11 and PyPy 3.11). See [issue #16](https://github.com/mypyc/librt/issues/16) for discussion. ## Making a release 1. As a prerequisite, there generally will be some changes in the mypy repository under `mypyc/lib-rt` that you want to release. 2. Run the `sync-mypy.py` script in this repository to sync changes from the mypy repository. 3. Bump the version number in `pyproject.toml` in this repository. 4. Update `smoke_tests.py` (optional but recommended for new features). Here's how to run tests: * Activate a dedicated virtualenv (don't reuse your mypy virtualenv). * `pip install -U ./lib-rt` * `pip install pytest mypy-extensions` * `pytest smoke_tests.py` 5. Commit and push (pushing directly to master is fine). 6. Wait until all [builds](https://github.com/mypyc/librt/actions) complete successfully (no release is triggered yet). 7. Once builds are complete, tag the release (`git tag vX.Y.Z`; `git push origin vX.Y.Z`). 8. Go to the ["Actions" tab](https://github.com/mypyc/librt/actions) and click "Build wheels" on the left. 9. Click "Run workflow" and pick the newly created tag from the drop-down list. This will build *and upload* the wheels. 10. After the workflow completes, verify that `pip install -U librt` installs the new version from PyPI. 11. Create a PR to update the `librt` version in `mypy-requirements.txt`, `test-requirements.txt` and `pyproject.toml` (`dependencies`, and `requires` under `build-system`) in the mypy repository. The process should take about 20 minutes. ././@PaxHeader0000000000000000000000000000003200000000000010210 xustar0026 mtime=1778435292.84661 librt-0.11.0/base64/0000755000175100017510000000000015200142335013432 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8165812 librt-0.11.0/base64/arch/0000755000175100017510000000000015200142335014347 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8470356 librt-0.11.0/base64/arch/avx/0000755000175100017510000000000015200142335015145 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx/codec.c0000644000175100017510000000323315200142331016363 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if HAVE_AVX #if defined(__clang__) #pragma clang attribute push (__attribute__((target("avx"))), apply_to=function) #else #pragma GCC target("avx") #endif #include // Only enable inline assembly on supported compilers and on 64-bit CPUs. #ifndef BASE64_AVX_USE_ASM # if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64 # define BASE64_AVX_USE_ASM 1 # else # define BASE64_AVX_USE_ASM 0 # endif #endif #include "../ssse3/dec_reshuffle.c" #include "../ssse3/dec_loop.c" #if BASE64_AVX_USE_ASM # include "./enc_loop_asm.c" #else # include "../ssse3/enc_translate.c" # include "../ssse3/enc_reshuffle.c" # include "../ssse3/enc_loop.c" #endif #endif // HAVE_AVX void base64_stream_encode_avx BASE64_ENC_PARAMS { #if HAVE_AVX #include "../generic/enc_head.c" // For supported compilers, use a hand-optimized inline assembly // encoder. Otherwise fall back on the SSSE3 encoder, but compiled with // AVX flags to generate better optimized AVX code. #if BASE64_AVX_USE_ASM enc_loop_avx(&s, &slen, &o, &olen); #else enc_loop_ssse3(&s, &slen, &o, &olen); #endif #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } int base64_stream_decode_avx BASE64_DEC_PARAMS { #if HAVE_AVX #include "../generic/dec_head.c" dec_loop_ssse3(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #if defined(__clang__) #pragma clang attribute pop #endif #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx/enc_loop_asm.c0000644000175100017510000002214215200142331017744 0ustar00runnerrunner// Apologies in advance for combining the preprocessor with inline assembly, // two notoriously gnarly parts of C, but it was necessary to avoid a lot of // code repetition. The preprocessor is used to template large sections of // inline assembly that differ only in the registers used. If the code was // written out by hand, it would become very large and hard to audit. // Generate a block of inline assembly that loads register R0 from memory. The // offset at which the register is loaded is set by the given round. #define LOAD(R0, ROUND) \ "vlddqu ("#ROUND" * 12)(%[src]), %["R0"] \n\t" // Generate a block of inline assembly that deinterleaves and shuffles register // R0 using preloaded constants. Outputs in R0 and R1. #define SHUF(R0, R1, R2) \ "vpshufb %[lut0], %["R0"], %["R1"] \n\t" \ "vpand %["R1"], %[msk0], %["R2"] \n\t" \ "vpand %["R1"], %[msk2], %["R1"] \n\t" \ "vpmulhuw %["R2"], %[msk1], %["R2"] \n\t" \ "vpmullw %["R1"], %[msk3], %["R1"] \n\t" \ "vpor %["R1"], %["R2"], %["R1"] \n\t" // Generate a block of inline assembly that takes R0 and R1 and translates // their contents to the base64 alphabet, using preloaded constants. #define TRAN(R0, R1, R2) \ "vpsubusb %[n51], %["R1"], %["R0"] \n\t" \ "vpcmpgtb %[n25], %["R1"], %["R2"] \n\t" \ "vpsubb %["R2"], %["R0"], %["R0"] \n\t" \ "vpshufb %["R0"], %[lut1], %["R2"] \n\t" \ "vpaddb %["R1"], %["R2"], %["R0"] \n\t" // Generate a block of inline assembly that stores the given register R0 at an // offset set by the given round. #define STOR(R0, ROUND) \ "vmovdqu %["R0"], ("#ROUND" * 16)(%[dst]) \n\t" // Generate a block of inline assembly that generates a single self-contained // encoder round: fetch the data, process it, and store the result. Then update // the source and destination pointers. #define ROUND() \ LOAD("a", 0) \ SHUF("a", "b", "c") \ TRAN("a", "b", "c") \ STOR("a", 0) \ "add $12, %[src] \n\t" \ "add $16, %[dst] \n\t" // Define a macro that initiates a three-way interleaved encoding round by // preloading registers a, b and c from memory. // The register graph shows which registers are in use during each step, and // is a visual aid for choosing registers for that step. Symbol index: // // + indicates that a register is loaded by that step. // | indicates that a register is in use and must not be touched. // - indicates that a register is decommissioned by that step. // x indicates that a register is used as a temporary by that step. // V indicates that a register is an input or output to the macro. // #define ROUND_3_INIT() /* a b c d e f */ \ LOAD("a", 0) /* + */ \ SHUF("a", "d", "e") /* | + x */ \ LOAD("b", 1) /* | + | */ \ TRAN("a", "d", "e") /* | | - x */ \ LOAD("c", 2) /* V V V */ // Define a macro that translates, shuffles and stores the input registers A, B // and C, and preloads registers D, E and F for the next round. // This macro can be arbitrarily daisy-chained by feeding output registers D, E // and F back into the next round as input registers A, B and C. The macro // carefully interleaves memory operations with data operations for optimal // pipelined performance. #define ROUND_3(ROUND, A,B,C,D,E,F) /* A B C D E F */ \ LOAD(D, (ROUND + 3)) /* V V V + */ \ SHUF(B, E, F) /* | | | | + x */ \ STOR(A, (ROUND + 0)) /* - | | | | */ \ TRAN(B, E, F) /* | | | - x */ \ LOAD(E, (ROUND + 4)) /* | | | + */ \ SHUF(C, A, F) /* + | | | | x */ \ STOR(B, (ROUND + 1)) /* | - | | | */ \ TRAN(C, A, F) /* - | | | x */ \ LOAD(F, (ROUND + 5)) /* | | | + */ \ SHUF(D, A, B) /* + x | | | | */ \ STOR(C, (ROUND + 2)) /* | - | | | */ \ TRAN(D, A, B) /* - x V V V */ // Define a macro that terminates a ROUND_3 macro by taking pre-loaded // registers D, E and F, and translating, shuffling and storing them. #define ROUND_3_END(ROUND, A,B,C,D,E,F) /* A B C D E F */ \ SHUF(E, A, B) /* + x V V V */ \ STOR(D, (ROUND + 3)) /* | - | | */ \ TRAN(E, A, B) /* - x | | */ \ SHUF(F, C, D) /* + x | | */ \ STOR(E, (ROUND + 4)) /* | - | */ \ TRAN(F, C, D) /* - x | */ \ STOR(F, (ROUND + 5)) /* - */ // Define a type A round. Inputs are a, b, and c, outputs are d, e, and f. #define ROUND_3_A(ROUND) \ ROUND_3(ROUND, "a", "b", "c", "d", "e", "f") // Define a type B round. Inputs and outputs are swapped with regard to type A. #define ROUND_3_B(ROUND) \ ROUND_3(ROUND, "d", "e", "f", "a", "b", "c") // Terminating macro for a type A round. #define ROUND_3_A_LAST(ROUND) \ ROUND_3_A(ROUND) \ ROUND_3_END(ROUND, "a", "b", "c", "d", "e", "f") // Terminating macro for a type B round. #define ROUND_3_B_LAST(ROUND) \ ROUND_3_B(ROUND) \ ROUND_3_END(ROUND, "d", "e", "f", "a", "b", "c") // Suppress clang's warning that the literal string in the asm statement is // overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99 // compilers). It may be true, but the goal here is not C99 portability. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverlength-strings" static inline void enc_loop_avx (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { // For a clearer explanation of the algorithm used by this function, // please refer to the plain (not inline assembly) implementation. This // function follows the same basic logic. if (*slen < 16) { return; } // Process blocks of 12 bytes at a time. Input is read in blocks of 16 // bytes, so "reserve" four bytes from the input buffer to ensure that // we never read beyond the end of the input buffer. size_t rounds = (*slen - 4) / 12; *slen -= rounds * 12; // 12 bytes consumed per round *olen += rounds * 16; // 16 bytes produced per round // Number of times to go through the 36x loop. size_t loops = rounds / 36; // Number of rounds remaining after the 36x loop. rounds %= 36; // Lookup tables. const __m128i lut0 = _mm_set_epi8( 10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1); const __m128i lut1 = _mm_setr_epi8( 65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0); // Temporary registers. __m128i a, b, c, d, e, f; __asm__ volatile ( // If there are 36 rounds or more, enter a 36x unrolled loop of // interleaved encoding rounds. The rounds interleave memory // operations (load/store) with data operations (table lookups, // etc) to maximize pipeline throughput. " test %[loops], %[loops] \n\t" " jz 18f \n\t" " jmp 36f \n\t" " \n\t" ".balign 64 \n\t" "36: " ROUND_3_INIT() " " ROUND_3_A( 0) " " ROUND_3_B( 3) " " ROUND_3_A( 6) " " ROUND_3_B( 9) " " ROUND_3_A(12) " " ROUND_3_B(15) " " ROUND_3_A(18) " " ROUND_3_B(21) " " ROUND_3_A(24) " " ROUND_3_B(27) " " ROUND_3_A_LAST(30) " add $(12 * 36), %[src] \n\t" " add $(16 * 36), %[dst] \n\t" " dec %[loops] \n\t" " jnz 36b \n\t" // Enter an 18x unrolled loop for rounds of 18 or more. "18: cmp $18, %[rounds] \n\t" " jl 9f \n\t" " " ROUND_3_INIT() " " ROUND_3_A(0) " " ROUND_3_B(3) " " ROUND_3_A(6) " " ROUND_3_B(9) " " ROUND_3_A_LAST(12) " sub $18, %[rounds] \n\t" " add $(12 * 18), %[src] \n\t" " add $(16 * 18), %[dst] \n\t" // Enter a 9x unrolled loop for rounds of 9 or more. "9: cmp $9, %[rounds] \n\t" " jl 6f \n\t" " " ROUND_3_INIT() " " ROUND_3_A(0) " " ROUND_3_B_LAST(3) " sub $9, %[rounds] \n\t" " add $(12 * 9), %[src] \n\t" " add $(16 * 9), %[dst] \n\t" // Enter a 6x unrolled loop for rounds of 6 or more. "6: cmp $6, %[rounds] \n\t" " jl 55f \n\t" " " ROUND_3_INIT() " " ROUND_3_A_LAST(0) " sub $6, %[rounds] \n\t" " add $(12 * 6), %[src] \n\t" " add $(16 * 6), %[dst] \n\t" // Dispatch the remaining rounds 0..5. "55: cmp $3, %[rounds] \n\t" " jg 45f \n\t" " je 3f \n\t" " cmp $1, %[rounds] \n\t" " jg 2f \n\t" " je 1f \n\t" " jmp 0f \n\t" "45: cmp $4, %[rounds] \n\t" " je 4f \n\t" // Block of non-interlaced encoding rounds, which can each // individually be jumped to. Rounds fall through to the next. "5: " ROUND() "4: " ROUND() "3: " ROUND() "2: " ROUND() "1: " ROUND() "0: \n\t" // Outputs (modified). : [rounds] "+r" (rounds), [loops] "+r" (loops), [src] "+r" (*s), [dst] "+r" (*o), [a] "=&x" (a), [b] "=&x" (b), [c] "=&x" (c), [d] "=&x" (d), [e] "=&x" (e), [f] "=&x" (f) // Inputs (not modified). : [lut0] "x" (lut0), [lut1] "x" (lut1), [msk0] "x" (_mm_set1_epi32(0x0FC0FC00)), [msk1] "x" (_mm_set1_epi32(0x04000040)), [msk2] "x" (_mm_set1_epi32(0x003F03F0)), [msk3] "x" (_mm_set1_epi32(0x01000010)), [n51] "x" (_mm_set1_epi8(51)), [n25] "x" (_mm_set1_epi8(25)) // Clobbers. : "cc", "memory" ); } #pragma GCC diagnostic pop ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8483224 librt-0.11.0/base64/arch/avx2/0000755000175100017510000000000015200142335015227 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx2/codec.c0000644000175100017510000000256615200142331016455 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if HAVE_AVX2 #if defined(__clang__) #pragma clang attribute push (__attribute__((target("avx2"))), apply_to=function) #else #pragma GCC target("avx2") #endif #include // Only enable inline assembly on supported compilers and on 64-bit CPUs. #ifndef BASE64_AVX2_USE_ASM # if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64 # define BASE64_AVX2_USE_ASM 1 # else # define BASE64_AVX2_USE_ASM 0 # endif #endif #include "./dec_reshuffle.c" #include "./dec_loop.c" #if BASE64_AVX2_USE_ASM # include "./enc_loop_asm.c" #else # include "./enc_translate.c" # include "./enc_reshuffle.c" # include "./enc_loop.c" #endif #endif // HAVE_AVX2 void base64_stream_encode_avx2 BASE64_ENC_PARAMS { #if HAVE_AVX2 #include "../generic/enc_head.c" enc_loop_avx2(&s, &slen, &o, &olen); #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } int base64_stream_decode_avx2 BASE64_DEC_PARAMS { #if HAVE_AVX2 #include "../generic/dec_head.c" dec_loop_avx2(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #if defined(__clang__) #pragma clang attribute pop #endif #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx2/dec_loop.c0000644000175100017510000000623515200142331017161 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE int dec_loop_avx2_inner (const uint8_t **s, uint8_t **o, size_t *rounds) { const __m256i lut_lo = _mm256_setr_epi8( 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A, 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A); const __m256i lut_hi = _mm256_setr_epi8( 0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10); const __m256i lut_roll = _mm256_setr_epi8( 0, 16, 19, 4, -65, -65, -71, -71, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 19, 4, -65, -65, -71, -71, 0, 0, 0, 0, 0, 0, 0, 0); const __m256i mask_2F = _mm256_set1_epi8(0x2F); // Load input: __m256i str = _mm256_loadu_si256((__m256i *) *s); // See the SSSE3 decoder for an explanation of the algorithm. const __m256i hi_nibbles = _mm256_and_si256(_mm256_srli_epi32(str, 4), mask_2F); const __m256i lo_nibbles = _mm256_and_si256(str, mask_2F); const __m256i hi = _mm256_shuffle_epi8(lut_hi, hi_nibbles); const __m256i lo = _mm256_shuffle_epi8(lut_lo, lo_nibbles); if (!_mm256_testz_si256(lo, hi)) { return 0; } const __m256i eq_2F = _mm256_cmpeq_epi8(str, mask_2F); const __m256i roll = _mm256_shuffle_epi8(lut_roll, _mm256_add_epi8(eq_2F, hi_nibbles)); // Now simply add the delta values to the input: str = _mm256_add_epi8(str, roll); // Reshuffle the input to packed 12-byte output format: str = dec_reshuffle(str); // Store the output: _mm256_storeu_si256((__m256i *) *o, str); *s += 32; *o += 24; *rounds -= 1; return 1; } static inline void dec_loop_avx2 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 45) { return; } // Process blocks of 32 bytes per round. Because 8 extra zero bytes are // written after the output, ensure that there will be at least 13 // bytes of input data left to cover the gap. (11 data bytes and up to // two end-of-string markers.) size_t rounds = (*slen - 13) / 32; *slen -= rounds * 32; // 32 bytes consumed per round *olen += rounds * 24; // 24 bytes produced per round do { if (rounds >= 8) { if (dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 4) { if (dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 2) { if (dec_loop_avx2_inner(s, o, &rounds) && dec_loop_avx2_inner(s, o, &rounds)) { continue; } break; } dec_loop_avx2_inner(s, o, &rounds); break; } while (rounds > 0); // Adjust for any rounds that were skipped: *slen += rounds * 32; *olen -= rounds * 24; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx2/dec_reshuffle.c0000644000175100017510000000243015200142331020164 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE __m256i dec_reshuffle (const __m256i in) { // in, lower lane, bits, upper case are most significant bits, lower // case are least significant bits: // 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ // 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG // 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD // 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA const __m256i merge_ab_and_bc = _mm256_maddubs_epi16(in, _mm256_set1_epi32(0x01400140)); // 0000kkkk LLllllll 0000JJJJ JJjjKKKK // 0000hhhh IIiiiiii 0000GGGG GGggHHHH // 0000eeee FFffffff 0000DDDD DDddEEEE // 0000bbbb CCcccccc 0000AAAA AAaaBBBB __m256i out = _mm256_madd_epi16(merge_ab_and_bc, _mm256_set1_epi32(0x00011000)); // 00000000 JJJJJJjj KKKKkkkk LLllllll // 00000000 GGGGGGgg HHHHhhhh IIiiiiii // 00000000 DDDDDDdd EEEEeeee FFffffff // 00000000 AAAAAAaa BBBBbbbb CCcccccc // Pack bytes together in each lane: out = _mm256_shuffle_epi8(out, _mm256_setr_epi8( 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, -1, -1, -1, -1, 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, -1, -1, -1, -1)); // 00000000 00000000 00000000 00000000 // LLllllll KKKKkkkk JJJJJJjj IIiiiiii // HHHHhhhh GGGGGGgg FFffffff EEEEeeee // DDDDDDdd CCcccccc BBBBbbbb AAAAAAaa // Pack lanes: return _mm256_permutevar8x32_epi32(out, _mm256_setr_epi32(0, 1, 2, 4, 5, 6, -1, -1)); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx2/enc_loop.c0000644000175100017510000000436515200142331017175 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE void enc_loop_avx2_inner_first (const uint8_t **s, uint8_t **o) { // First load is done at s - 0 to not get a segfault: __m256i src = _mm256_loadu_si256((__m256i *) *s); // Shift by 4 bytes, as required by enc_reshuffle: src = _mm256_permutevar8x32_epi32(src, _mm256_setr_epi32(0, 0, 1, 2, 3, 4, 5, 6)); // Reshuffle, translate, store: src = enc_reshuffle(src); src = enc_translate(src); _mm256_storeu_si256((__m256i *) *o, src); // Subsequent loads will be done at s - 4, set pointer for next round: *s += 20; *o += 32; } static BASE64_FORCE_INLINE void enc_loop_avx2_inner (const uint8_t **s, uint8_t **o) { // Load input: __m256i src = _mm256_loadu_si256((__m256i *) *s); // Reshuffle, translate, store: src = enc_reshuffle(src); src = enc_translate(src); _mm256_storeu_si256((__m256i *) *o, src); *s += 24; *o += 32; } static inline void enc_loop_avx2 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 32) { return; } // Process blocks of 24 bytes at a time. Because blocks are loaded 32 // bytes at a time an offset of -4, ensure that there will be at least // 4 remaining bytes after the last round, so that the final read will // not pass beyond the bounds of the input buffer: size_t rounds = (*slen - 4) / 24; *slen -= rounds * 24; // 24 bytes consumed per round *olen += rounds * 32; // 32 bytes produced per round // The first loop iteration requires special handling to ensure that // the read, which is done at an offset, does not underflow the buffer: enc_loop_avx2_inner_first(s, o); rounds--; while (rounds > 0) { if (rounds >= 8) { enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); rounds -= 8; continue; } if (rounds >= 4) { enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); rounds -= 4; continue; } if (rounds >= 2) { enc_loop_avx2_inner(s, o); enc_loop_avx2_inner(s, o); rounds -= 2; continue; } enc_loop_avx2_inner(s, o); break; } // Add the offset back: *s += 4; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx2/enc_loop_asm.c0000644000175100017510000002432515200142331020033 0ustar00runnerrunner// Apologies in advance for combining the preprocessor with inline assembly, // two notoriously gnarly parts of C, but it was necessary to avoid a lot of // code repetition. The preprocessor is used to template large sections of // inline assembly that differ only in the registers used. If the code was // written out by hand, it would become very large and hard to audit. // Generate a block of inline assembly that loads register R0 from memory. The // offset at which the register is loaded is set by the given round and a // constant offset. #define LOAD(R0, ROUND, OFFSET) \ "vlddqu ("#ROUND" * 24 + "#OFFSET")(%[src]), %["R0"] \n\t" // Generate a block of inline assembly that deinterleaves and shuffles register // R0 using preloaded constants. Outputs in R0 and R1. #define SHUF(R0, R1, R2) \ "vpshufb %[lut0], %["R0"], %["R1"] \n\t" \ "vpand %["R1"], %[msk0], %["R2"] \n\t" \ "vpand %["R1"], %[msk2], %["R1"] \n\t" \ "vpmulhuw %["R2"], %[msk1], %["R2"] \n\t" \ "vpmullw %["R1"], %[msk3], %["R1"] \n\t" \ "vpor %["R1"], %["R2"], %["R1"] \n\t" // Generate a block of inline assembly that takes R0 and R1 and translates // their contents to the base64 alphabet, using preloaded constants. #define TRAN(R0, R1, R2) \ "vpsubusb %[n51], %["R1"], %["R0"] \n\t" \ "vpcmpgtb %[n25], %["R1"], %["R2"] \n\t" \ "vpsubb %["R2"], %["R0"], %["R0"] \n\t" \ "vpshufb %["R0"], %[lut1], %["R2"] \n\t" \ "vpaddb %["R1"], %["R2"], %["R0"] \n\t" // Generate a block of inline assembly that stores the given register R0 at an // offset set by the given round. #define STOR(R0, ROUND) \ "vmovdqu %["R0"], ("#ROUND" * 32)(%[dst]) \n\t" // Generate a block of inline assembly that generates a single self-contained // encoder round: fetch the data, process it, and store the result. Then update // the source and destination pointers. #define ROUND() \ LOAD("a", 0, -4) \ SHUF("a", "b", "c") \ TRAN("a", "b", "c") \ STOR("a", 0) \ "add $24, %[src] \n\t" \ "add $32, %[dst] \n\t" // Define a macro that initiates a three-way interleaved encoding round by // preloading registers a, b and c from memory. // The register graph shows which registers are in use during each step, and // is a visual aid for choosing registers for that step. Symbol index: // // + indicates that a register is loaded by that step. // | indicates that a register is in use and must not be touched. // - indicates that a register is decommissioned by that step. // x indicates that a register is used as a temporary by that step. // V indicates that a register is an input or output to the macro. // #define ROUND_3_INIT() /* a b c d e f */ \ LOAD("a", 0, -4) /* + */ \ SHUF("a", "d", "e") /* | + x */ \ LOAD("b", 1, -4) /* | + | */ \ TRAN("a", "d", "e") /* | | - x */ \ LOAD("c", 2, -4) /* V V V */ // Define a macro that translates, shuffles and stores the input registers A, B // and C, and preloads registers D, E and F for the next round. // This macro can be arbitrarily daisy-chained by feeding output registers D, E // and F back into the next round as input registers A, B and C. The macro // carefully interleaves memory operations with data operations for optimal // pipelined performance. #define ROUND_3(ROUND, A,B,C,D,E,F) /* A B C D E F */ \ LOAD(D, (ROUND + 3), -4) /* V V V + */ \ SHUF(B, E, F) /* | | | | + x */ \ STOR(A, (ROUND + 0)) /* - | | | | */ \ TRAN(B, E, F) /* | | | - x */ \ LOAD(E, (ROUND + 4), -4) /* | | | + */ \ SHUF(C, A, F) /* + | | | | x */ \ STOR(B, (ROUND + 1)) /* | - | | | */ \ TRAN(C, A, F) /* - | | | x */ \ LOAD(F, (ROUND + 5), -4) /* | | | + */ \ SHUF(D, A, B) /* + x | | | | */ \ STOR(C, (ROUND + 2)) /* | - | | | */ \ TRAN(D, A, B) /* - x V V V */ // Define a macro that terminates a ROUND_3 macro by taking pre-loaded // registers D, E and F, and translating, shuffling and storing them. #define ROUND_3_END(ROUND, A,B,C,D,E,F) /* A B C D E F */ \ SHUF(E, A, B) /* + x V V V */ \ STOR(D, (ROUND + 3)) /* | - | | */ \ TRAN(E, A, B) /* - x | | */ \ SHUF(F, C, D) /* + x | | */ \ STOR(E, (ROUND + 4)) /* | - | */ \ TRAN(F, C, D) /* - x | */ \ STOR(F, (ROUND + 5)) /* - */ // Define a type A round. Inputs are a, b, and c, outputs are d, e, and f. #define ROUND_3_A(ROUND) \ ROUND_3(ROUND, "a", "b", "c", "d", "e", "f") // Define a type B round. Inputs and outputs are swapped with regard to type A. #define ROUND_3_B(ROUND) \ ROUND_3(ROUND, "d", "e", "f", "a", "b", "c") // Terminating macro for a type A round. #define ROUND_3_A_LAST(ROUND) \ ROUND_3_A(ROUND) \ ROUND_3_END(ROUND, "a", "b", "c", "d", "e", "f") // Terminating macro for a type B round. #define ROUND_3_B_LAST(ROUND) \ ROUND_3_B(ROUND) \ ROUND_3_END(ROUND, "d", "e", "f", "a", "b", "c") // Suppress clang's warning that the literal string in the asm statement is // overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99 // compilers). It may be true, but the goal here is not C99 portability. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverlength-strings" static inline void enc_loop_avx2 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { // For a clearer explanation of the algorithm used by this function, // please refer to the plain (not inline assembly) implementation. This // function follows the same basic logic. if (*slen < 32) { return; } // Process blocks of 24 bytes at a time. Because blocks are loaded 32 // bytes at a time an offset of -4, ensure that there will be at least // 4 remaining bytes after the last round, so that the final read will // not pass beyond the bounds of the input buffer. size_t rounds = (*slen - 4) / 24; *slen -= rounds * 24; // 24 bytes consumed per round *olen += rounds * 32; // 32 bytes produced per round // Pre-decrement the number of rounds to get the number of rounds // *after* the first round, which is handled as a special case. rounds--; // Number of times to go through the 36x loop. size_t loops = rounds / 36; // Number of rounds remaining after the 36x loop. rounds %= 36; // Lookup tables. const __m256i lut0 = _mm256_set_epi8( 10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1, 14, 15, 13, 14, 11, 12, 10, 11, 8, 9, 7, 8, 5, 6, 4, 5); const __m256i lut1 = _mm256_setr_epi8( 65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0, 65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0); // Temporary registers. __m256i a, b, c, d, e; // Temporary register f doubles as the shift mask for the first round. __m256i f = _mm256_setr_epi32(0, 0, 1, 2, 3, 4, 5, 6); __asm__ volatile ( // The first loop iteration requires special handling to ensure // that the read, which is normally done at an offset of -4, // does not underflow the buffer. Load the buffer at an offset // of 0 and permute the input to achieve the same effect. LOAD("a", 0, 0) "vpermd %[a], %[f], %[a] \n\t" // Perform the standard shuffling and translation steps. SHUF("a", "b", "c") TRAN("a", "b", "c") // Store the result and increment the source and dest pointers. "vmovdqu %[a], (%[dst]) \n\t" "add $24, %[src] \n\t" "add $32, %[dst] \n\t" // If there are 36 rounds or more, enter a 36x unrolled loop of // interleaved encoding rounds. The rounds interleave memory // operations (load/store) with data operations (table lookups, // etc) to maximize pipeline throughput. " test %[loops], %[loops] \n\t" " jz 18f \n\t" " jmp 36f \n\t" " \n\t" ".balign 64 \n\t" "36: " ROUND_3_INIT() " " ROUND_3_A( 0) " " ROUND_3_B( 3) " " ROUND_3_A( 6) " " ROUND_3_B( 9) " " ROUND_3_A(12) " " ROUND_3_B(15) " " ROUND_3_A(18) " " ROUND_3_B(21) " " ROUND_3_A(24) " " ROUND_3_B(27) " " ROUND_3_A_LAST(30) " add $(24 * 36), %[src] \n\t" " add $(32 * 36), %[dst] \n\t" " dec %[loops] \n\t" " jnz 36b \n\t" // Enter an 18x unrolled loop for rounds of 18 or more. "18: cmp $18, %[rounds] \n\t" " jl 9f \n\t" " " ROUND_3_INIT() " " ROUND_3_A(0) " " ROUND_3_B(3) " " ROUND_3_A(6) " " ROUND_3_B(9) " " ROUND_3_A_LAST(12) " sub $18, %[rounds] \n\t" " add $(24 * 18), %[src] \n\t" " add $(32 * 18), %[dst] \n\t" // Enter a 9x unrolled loop for rounds of 9 or more. "9: cmp $9, %[rounds] \n\t" " jl 6f \n\t" " " ROUND_3_INIT() " " ROUND_3_A(0) " " ROUND_3_B_LAST(3) " sub $9, %[rounds] \n\t" " add $(24 * 9), %[src] \n\t" " add $(32 * 9), %[dst] \n\t" // Enter a 6x unrolled loop for rounds of 6 or more. "6: cmp $6, %[rounds] \n\t" " jl 55f \n\t" " " ROUND_3_INIT() " " ROUND_3_A_LAST(0) " sub $6, %[rounds] \n\t" " add $(24 * 6), %[src] \n\t" " add $(32 * 6), %[dst] \n\t" // Dispatch the remaining rounds 0..5. "55: cmp $3, %[rounds] \n\t" " jg 45f \n\t" " je 3f \n\t" " cmp $1, %[rounds] \n\t" " jg 2f \n\t" " je 1f \n\t" " jmp 0f \n\t" "45: cmp $4, %[rounds] \n\t" " je 4f \n\t" // Block of non-interlaced encoding rounds, which can each // individually be jumped to. Rounds fall through to the next. "5: " ROUND() "4: " ROUND() "3: " ROUND() "2: " ROUND() "1: " ROUND() "0: \n\t" // Outputs (modified). : [rounds] "+r" (rounds), [loops] "+r" (loops), [src] "+r" (*s), [dst] "+r" (*o), [a] "=&x" (a), [b] "=&x" (b), [c] "=&x" (c), [d] "=&x" (d), [e] "=&x" (e), [f] "+x" (f) // Inputs (not modified). : [lut0] "x" (lut0), [lut1] "x" (lut1), [msk0] "x" (_mm256_set1_epi32(0x0FC0FC00)), [msk1] "x" (_mm256_set1_epi32(0x04000040)), [msk2] "x" (_mm256_set1_epi32(0x003F03F0)), [msk3] "x" (_mm256_set1_epi32(0x01000010)), [n51] "x" (_mm256_set1_epi8(51)), [n25] "x" (_mm256_set1_epi8(25)) // Clobbers. : "cc", "memory" ); } #pragma GCC diagnostic pop ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx2/enc_reshuffle.c0000644000175100017510000000523215200142331020201 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE __m256i enc_reshuffle (const __m256i input) { // Translation of the SSSE3 reshuffling algorithm to AVX2. This one // works with shifted (4 bytes) input in order to be able to work // efficiently in the two 128-bit lanes. // Input, bytes MSB to LSB: // 0 0 0 0 x w v u t s r q p o n m // l k j i h g f e d c b a 0 0 0 0 const __m256i in = _mm256_shuffle_epi8(input, _mm256_set_epi8( 10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1, 14, 15, 13, 14, 11, 12, 10, 11, 8, 9, 7, 8, 5, 6, 4, 5)); // in, bytes MSB to LSB: // w x v w // t u s t // q r p q // n o m n // k l j k // h i g h // e f d e // b c a b const __m256i t0 = _mm256_and_si256(in, _mm256_set1_epi32(0x0FC0FC00)); // bits, upper case are most significant bits, lower case are least // significant bits. // 0000wwww XX000000 VVVVVV00 00000000 // 0000tttt UU000000 SSSSSS00 00000000 // 0000qqqq RR000000 PPPPPP00 00000000 // 0000nnnn OO000000 MMMMMM00 00000000 // 0000kkkk LL000000 JJJJJJ00 00000000 // 0000hhhh II000000 GGGGGG00 00000000 // 0000eeee FF000000 DDDDDD00 00000000 // 0000bbbb CC000000 AAAAAA00 00000000 const __m256i t1 = _mm256_mulhi_epu16(t0, _mm256_set1_epi32(0x04000040)); // 00000000 00wwwwXX 00000000 00VVVVVV // 00000000 00ttttUU 00000000 00SSSSSS // 00000000 00qqqqRR 00000000 00PPPPPP // 00000000 00nnnnOO 00000000 00MMMMMM // 00000000 00kkkkLL 00000000 00JJJJJJ // 00000000 00hhhhII 00000000 00GGGGGG // 00000000 00eeeeFF 00000000 00DDDDDD // 00000000 00bbbbCC 00000000 00AAAAAA const __m256i t2 = _mm256_and_si256(in, _mm256_set1_epi32(0x003F03F0)); // 00000000 00xxxxxx 000000vv WWWW0000 // 00000000 00uuuuuu 000000ss TTTT0000 // 00000000 00rrrrrr 000000pp QQQQ0000 // 00000000 00oooooo 000000mm NNNN0000 // 00000000 00llllll 000000jj KKKK0000 // 00000000 00iiiiii 000000gg HHHH0000 // 00000000 00ffffff 000000dd EEEE0000 // 00000000 00cccccc 000000aa BBBB0000 const __m256i t3 = _mm256_mullo_epi16(t2, _mm256_set1_epi32(0x01000010)); // 00xxxxxx 00000000 00vvWWWW 00000000 // 00uuuuuu 00000000 00ssTTTT 00000000 // 00rrrrrr 00000000 00ppQQQQ 00000000 // 00oooooo 00000000 00mmNNNN 00000000 // 00llllll 00000000 00jjKKKK 00000000 // 00iiiiii 00000000 00ggHHHH 00000000 // 00ffffff 00000000 00ddEEEE 00000000 // 00cccccc 00000000 00aaBBBB 00000000 return _mm256_or_si256(t1, t3); // 00xxxxxx 00wwwwXX 00vvWWWW 00VVVVVV // 00uuuuuu 00ttttUU 00ssTTTT 00SSSSSS // 00rrrrrr 00qqqqRR 00ppQQQQ 00PPPPPP // 00oooooo 00nnnnOO 00mmNNNN 00MMMMMM // 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ // 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG // 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD // 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx2/enc_translate.c0000644000175100017510000000234315200142331020213 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE __m256i enc_translate (const __m256i in) { // A lookup table containing the absolute offsets for all ranges: const __m256i lut = _mm256_setr_epi8( 65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0, 65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0); // Translate values 0..63 to the Base64 alphabet. There are five sets: // # From To Abs Index Characters // 0 [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ // 1 [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz // 2 [52..61] [48..57] -4 [2..11] 0123456789 // 3 [62] [43] -19 12 + // 4 [63] [47] -16 13 / // Create LUT indices from the input. The index for range #0 is right, // others are 1 less than expected: __m256i indices = _mm256_subs_epu8(in, _mm256_set1_epi8(51)); // mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0: const __m256i mask = _mm256_cmpgt_epi8(in, _mm256_set1_epi8(25)); // Subtract -1, so add 1 to indices for range #[1..4]. All indices are // now correct: indices = _mm256_sub_epi8(indices, mask); // Add offsets to input values: return _mm256_add_epi8(in, _mm256_shuffle_epi8(lut, indices)); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8488479 librt-0.11.0/base64/arch/avx512/0000755000175100017510000000000015200142335015375 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx512/codec.c0000644000175100017510000000216315200142331016614 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if HAVE_AVX512 #if defined(__clang__) #pragma clang attribute push (__attribute__((target("avx512vbmi"))), apply_to=function) #else #pragma GCC target("avx512vbmi") #endif #include #include "../avx2/dec_reshuffle.c" #include "../avx2/dec_loop.c" #include "enc_reshuffle_translate.c" #include "enc_loop.c" #endif // HAVE_AVX512 void base64_stream_encode_avx512 BASE64_ENC_PARAMS { #if HAVE_AVX512 #include "../generic/enc_head.c" enc_loop_avx512(&s, &slen, &o, &olen); #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } // Reuse AVX2 decoding. Not supporting AVX512 at present int base64_stream_decode_avx512 BASE64_DEC_PARAMS { #if HAVE_AVX512 #include "../generic/dec_head.c" dec_loop_avx2(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #if defined(__clang__) #pragma clang attribute pop #endif #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx512/enc_loop.c0000644000175100017510000000274215200142331017340 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE void enc_loop_avx512_inner (const uint8_t **s, uint8_t **o) { // Load input. __m512i src = _mm512_loadu_si512((__m512i *) *s); // Reshuffle, translate, store. src = enc_reshuffle_translate(src); _mm512_storeu_si512((__m512i *) *o, src); *s += 48; *o += 64; } static inline void enc_loop_avx512 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 64) { return; } // Process blocks of 48 bytes at a time. Because blocks are loaded 64 // bytes at a time, ensure that there will be at least 24 remaining // bytes after the last round, so that the final read will not pass // beyond the bounds of the input buffer. size_t rounds = (*slen - 24) / 48; *slen -= rounds * 48; // 48 bytes consumed per round *olen += rounds * 64; // 64 bytes produced per round while (rounds > 0) { if (rounds >= 8) { enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); rounds -= 8; continue; } if (rounds >= 4) { enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); rounds -= 4; continue; } if (rounds >= 2) { enc_loop_avx512_inner(s, o); enc_loop_avx512_inner(s, o); rounds -= 2; continue; } enc_loop_avx512_inner(s, o); break; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/avx512/enc_reshuffle_translate.c0000644000175100017510000000434515200142331022430 0ustar00runnerrunner// AVX512 algorithm is based on permutevar and multishift. The code is based on // https://github.com/WojciechMula/base64simd which is under BSD-2 license. static BASE64_FORCE_INLINE __m512i enc_reshuffle_translate (const __m512i input) { // 32-bit input // [ 0 0 0 0 0 0 0 0|c1 c0 d5 d4 d3 d2 d1 d0| // b3 b2 b1 b0 c5 c4 c3 c2|a5 a4 a3 a2 a1 a0 b5 b4] // output order [1, 2, 0, 1] // [b3 b2 b1 b0 c5 c4 c3 c2|c1 c0 d5 d4 d3 d2 d1 d0| // a5 a4 a3 a2 a1 a0 b5 b4|b3 b2 b1 b0 c3 c2 c1 c0] const __m512i shuffle_input = _mm512_setr_epi32(0x01020001, 0x04050304, 0x07080607, 0x0a0b090a, 0x0d0e0c0d, 0x10110f10, 0x13141213, 0x16171516, 0x191a1819, 0x1c1d1b1c, 0x1f201e1f, 0x22232122, 0x25262425, 0x28292728, 0x2b2c2a2b, 0x2e2f2d2e); // Reorder bytes // [b3 b2 b1 b0 c5 c4 c3 c2|c1 c0 d5 d4 d3 d2 d1 d0| // a5 a4 a3 a2 a1 a0 b5 b4|b3 b2 b1 b0 c3 c2 c1 c0] const __m512i in = _mm512_permutexvar_epi8(shuffle_input, input); // After multishift a single 32-bit lane has following layout // [c1 c0 d5 d4 d3 d2 d1 d0|b1 b0 c5 c4 c3 c2 c1 c0| // a1 a0 b5 b4 b3 b2 b1 b0|d1 d0 a5 a4 a3 a2 a1 a0] // (a = [10:17], b = [4:11], c = [22:27], d = [16:21]) // 48, 54, 36, 42, 16, 22, 4, 10 const __m512i shifts = _mm512_set1_epi64(0x3036242a1016040alu); __m512i shuffled_in = _mm512_multishift_epi64_epi8(shifts, in); // Translate immediately after reshuffled. const __m512i lookup = _mm512_loadu_si512(base64_table_enc_6bit); // Translation 6-bit values to ASCII. return _mm512_permutexvar_epi8(shuffled_in, lookup); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8497574 librt-0.11.0/base64/arch/generic/0000755000175100017510000000000015200142335015763 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1778435292.850133 librt-0.11.0/base64/arch/generic/32/0000755000175100017510000000000015200142335016207 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/32/dec_loop.c0000644000175100017510000000425215200142331020136 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE int dec_loop_generic_32_inner (const uint8_t **s, uint8_t **o, size_t *rounds) { const uint32_t str = base64_table_dec_32bit_d0[(*s)[0]] | base64_table_dec_32bit_d1[(*s)[1]] | base64_table_dec_32bit_d2[(*s)[2]] | base64_table_dec_32bit_d3[(*s)[3]]; #if BASE64_LITTLE_ENDIAN // LUTs for little-endian set MSB in case of invalid character: if (str & UINT32_C(0x80000000)) { return 0; } #else // LUTs for big-endian set LSB in case of invalid character: if (str & UINT32_C(1)) { return 0; } #endif // Store the output: memcpy(*o, &str, sizeof (str)); *s += 4; *o += 3; *rounds -= 1; return 1; } static inline void dec_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 8) { return; } // Process blocks of 4 bytes per round. Because one extra zero byte is // written after the output, ensure that there will be at least 4 bytes // of input data left to cover the gap. (Two data bytes and up to two // end-of-string markers.) size_t rounds = (*slen - 4) / 4; *slen -= rounds * 4; // 4 bytes consumed per round *olen += rounds * 3; // 3 bytes produced per round do { if (rounds >= 8) { if (dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 4) { if (dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 2) { if (dec_loop_generic_32_inner(s, o, &rounds) && dec_loop_generic_32_inner(s, o, &rounds)) { continue; } break; } dec_loop_generic_32_inner(s, o, &rounds); break; } while (rounds > 0); // Adjust for any rounds that were skipped: *slen += rounds * 4; *olen -= rounds * 3; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/32/enc_loop.c0000644000175100017510000000361415200142331020151 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE void enc_loop_generic_32_inner (const uint8_t **s, uint8_t **o) { uint32_t src; // Load input: memcpy(&src, *s, sizeof (src)); // Reorder to 32-bit big-endian, if not already in that format. The // workset must be in big-endian, otherwise the shifted bits do not // carry over properly among adjacent bytes: src = BASE64_HTOBE32(src); // Two indices for the 12-bit lookup table: const size_t index0 = (src >> 20) & 0xFFFU; const size_t index1 = (src >> 8) & 0xFFFU; // Table lookup and store: memcpy(*o + 0, base64_table_enc_12bit + index0, 2); memcpy(*o + 2, base64_table_enc_12bit + index1, 2); *s += 3; *o += 4; } static inline void enc_loop_generic_32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 4) { return; } // Process blocks of 3 bytes at a time. Because blocks are loaded 4 // bytes at a time, ensure that there will be at least one remaining // byte after the last round, so that the final read will not pass // beyond the bounds of the input buffer: size_t rounds = (*slen - 1) / 3; *slen -= rounds * 3; // 3 bytes consumed per round *olen += rounds * 4; // 4 bytes produced per round do { if (rounds >= 8) { enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); rounds -= 8; continue; } if (rounds >= 4) { enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); rounds -= 4; continue; } if (rounds >= 2) { enc_loop_generic_32_inner(s, o); enc_loop_generic_32_inner(s, o); rounds -= 2; continue; } enc_loop_generic_32_inner(s, o); break; } while (rounds > 0); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8503094 librt-0.11.0/base64/arch/generic/64/0000755000175100017510000000000015200142335016214 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/64/enc_loop.c0000644000175100017510000000412015200142331020147 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE void enc_loop_generic_64_inner (const uint8_t **s, uint8_t **o) { uint64_t src; // Load input: memcpy(&src, *s, sizeof (src)); // Reorder to 64-bit big-endian, if not already in that format. The // workset must be in big-endian, otherwise the shifted bits do not // carry over properly among adjacent bytes: src = BASE64_HTOBE64(src); // Four indices for the 12-bit lookup table: const size_t index0 = (src >> 52) & 0xFFFU; const size_t index1 = (src >> 40) & 0xFFFU; const size_t index2 = (src >> 28) & 0xFFFU; const size_t index3 = (src >> 16) & 0xFFFU; // Table lookup and store: memcpy(*o + 0, base64_table_enc_12bit + index0, 2); memcpy(*o + 2, base64_table_enc_12bit + index1, 2); memcpy(*o + 4, base64_table_enc_12bit + index2, 2); memcpy(*o + 6, base64_table_enc_12bit + index3, 2); *s += 6; *o += 8; } static inline void enc_loop_generic_64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 8) { return; } // Process blocks of 6 bytes at a time. Because blocks are loaded 8 // bytes at a time, ensure that there will be at least 2 remaining // bytes after the last round, so that the final read will not pass // beyond the bounds of the input buffer: size_t rounds = (*slen - 2) / 6; *slen -= rounds * 6; // 6 bytes consumed per round *olen += rounds * 8; // 8 bytes produced per round do { if (rounds >= 8) { enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); rounds -= 8; continue; } if (rounds >= 4) { enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); rounds -= 4; continue; } if (rounds >= 2) { enc_loop_generic_64_inner(s, o); enc_loop_generic_64_inner(s, o); rounds -= 2; continue; } enc_loop_generic_64_inner(s, o); break; } while (rounds > 0); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/codec.c0000644000175100017510000000142615200142331017203 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if BASE64_WORDSIZE == 32 # include "32/enc_loop.c" #elif BASE64_WORDSIZE == 64 # include "64/enc_loop.c" #endif #if BASE64_WORDSIZE >= 32 # include "32/dec_loop.c" #endif void base64_stream_encode_plain BASE64_ENC_PARAMS { #include "enc_head.c" #if BASE64_WORDSIZE == 32 enc_loop_generic_32(&s, &slen, &o, &olen); #elif BASE64_WORDSIZE == 64 enc_loop_generic_64(&s, &slen, &o, &olen); #endif #include "enc_tail.c" } int base64_stream_decode_plain BASE64_DEC_PARAMS { #include "dec_head.c" #if BASE64_WORDSIZE >= 32 dec_loop_generic_32(&s, &slen, &o, &olen); #endif #include "dec_tail.c" } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/dec_head.c0000644000175100017510000000142715200142331017643 0ustar00runnerrunnerint ret = 0; const uint8_t *s = (const uint8_t *) src; uint8_t *o = (uint8_t *) out; uint8_t q; // Use local temporaries to avoid cache thrashing: size_t olen = 0; size_t slen = srclen; struct base64_state st; st.eof = state->eof; st.bytes = state->bytes; st.carry = state->carry; // If we previously saw an EOF or an invalid character, bail out: if (st.eof) { *outlen = 0; ret = 0; // If there was a trailing '=' to check, check it: if (slen && (st.eof == BASE64_AEOF)) { state->bytes = 0; state->eof = BASE64_EOF; ret = ((base64_table_dec_8bit[*s++] == 254) && (slen == 1)) ? 1 : 0; } return ret; } // Turn four 6-bit numbers into three bytes: // out[0] = 11111122 // out[1] = 22223333 // out[2] = 33444444 // Duff's device again: switch (st.bytes) { for (;;) { case 0: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/dec_tail.c0000644000175100017510000000335615200142331017676 0ustar00runnerrunner if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.eof = BASE64_EOF; // Treat character '=' as invalid for byte 0: break; } st.carry = q << 2; st.bytes++; // Deliberate fallthrough: BASE64_FALLTHROUGH case 1: if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.eof = BASE64_EOF; // Treat character '=' as invalid for byte 1: break; } *o++ = st.carry | (q >> 4); st.carry = q << 4; st.bytes++; olen++; // Deliberate fallthrough: BASE64_FALLTHROUGH case 2: if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.bytes++; // When q == 254, the input char is '='. // Check if next byte is also '=': if (q == 254) { if (slen-- != 0) { st.bytes = 0; // EOF: st.eof = BASE64_EOF; q = base64_table_dec_8bit[*s++]; ret = ((q == 254) && (slen == 0)) ? 1 : 0; break; } else { // Almost EOF st.eof = BASE64_AEOF; ret = 1; break; } } // If we get here, there was an error: break; } *o++ = st.carry | (q >> 2); st.carry = q << 6; st.bytes++; olen++; // Deliberate fallthrough: BASE64_FALLTHROUGH case 3: if (slen-- == 0) { ret = 1; break; } if ((q = base64_table_dec_8bit[*s++]) >= 254) { st.bytes = 0; st.eof = BASE64_EOF; // When q == 254, the input char is '='. Return 1 and EOF. // When q == 255, the input char is invalid. Return 0 and EOF. ret = ((q == 254) && (slen == 0)) ? 1 : 0; break; } *o++ = st.carry | q; st.carry = 0; st.bytes = 0; olen++; } } state->eof = st.eof; state->bytes = st.bytes; state->carry = st.carry; *outlen = olen; return ret; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/enc_head.c0000644000175100017510000000111115200142331017643 0ustar00runnerrunner// Assume that *out is large enough to contain the output. // Theoretically it should be 4/3 the length of src. const uint8_t *s = (const uint8_t *) src; uint8_t *o = (uint8_t *) out; // Use local temporaries to avoid cache thrashing: size_t olen = 0; size_t slen = srclen; struct base64_state st; st.bytes = state->bytes; st.carry = state->carry; // Turn three bytes into four 6-bit numbers: // in[0] = 00111111 // in[1] = 00112222 // in[2] = 00222233 // in[3] = 00333333 // Duff's device, a for() loop inside a switch() statement. Legal! switch (st.bytes) { for (;;) { case 0: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/generic/enc_tail.c0000644000175100017510000000117515200142331017705 0ustar00runnerrunner if (slen-- == 0) { break; } *o++ = base64_table_enc_6bit[*s >> 2]; st.carry = (*s++ << 4) & 0x30; st.bytes++; olen += 1; // Deliberate fallthrough: BASE64_FALLTHROUGH case 1: if (slen-- == 0) { break; } *o++ = base64_table_enc_6bit[st.carry | (*s >> 4)]; st.carry = (*s++ << 2) & 0x3C; st.bytes++; olen += 1; // Deliberate fallthrough: BASE64_FALLTHROUGH case 2: if (slen-- == 0) { break; } *o++ = base64_table_enc_6bit[st.carry | (*s >> 6)]; *o++ = base64_table_enc_6bit[*s++ & 0x3F]; st.bytes = 0; olen += 2; } } state->bytes = st.bytes; state->carry = st.carry; *outlen = olen; ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8512292 librt-0.11.0/base64/arch/neon32/0000755000175100017510000000000015200142335015453 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon32/codec.c0000644000175100017510000000370015200142331016670 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #ifdef __arm__ # if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && HAVE_NEON32 # define BASE64_USE_NEON32 # endif #endif #ifdef BASE64_USE_NEON32 #include // Only enable inline assembly on supported compilers. #if defined(__GNUC__) || defined(__clang__) #define BASE64_NEON32_USE_ASM #endif static BASE64_FORCE_INLINE uint8x16_t vqtbl1q_u8 (const uint8x16_t lut, const uint8x16_t indices) { // NEON32 only supports 64-bit wide lookups in 128-bit tables. Emulate // the NEON64 `vqtbl1q_u8` intrinsic to do 128-bit wide lookups. uint8x8x2_t lut2; uint8x8x2_t result; lut2.val[0] = vget_low_u8(lut); lut2.val[1] = vget_high_u8(lut); result.val[0] = vtbl2_u8(lut2, vget_low_u8(indices)); result.val[1] = vtbl2_u8(lut2, vget_high_u8(indices)); return vcombine_u8(result.val[0], result.val[1]); } #include "../generic/32/dec_loop.c" #include "../generic/32/enc_loop.c" #include "dec_loop.c" #include "enc_reshuffle.c" #include "enc_translate.c" #include "enc_loop.c" #endif // BASE64_USE_NEON32 // Stride size is so large on these NEON 32-bit functions // (48 bytes encode, 32 bytes decode) that we inline the // uint32 codec to stay performant on smaller inputs. void base64_stream_encode_neon32 BASE64_ENC_PARAMS { #ifdef BASE64_USE_NEON32 #include "../generic/enc_head.c" enc_loop_neon32(&s, &slen, &o, &olen); enc_loop_generic_32(&s, &slen, &o, &olen); #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } int base64_stream_decode_neon32 BASE64_DEC_PARAMS { #ifdef BASE64_USE_NEON32 #include "../generic/dec_head.c" dec_loop_neon32(&s, &slen, &o, &olen); dec_loop_generic_32(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon32/dec_loop.c0000644000175100017510000000553215200142331017404 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE int is_nonzero (const uint8x16_t v) { uint64_t u64; const uint64x2_t v64 = vreinterpretq_u64_u8(v); const uint32x2_t v32 = vqmovn_u64(v64); vst1_u64(&u64, vreinterpret_u64_u32(v32)); return u64 != 0; } static BASE64_FORCE_INLINE uint8x16_t delta_lookup (const uint8x16_t v) { const uint8x8_t lut = { 0, 16, 19, 4, (uint8_t) -65, (uint8_t) -65, (uint8_t) -71, (uint8_t) -71, }; return vcombine_u8( vtbl1_u8(lut, vget_low_u8(v)), vtbl1_u8(lut, vget_high_u8(v))); } static BASE64_FORCE_INLINE uint8x16_t dec_loop_neon32_lane (uint8x16_t *lane) { // See the SSSE3 decoder for an explanation of the algorithm. const uint8x16_t lut_lo = { 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A }; const uint8x16_t lut_hi = { 0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10 }; const uint8x16_t mask_0F = vdupq_n_u8(0x0F); const uint8x16_t mask_2F = vdupq_n_u8(0x2F); const uint8x16_t hi_nibbles = vshrq_n_u8(*lane, 4); const uint8x16_t lo_nibbles = vandq_u8(*lane, mask_0F); const uint8x16_t eq_2F = vceqq_u8(*lane, mask_2F); const uint8x16_t hi = vqtbl1q_u8(lut_hi, hi_nibbles); const uint8x16_t lo = vqtbl1q_u8(lut_lo, lo_nibbles); // Now simply add the delta values to the input: *lane = vaddq_u8(*lane, delta_lookup(vaddq_u8(eq_2F, hi_nibbles))); // Return the validity mask: return vandq_u8(lo, hi); } static inline void dec_loop_neon32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 64) { return; } // Process blocks of 64 bytes per round. Unlike the SSE codecs, no // extra trailing zero bytes are written, so it is not necessary to // reserve extra input bytes: size_t rounds = *slen / 64; *slen -= rounds * 64; // 64 bytes consumed per round *olen += rounds * 48; // 48 bytes produced per round do { uint8x16x3_t dec; // Load 64 bytes and deinterleave: uint8x16x4_t str = vld4q_u8(*s); // Decode each lane, collect a mask of invalid inputs: const uint8x16_t classified = dec_loop_neon32_lane(&str.val[0]) | dec_loop_neon32_lane(&str.val[1]) | dec_loop_neon32_lane(&str.val[2]) | dec_loop_neon32_lane(&str.val[3]); // Check for invalid input: if any of the delta values are // zero, fall back on bytewise code to do error checking and // reporting: if (is_nonzero(classified)) { break; } // Compress four bytes into three: dec.val[0] = vorrq_u8(vshlq_n_u8(str.val[0], 2), vshrq_n_u8(str.val[1], 4)); dec.val[1] = vorrq_u8(vshlq_n_u8(str.val[1], 4), vshrq_n_u8(str.val[2], 2)); dec.val[2] = vorrq_u8(vshlq_n_u8(str.val[2], 6), str.val[3]); // Interleave and store decoded result: vst3q_u8(*o, dec); *s += 64; *o += 48; } while (--rounds > 0); // Adjust for any rounds that were skipped: *slen += rounds * 64; *olen -= rounds * 48; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon32/enc_loop.c0000644000175100017510000001105715200142331017415 0ustar00runnerrunner#ifdef BASE64_NEON32_USE_ASM static BASE64_FORCE_INLINE void enc_loop_neon32_inner_asm (const uint8_t **s, uint8_t **o) { // This function duplicates the functionality of enc_loop_neon32_inner, // but entirely with inline assembly. This gives a significant speedup // over using NEON intrinsics, which do not always generate very good // code. The logic of the assembly is directly lifted from the // intrinsics version, so it can be used as a guide to this code. // Temporary registers, used as scratch space. uint8x16_t tmp0, tmp1, tmp2, tmp3; uint8x16_t mask0, mask1, mask2, mask3; // A lookup table containing the absolute offsets for all ranges. const uint8x16_t lut = { 65U, 71U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 237U, 240U, 0U, 0U }; // Numeric constants. const uint8x16_t n51 = vdupq_n_u8(51); const uint8x16_t n25 = vdupq_n_u8(25); const uint8x16_t n63 = vdupq_n_u8(63); __asm__ ( // Load 48 bytes and deinterleave. The bytes are loaded to // hard-coded registers q12, q13 and q14, to ensure that they // are contiguous. Increment the source pointer. "vld3.8 {d24, d26, d28}, [%[src]]! \n\t" "vld3.8 {d25, d27, d29}, [%[src]]! \n\t" // Reshuffle the bytes using temporaries. "vshr.u8 %q[t0], q12, #2 \n\t" "vshr.u8 %q[t1], q13, #4 \n\t" "vshr.u8 %q[t2], q14, #6 \n\t" "vsli.8 %q[t1], q12, #4 \n\t" "vsli.8 %q[t2], q13, #2 \n\t" "vand.u8 %q[t1], %q[t1], %q[n63] \n\t" "vand.u8 %q[t2], %q[t2], %q[n63] \n\t" "vand.u8 %q[t3], q14, %q[n63] \n\t" // t0..t3 are the reshuffled inputs. Create LUT indices. "vqsub.u8 q12, %q[t0], %q[n51] \n\t" "vqsub.u8 q13, %q[t1], %q[n51] \n\t" "vqsub.u8 q14, %q[t2], %q[n51] \n\t" "vqsub.u8 q15, %q[t3], %q[n51] \n\t" // Create the mask for range #0. "vcgt.u8 %q[m0], %q[t0], %q[n25] \n\t" "vcgt.u8 %q[m1], %q[t1], %q[n25] \n\t" "vcgt.u8 %q[m2], %q[t2], %q[n25] \n\t" "vcgt.u8 %q[m3], %q[t3], %q[n25] \n\t" // Subtract -1 to correct the LUT indices. "vsub.u8 q12, %q[m0] \n\t" "vsub.u8 q13, %q[m1] \n\t" "vsub.u8 q14, %q[m2] \n\t" "vsub.u8 q15, %q[m3] \n\t" // Lookup the delta values. "vtbl.u8 d24, {%q[lut]}, d24 \n\t" "vtbl.u8 d25, {%q[lut]}, d25 \n\t" "vtbl.u8 d26, {%q[lut]}, d26 \n\t" "vtbl.u8 d27, {%q[lut]}, d27 \n\t" "vtbl.u8 d28, {%q[lut]}, d28 \n\t" "vtbl.u8 d29, {%q[lut]}, d29 \n\t" "vtbl.u8 d30, {%q[lut]}, d30 \n\t" "vtbl.u8 d31, {%q[lut]}, d31 \n\t" // Add the delta values. "vadd.u8 q12, %q[t0] \n\t" "vadd.u8 q13, %q[t1] \n\t" "vadd.u8 q14, %q[t2] \n\t" "vadd.u8 q15, %q[t3] \n\t" // Store 64 bytes and interleave. Increment the dest pointer. "vst4.8 {d24, d26, d28, d30}, [%[dst]]! \n\t" "vst4.8 {d25, d27, d29, d31}, [%[dst]]! \n\t" // Outputs (modified). : [src] "+r" (*s), [dst] "+r" (*o), [t0] "=&w" (tmp0), [t1] "=&w" (tmp1), [t2] "=&w" (tmp2), [t3] "=&w" (tmp3), [m0] "=&w" (mask0), [m1] "=&w" (mask1), [m2] "=&w" (mask2), [m3] "=&w" (mask3) // Inputs (not modified). : [lut] "w" (lut), [n25] "w" (n25), [n51] "w" (n51), [n63] "w" (n63) // Clobbers. : "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31", "cc", "memory" ); } #endif static BASE64_FORCE_INLINE void enc_loop_neon32_inner (const uint8_t **s, uint8_t **o) { #ifdef BASE64_NEON32_USE_ASM enc_loop_neon32_inner_asm(s, o); #else // Load 48 bytes and deinterleave: uint8x16x3_t src = vld3q_u8(*s); // Reshuffle: uint8x16x4_t out = enc_reshuffle(src); // Translate reshuffled bytes to the Base64 alphabet: out = enc_translate(out); // Interleave and store output: vst4q_u8(*o, out); *s += 48; *o += 64; #endif } static inline void enc_loop_neon32 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { size_t rounds = *slen / 48; *slen -= rounds * 48; // 48 bytes consumed per round *olen += rounds * 64; // 64 bytes produced per round while (rounds > 0) { if (rounds >= 8) { enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); rounds -= 8; continue; } if (rounds >= 4) { enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); rounds -= 4; continue; } if (rounds >= 2) { enc_loop_neon32_inner(s, o); enc_loop_neon32_inner(s, o); rounds -= 2; continue; } enc_loop_neon32_inner(s, o); break; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon32/enc_reshuffle.c0000644000175100017510000000172615200142331020431 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE uint8x16x4_t enc_reshuffle (uint8x16x3_t in) { uint8x16x4_t out; // Input: // in[0] = a7 a6 a5 a4 a3 a2 a1 a0 // in[1] = b7 b6 b5 b4 b3 b2 b1 b0 // in[2] = c7 c6 c5 c4 c3 c2 c1 c0 // Output: // out[0] = 00 00 a7 a6 a5 a4 a3 a2 // out[1] = 00 00 a1 a0 b7 b6 b5 b4 // out[2] = 00 00 b3 b2 b1 b0 c7 c6 // out[3] = 00 00 c5 c4 c3 c2 c1 c0 // Move the input bits to where they need to be in the outputs. Except // for the first output, the high two bits are not cleared. out.val[0] = vshrq_n_u8(in.val[0], 2); out.val[1] = vshrq_n_u8(in.val[1], 4); out.val[2] = vshrq_n_u8(in.val[2], 6); out.val[1] = vsliq_n_u8(out.val[1], in.val[0], 4); out.val[2] = vsliq_n_u8(out.val[2], in.val[1], 2); // Clear the high two bits in the second, third and fourth output. out.val[1] = vandq_u8(out.val[1], vdupq_n_u8(0x3F)); out.val[2] = vandq_u8(out.val[2], vdupq_n_u8(0x3F)); out.val[3] = vandq_u8(in.val[2], vdupq_n_u8(0x3F)); return out; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon32/enc_translate.c0000644000175100017510000000410415200142331020434 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE uint8x16x4_t enc_translate (const uint8x16x4_t in) { // A lookup table containing the absolute offsets for all ranges: const uint8x16_t lut = { 65U, 71U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 252U, 237U, 240U, 0U, 0U }; const uint8x16_t offset = vdupq_n_u8(51); uint8x16x4_t indices, mask, delta, out; // Translate values 0..63 to the Base64 alphabet. There are five sets: // # From To Abs Index Characters // 0 [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ // 1 [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz // 2 [52..61] [48..57] -4 [2..11] 0123456789 // 3 [62] [43] -19 12 + // 4 [63] [47] -16 13 / // Create LUT indices from input: // the index for range #0 is right, others are 1 less than expected: indices.val[0] = vqsubq_u8(in.val[0], offset); indices.val[1] = vqsubq_u8(in.val[1], offset); indices.val[2] = vqsubq_u8(in.val[2], offset); indices.val[3] = vqsubq_u8(in.val[3], offset); // mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0: mask.val[0] = vcgtq_u8(in.val[0], vdupq_n_u8(25)); mask.val[1] = vcgtq_u8(in.val[1], vdupq_n_u8(25)); mask.val[2] = vcgtq_u8(in.val[2], vdupq_n_u8(25)); mask.val[3] = vcgtq_u8(in.val[3], vdupq_n_u8(25)); // Subtract -1, so add 1 to indices for range #[1..4], All indices are // now correct: indices.val[0] = vsubq_u8(indices.val[0], mask.val[0]); indices.val[1] = vsubq_u8(indices.val[1], mask.val[1]); indices.val[2] = vsubq_u8(indices.val[2], mask.val[2]); indices.val[3] = vsubq_u8(indices.val[3], mask.val[3]); // Lookup delta values: delta.val[0] = vqtbl1q_u8(lut, indices.val[0]); delta.val[1] = vqtbl1q_u8(lut, indices.val[1]); delta.val[2] = vqtbl1q_u8(lut, indices.val[2]); delta.val[3] = vqtbl1q_u8(lut, indices.val[3]); // Add delta values: out.val[0] = vaddq_u8(in.val[0], delta.val[0]); out.val[1] = vaddq_u8(in.val[1], delta.val[1]); out.val[2] = vaddq_u8(in.val[2], delta.val[2]); out.val[3] = vaddq_u8(in.val[3], delta.val[3]); return out; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8521302 librt-0.11.0/base64/arch/neon64/0000755000175100017510000000000015200142335015460 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon64/codec.c0000644000175100017510000000421615200142331016700 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if HAVE_NEON64 #include // Only enable inline assembly on supported compilers. #if !defined(__wasm__) && (defined(__GNUC__) || defined(__clang__)) #define BASE64_NEON64_USE_ASM #endif static BASE64_FORCE_INLINE uint8x16x4_t load_64byte_table (const uint8_t *p) { #ifdef BASE64_NEON64_USE_ASM // Force the table to be loaded into contiguous registers. GCC will not // normally allocate contiguous registers for a `uint8x16x4_t'. These // registers are chosen to not conflict with the ones in the enc loop. register uint8x16_t t0 __asm__ ("v8"); register uint8x16_t t1 __asm__ ("v9"); register uint8x16_t t2 __asm__ ("v10"); register uint8x16_t t3 __asm__ ("v11"); __asm__ ( "ld1 {%[t0].16b, %[t1].16b, %[t2].16b, %[t3].16b}, [%[src]], #64 \n\t" : [src] "+r" (p), [t0] "=w" (t0), [t1] "=w" (t1), [t2] "=w" (t2), [t3] "=w" (t3) ); return (uint8x16x4_t) { .val[0] = t0, .val[1] = t1, .val[2] = t2, .val[3] = t3, }; #else return vld1q_u8_x4(p); #endif } #include "../generic/32/dec_loop.c" #include "../generic/64/enc_loop.c" #include "dec_loop.c" #ifdef BASE64_NEON64_USE_ASM # include "enc_loop_asm.c" #else # include "enc_reshuffle.c" # include "enc_loop.c" #endif #endif // HAVE_NEON64 // Stride size is so large on these NEON 64-bit functions // (48 bytes encode, 64 bytes decode) that we inline the // uint64 codec to stay performant on smaller inputs. void base64_stream_encode_neon64 BASE64_ENC_PARAMS { #if HAVE_NEON64 #include "../generic/enc_head.c" enc_loop_neon64(&s, &slen, &o, &olen); enc_loop_generic_64(&s, &slen, &o, &olen); #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } int base64_stream_decode_neon64 BASE64_DEC_PARAMS { #if HAVE_NEON64 #include "../generic/dec_head.c" dec_loop_neon64(&s, &slen, &o, &olen); dec_loop_generic_32(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon64/dec_loop.c0000644000175100017510000001221715200142331017407 0ustar00runnerrunner// The input consists of five valid character sets in the Base64 alphabet, // which we need to map back to the 6-bit values they represent. // There are three ranges, two singles, and then there's the rest. // // # From To LUT Characters // 1 [0..42] [255] #1 invalid input // 2 [43] [62] #1 + // 3 [44..46] [255] #1 invalid input // 4 [47] [63] #1 / // 5 [48..57] [52..61] #1 0..9 // 6 [58..63] [255] #1 invalid input // 7 [64] [255] #2 invalid input // 8 [65..90] [0..25] #2 A..Z // 9 [91..96] [255] #2 invalid input // 10 [97..122] [26..51] #2 a..z // 11 [123..126] [255] #2 invalid input // (12) Everything else => invalid input // The first LUT will use the VTBL instruction (out of range indices are set to // 0 in destination). static const uint8_t dec_lut1[] = { 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 255U, 62U, 255U, 255U, 255U, 63U, 52U, 53U, 54U, 55U, 56U, 57U, 58U, 59U, 60U, 61U, 255U, 255U, 255U, 255U, 255U, 255U, }; // The second LUT will use the VTBX instruction (out of range indices will be // unchanged in destination). Input [64..126] will be mapped to index [1..63] // in this LUT. Index 0 means that value comes from LUT #1. static const uint8_t dec_lut2[] = { 0U, 255U, 0U, 1U, 2U, 3U, 4U, 5U, 6U, 7U, 8U, 9U, 10U, 11U, 12U, 13U, 14U, 15U, 16U, 17U, 18U, 19U, 20U, 21U, 22U, 23U, 24U, 25U, 255U, 255U, 255U, 255U, 255U, 255U, 26U, 27U, 28U, 29U, 30U, 31U, 32U, 33U, 34U, 35U, 36U, 37U, 38U, 39U, 40U, 41U, 42U, 43U, 44U, 45U, 46U, 47U, 48U, 49U, 50U, 51U, 255U, 255U, 255U, 255U, }; // All input values in range for the first look-up will be 0U in the second // look-up result. All input values out of range for the first look-up will be // 0U in the first look-up result. Thus, the two results can be ORed without // conflicts. // // Invalid characters that are in the valid range for either look-up will be // set to 255U in the combined result. Other invalid characters will just be // passed through with the second look-up result (using the VTBX instruction). // Since the second LUT is 64 bytes, those passed-through values are guaranteed // to have a value greater than 63U. Therefore, valid characters will be mapped // to the valid [0..63] range and all invalid characters will be mapped to // values greater than 63. static inline void dec_loop_neon64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 64) { return; } // Process blocks of 64 bytes per round. Unlike the SSE codecs, no // extra trailing zero bytes are written, so it is not necessary to // reserve extra input bytes: size_t rounds = *slen / 64; *slen -= rounds * 64; // 64 bytes consumed per round *olen += rounds * 48; // 48 bytes produced per round const uint8x16x4_t tbl_dec1 = load_64byte_table(dec_lut1); const uint8x16x4_t tbl_dec2 = load_64byte_table(dec_lut2); do { const uint8x16_t offset = vdupq_n_u8(63U); uint8x16x4_t dec1, dec2; uint8x16x3_t dec; // Load 64 bytes and deinterleave: uint8x16x4_t str = vld4q_u8((uint8_t *) *s); // Get indices for second LUT: dec2.val[0] = vqsubq_u8(str.val[0], offset); dec2.val[1] = vqsubq_u8(str.val[1], offset); dec2.val[2] = vqsubq_u8(str.val[2], offset); dec2.val[3] = vqsubq_u8(str.val[3], offset); // Get values from first LUT: dec1.val[0] = vqtbl4q_u8(tbl_dec1, str.val[0]); dec1.val[1] = vqtbl4q_u8(tbl_dec1, str.val[1]); dec1.val[2] = vqtbl4q_u8(tbl_dec1, str.val[2]); dec1.val[3] = vqtbl4q_u8(tbl_dec1, str.val[3]); // Get values from second LUT: dec2.val[0] = vqtbx4q_u8(dec2.val[0], tbl_dec2, dec2.val[0]); dec2.val[1] = vqtbx4q_u8(dec2.val[1], tbl_dec2, dec2.val[1]); dec2.val[2] = vqtbx4q_u8(dec2.val[2], tbl_dec2, dec2.val[2]); dec2.val[3] = vqtbx4q_u8(dec2.val[3], tbl_dec2, dec2.val[3]); // Get final values: str.val[0] = vorrq_u8(dec1.val[0], dec2.val[0]); str.val[1] = vorrq_u8(dec1.val[1], dec2.val[1]); str.val[2] = vorrq_u8(dec1.val[2], dec2.val[2]); str.val[3] = vorrq_u8(dec1.val[3], dec2.val[3]); // Check for invalid input, any value larger than 63: const uint8x16_t classified = vorrq_u8( vorrq_u8(vcgtq_u8(str.val[0], vdupq_n_u8(63)), vcgtq_u8(str.val[1], vdupq_n_u8(63))), vorrq_u8(vcgtq_u8(str.val[2], vdupq_n_u8(63)), vcgtq_u8(str.val[3], vdupq_n_u8(63))) ); // Check that all bits are zero: if (vmaxvq_u8(classified) != 0U) { break; } // Compress four bytes into three: dec.val[0] = vorrq_u8(vshlq_n_u8(str.val[0], 2), vshrq_n_u8(str.val[1], 4)); dec.val[1] = vorrq_u8(vshlq_n_u8(str.val[1], 4), vshrq_n_u8(str.val[2], 2)); dec.val[2] = vorrq_u8(vshlq_n_u8(str.val[2], 6), str.val[3]); // Interleave and store decoded result: vst3q_u8((uint8_t *) *o, dec); *s += 64; *o += 48; } while (--rounds > 0); // Adjust for any rounds that were skipped: *slen += rounds * 64; *olen -= rounds * 48; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon64/enc_loop.c0000644000175100017510000000350115200142331017415 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE void enc_loop_neon64_inner (const uint8_t **s, uint8_t **o, const uint8x16x4_t tbl_enc) { // Load 48 bytes and deinterleave: uint8x16x3_t src = vld3q_u8(*s); // Divide bits of three input bytes over four output bytes: uint8x16x4_t out = enc_reshuffle(src); // The bits have now been shifted to the right locations; // translate their values 0..63 to the Base64 alphabet. // Use a 64-byte table lookup: out.val[0] = vqtbl4q_u8(tbl_enc, out.val[0]); out.val[1] = vqtbl4q_u8(tbl_enc, out.val[1]); out.val[2] = vqtbl4q_u8(tbl_enc, out.val[2]); out.val[3] = vqtbl4q_u8(tbl_enc, out.val[3]); // Interleave and store output: vst4q_u8(*o, out); *s += 48; *o += 64; } static inline void enc_loop_neon64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { size_t rounds = *slen / 48; *slen -= rounds * 48; // 48 bytes consumed per round *olen += rounds * 64; // 64 bytes produced per round // Load the encoding table: const uint8x16x4_t tbl_enc = load_64byte_table(base64_table_enc_6bit); while (rounds > 0) { if (rounds >= 8) { enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); rounds -= 8; continue; } if (rounds >= 4) { enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); rounds -= 4; continue; } if (rounds >= 2) { enc_loop_neon64_inner(s, o, tbl_enc); enc_loop_neon64_inner(s, o, tbl_enc); rounds -= 2; continue; } enc_loop_neon64_inner(s, o, tbl_enc); break; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon64/enc_loop_asm.c0000644000175100017510000001276115200142331020265 0ustar00runnerrunner// Apologies in advance for combining the preprocessor with inline assembly, // two notoriously gnarly parts of C, but it was necessary to avoid a lot of // code repetition. The preprocessor is used to template large sections of // inline assembly that differ only in the registers used. If the code was // written out by hand, it would become very large and hard to audit. // Generate a block of inline assembly that loads three user-defined registers // A, B, C from memory and deinterleaves them, post-incrementing the src // pointer. The register set should be sequential. #define LOAD(A, B, C) \ "ld3 {"A".16b, "B".16b, "C".16b}, [%[src]], #48 \n\t" // Generate a block of inline assembly that takes three deinterleaved registers // and shuffles the bytes. The output is in temporary registers t0..t3. #define SHUF(A, B, C) \ "ushr %[t0].16b, "A".16b, #2 \n\t" \ "ushr %[t1].16b, "B".16b, #4 \n\t" \ "ushr %[t2].16b, "C".16b, #6 \n\t" \ "sli %[t1].16b, "A".16b, #4 \n\t" \ "sli %[t2].16b, "B".16b, #2 \n\t" \ "and %[t1].16b, %[t1].16b, %[n63].16b \n\t" \ "and %[t2].16b, %[t2].16b, %[n63].16b \n\t" \ "and %[t3].16b, "C".16b, %[n63].16b \n\t" // Generate a block of inline assembly that takes temporary registers t0..t3 // and translates them to the base64 alphabet, using a table loaded into // v8..v11. The output is in user-defined registers A..D. #define TRAN(A, B, C, D) \ "tbl "A".16b, {v8.16b-v11.16b}, %[t0].16b \n\t" \ "tbl "B".16b, {v8.16b-v11.16b}, %[t1].16b \n\t" \ "tbl "C".16b, {v8.16b-v11.16b}, %[t2].16b \n\t" \ "tbl "D".16b, {v8.16b-v11.16b}, %[t3].16b \n\t" // Generate a block of inline assembly that interleaves four registers and // stores them, post-incrementing the destination pointer. #define STOR(A, B, C, D) \ "st4 {"A".16b, "B".16b, "C".16b, "D".16b}, [%[dst]], #64 \n\t" // Generate a block of inline assembly that generates a single self-contained // encoder round: fetch the data, process it, and store the result. #define ROUND() \ LOAD("v12", "v13", "v14") \ SHUF("v12", "v13", "v14") \ TRAN("v12", "v13", "v14", "v15") \ STOR("v12", "v13", "v14", "v15") // Generate a block of assembly that generates a type A interleaved encoder // round. It uses registers that were loaded by the previous type B round, and // in turn loads registers for the next type B round. #define ROUND_A() \ SHUF("v2", "v3", "v4") \ LOAD("v12", "v13", "v14") \ TRAN("v2", "v3", "v4", "v5") \ STOR("v2", "v3", "v4", "v5") // Type B interleaved encoder round. Same as type A, but register sets swapped. #define ROUND_B() \ SHUF("v12", "v13", "v14") \ LOAD("v2", "v3", "v4") \ TRAN("v12", "v13", "v14", "v15") \ STOR("v12", "v13", "v14", "v15") // The first type A round needs to load its own registers. #define ROUND_A_FIRST() \ LOAD("v2", "v3", "v4") \ ROUND_A() // The last type B round omits the load for the next step. #define ROUND_B_LAST() \ SHUF("v12", "v13", "v14") \ TRAN("v12", "v13", "v14", "v15") \ STOR("v12", "v13", "v14", "v15") // Suppress clang's warning that the literal string in the asm statement is // overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99 // compilers). It may be true, but the goal here is not C99 portability. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverlength-strings" static inline void enc_loop_neon64 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { size_t rounds = *slen / 48; if (rounds == 0) { return; } *slen -= rounds * 48; // 48 bytes consumed per round. *olen += rounds * 64; // 64 bytes produced per round. // Number of times to go through the 8x loop. size_t loops = rounds / 8; // Number of rounds remaining after the 8x loop. rounds %= 8; // Temporary registers, used as scratch space. uint8x16_t tmp0, tmp1, tmp2, tmp3; __asm__ volatile ( // Load the encoding table into v8..v11. " ld1 {v8.16b-v11.16b}, [%[tbl]] \n\t" // If there are eight rounds or more, enter an 8x unrolled loop // of interleaved encoding rounds. The rounds interleave memory // operations (load/store) with data operations to maximize // pipeline throughput. " cbz %[loops], 4f \n\t" // The SIMD instructions do not touch the flags. "88: subs %[loops], %[loops], #1 \n\t" " " ROUND_A_FIRST() " " ROUND_B() " " ROUND_A() " " ROUND_B() " " ROUND_A() " " ROUND_B() " " ROUND_A() " " ROUND_B_LAST() " b.ne 88b \n\t" // Enter a 4x unrolled loop for rounds of 4 or more. "4: cmp %[rounds], #4 \n\t" " b.lt 30f \n\t" " " ROUND_A_FIRST() " " ROUND_B() " " ROUND_A() " " ROUND_B_LAST() " sub %[rounds], %[rounds], #4 \n\t" // Dispatch the remaining rounds 0..3. "30: cbz %[rounds], 0f \n\t" " cmp %[rounds], #2 \n\t" " b.eq 2f \n\t" " b.lt 1f \n\t" // Block of non-interlaced encoding rounds, which can each // individually be jumped to. Rounds fall through to the next. "3: " ROUND() "2: " ROUND() "1: " ROUND() "0: \n\t" // Outputs (modified). : [loops] "+r" (loops), [src] "+r" (*s), [dst] "+r" (*o), [t0] "=&w" (tmp0), [t1] "=&w" (tmp1), [t2] "=&w" (tmp2), [t3] "=&w" (tmp3) // Inputs (not modified). : [rounds] "r" (rounds), [tbl] "r" (base64_table_enc_6bit), [n63] "w" (vdupq_n_u8(63)) // Clobbers. : "v2", "v3", "v4", "v5", "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", "cc", "memory" ); } #pragma GCC diagnostic pop ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/neon64/enc_reshuffle.c0000644000175100017510000000173415200142331020435 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE uint8x16x4_t enc_reshuffle (const uint8x16x3_t in) { uint8x16x4_t out; // Input: // in[0] = a7 a6 a5 a4 a3 a2 a1 a0 // in[1] = b7 b6 b5 b4 b3 b2 b1 b0 // in[2] = c7 c6 c5 c4 c3 c2 c1 c0 // Output: // out[0] = 00 00 a7 a6 a5 a4 a3 a2 // out[1] = 00 00 a1 a0 b7 b6 b5 b4 // out[2] = 00 00 b3 b2 b1 b0 c7 c6 // out[3] = 00 00 c5 c4 c3 c2 c1 c0 // Move the input bits to where they need to be in the outputs. Except // for the first output, the high two bits are not cleared. out.val[0] = vshrq_n_u8(in.val[0], 2); out.val[1] = vshrq_n_u8(in.val[1], 4); out.val[2] = vshrq_n_u8(in.val[2], 6); out.val[1] = vsliq_n_u8(out.val[1], in.val[0], 4); out.val[2] = vsliq_n_u8(out.val[2], in.val[1], 2); // Clear the high two bits in the second, third and fourth output. out.val[1] = vandq_u8(out.val[1], vdupq_n_u8(0x3F)); out.val[2] = vandq_u8(out.val[2], vdupq_n_u8(0x3F)); out.val[3] = vandq_u8(in.val[2], vdupq_n_u8(0x3F)); return out; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8523083 librt-0.11.0/base64/arch/sse41/0000755000175100017510000000000015200142335015306 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/sse41/codec.c0000644000175100017510000000266015200142331016527 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if HAVE_SSE41 #if defined(__clang__) #pragma clang attribute push (__attribute__((target("sse4.1"))), apply_to=function) #else #pragma GCC target("sse4.1") #endif #include // Only enable inline assembly on supported compilers and on 64-bit CPUs. #ifndef BASE64_SSE41_USE_ASM # if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64 # define BASE64_SSE41_USE_ASM 1 # else # define BASE64_SSE41_USE_ASM 0 # endif #endif #include "../ssse3/dec_reshuffle.c" #include "../ssse3/dec_loop.c" #if BASE64_SSE41_USE_ASM # include "../ssse3/enc_loop_asm.c" #else # include "../ssse3/enc_translate.c" # include "../ssse3/enc_reshuffle.c" # include "../ssse3/enc_loop.c" #endif #endif // HAVE_SSE41 void base64_stream_encode_sse41 BASE64_ENC_PARAMS { #if HAVE_SSE41 #include "../generic/enc_head.c" enc_loop_ssse3(&s, &slen, &o, &olen); #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } int base64_stream_decode_sse41 BASE64_DEC_PARAMS { #if HAVE_SSE41 #include "../generic/dec_head.c" dec_loop_ssse3(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #if defined(__clang__) #pragma clang attribute pop #endif #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8524778 librt-0.11.0/base64/arch/sse42/0000755000175100017510000000000015200142335015307 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/sse42/codec.c0000644000175100017510000000266015200142331016530 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if HAVE_SSE42 #if defined(__clang__) #pragma clang attribute push (__attribute__((target("sse4.2"))), apply_to=function) #else #pragma GCC target("sse4.2") #endif #include // Only enable inline assembly on supported compilers and on 64-bit CPUs. #ifndef BASE64_SSE42_USE_ASM # if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64 # define BASE64_SSE42_USE_ASM 1 # else # define BASE64_SSE42_USE_ASM 0 # endif #endif #include "../ssse3/dec_reshuffle.c" #include "../ssse3/dec_loop.c" #if BASE64_SSE42_USE_ASM # include "../ssse3/enc_loop_asm.c" #else # include "../ssse3/enc_translate.c" # include "../ssse3/enc_reshuffle.c" # include "../ssse3/enc_loop.c" #endif #endif // HAVE_SSE42 void base64_stream_encode_sse42 BASE64_ENC_PARAMS { #if HAVE_SSE42 #include "../generic/enc_head.c" enc_loop_ssse3(&s, &slen, &o, &olen); #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } int base64_stream_decode_sse42 BASE64_DEC_PARAMS { #if HAVE_SSE42 #include "../generic/dec_head.c" dec_loop_ssse3(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #if defined(__clang__) #pragma clang attribute pop #endif #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8537328 librt-0.11.0/base64/arch/ssse3/0000755000175100017510000000000015200142335015407 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/ssse3/codec.c0000644000175100017510000000300415200142331016621 0ustar00runnerrunner#include #include #include #include "libbase64.h" #include "../../tables/tables.h" #include "../../codecs.h" #include "config.h" #include "../../env.h" #if HAVE_SSSE3 #if defined(__clang__) #pragma clang attribute push (__attribute__((target("ssse3"))), apply_to=function) #else #pragma GCC target("ssse3") #endif #include // Only enable inline assembly on supported compilers and on 64-bit CPUs. // 32-bit CPUs with SSSE3 support, such as low-end Atoms, only have eight XMM // registers, which is not enough to run the inline assembly. #ifndef BASE64_SSSE3_USE_ASM # if (defined(__GNUC__) || defined(__clang__)) && BASE64_WORDSIZE == 64 # define BASE64_SSSE3_USE_ASM 1 # else # define BASE64_SSSE3_USE_ASM 0 # endif #endif #include "dec_reshuffle.c" #include "dec_loop.c" #if BASE64_SSSE3_USE_ASM # include "enc_loop_asm.c" #else # include "enc_reshuffle.c" # include "enc_translate.c" # include "enc_loop.c" #endif #endif // HAVE_SSSE3 void base64_stream_encode_ssse3 BASE64_ENC_PARAMS { #if HAVE_SSSE3 #include "../generic/enc_head.c" enc_loop_ssse3(&s, &slen, &o, &olen); #include "../generic/enc_tail.c" #else base64_enc_stub(state, src, srclen, out, outlen); #endif } int base64_stream_decode_ssse3 BASE64_DEC_PARAMS { #if HAVE_SSSE3 #include "../generic/dec_head.c" dec_loop_ssse3(&s, &slen, &o, &olen); #include "../generic/dec_tail.c" #if defined(__clang__) #pragma clang attribute pop #endif #else return base64_dec_stub(state, src, srclen, out, outlen); #endif } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/ssse3/dec_loop.c0000644000175100017510000001535315200142331017342 0ustar00runnerrunner// The input consists of six character sets in the Base64 alphabet, which we // need to map back to the 6-bit values they represent. There are three ranges, // two singles, and then there's the rest. // // # From To Add Characters // 1 [43] [62] +19 + // 2 [47] [63] +16 / // 3 [48..57] [52..61] +4 0..9 // 4 [65..90] [0..25] -65 A..Z // 5 [97..122] [26..51] -71 a..z // (6) Everything else => invalid input // // We will use lookup tables for character validation and offset computation. // Remember that 0x2X and 0x0X are the same index for _mm_shuffle_epi8, this // allows to mask with 0x2F instead of 0x0F and thus save one constant // declaration (register and/or memory access). // // For offsets: // Perfect hash for lut = ((src >> 4) & 0x2F) + ((src == 0x2F) ? 0xFF : 0x00) // 0000 = garbage // 0001 = / // 0010 = + // 0011 = 0-9 // 0100 = A-Z // 0101 = A-Z // 0110 = a-z // 0111 = a-z // 1000 >= garbage // // For validation, here's the table. // A character is valid if and only if the AND of the 2 lookups equals 0: // // hi \ lo 0000 0001 0010 0011 0100 0101 0110 0111 1000 1001 1010 1011 1100 1101 1110 1111 // LUT 0x15 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x11 0x13 0x1A 0x1B 0x1B 0x1B 0x1A // // 0000 0x10 char NUL SOH STX ETX EOT ENQ ACK BEL BS HT LF VT FF CR SO SI // andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // // 0001 0x10 char DLE DC1 DC2 DC3 DC4 NAK SYN ETB CAN EM SUB ESC FS GS RS US // andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // // 0010 0x01 char ! " # $ % & ' ( ) * + , - . / // andlut 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x01 0x00 0x01 0x01 0x01 0x00 // // 0011 0x02 char 0 1 2 3 4 5 6 7 8 9 : ; < = > ? // andlut 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x02 0x02 0x02 0x02 0x02 0x02 // // 0100 0x04 char @ A B C D E F G H I J K L M N O // andlut 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // // 0101 0x08 char P Q R S T U V W X Y Z [ \ ] ^ _ // andlut 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x08 0x08 0x08 0x08 // // 0110 0x04 char ` a b c d e f g h i j k l m n o // andlut 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 // 0111 0x08 char p q r s t u v w x y z { | } ~ // andlut 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x08 0x08 0x08 0x08 0x08 // // 1000 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // 1001 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // 1010 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // 1011 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // 1100 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // 1101 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // 1110 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 // 1111 0x10 andlut 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 0x10 static BASE64_FORCE_INLINE int dec_loop_ssse3_inner (const uint8_t **s, uint8_t **o, size_t *rounds) { const __m128i lut_lo = _mm_setr_epi8( 0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x13, 0x1A, 0x1B, 0x1B, 0x1B, 0x1A); const __m128i lut_hi = _mm_setr_epi8( 0x10, 0x10, 0x01, 0x02, 0x04, 0x08, 0x04, 0x08, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10); const __m128i lut_roll = _mm_setr_epi8( 0, 16, 19, 4, -65, -65, -71, -71, 0, 0, 0, 0, 0, 0, 0, 0); const __m128i mask_2F = _mm_set1_epi8(0x2F); // Load input: __m128i str = _mm_loadu_si128((__m128i *) *s); // Table lookups: const __m128i hi_nibbles = _mm_and_si128(_mm_srli_epi32(str, 4), mask_2F); const __m128i lo_nibbles = _mm_and_si128(str, mask_2F); const __m128i hi = _mm_shuffle_epi8(lut_hi, hi_nibbles); const __m128i lo = _mm_shuffle_epi8(lut_lo, lo_nibbles); // Check for invalid input: if any "and" values from lo and hi are not // zero, fall back on bytewise code to do error checking and reporting: if (_mm_movemask_epi8(_mm_cmpgt_epi8(_mm_and_si128(lo, hi), _mm_setzero_si128())) != 0) { return 0; } const __m128i eq_2F = _mm_cmpeq_epi8(str, mask_2F); const __m128i roll = _mm_shuffle_epi8(lut_roll, _mm_add_epi8(eq_2F, hi_nibbles)); // Now simply add the delta values to the input: str = _mm_add_epi8(str, roll); // Reshuffle the input to packed 12-byte output format: str = dec_reshuffle(str); // Store the output: _mm_storeu_si128((__m128i *) *o, str); *s += 16; *o += 12; *rounds -= 1; return 1; } static inline void dec_loop_ssse3 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 24) { return; } // Process blocks of 16 bytes per round. Because 4 extra zero bytes are // written after the output, ensure that there will be at least 8 bytes // of input data left to cover the gap. (6 data bytes and up to two // end-of-string markers.) size_t rounds = (*slen - 8) / 16; *slen -= rounds * 16; // 16 bytes consumed per round *olen += rounds * 12; // 12 bytes produced per round do { if (rounds >= 8) { if (dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 4) { if (dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds)) { continue; } break; } if (rounds >= 2) { if (dec_loop_ssse3_inner(s, o, &rounds) && dec_loop_ssse3_inner(s, o, &rounds)) { continue; } break; } dec_loop_ssse3_inner(s, o, &rounds); break; } while (rounds > 0); // Adjust for any rounds that were skipped: *slen += rounds * 16; *olen -= rounds * 12; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/ssse3/dec_reshuffle.c0000644000175100017510000000213615200142331020347 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE __m128i dec_reshuffle (const __m128i in) { // in, bits, upper case are most significant bits, lower case are least significant bits // 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ // 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG // 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD // 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA const __m128i merge_ab_and_bc = _mm_maddubs_epi16(in, _mm_set1_epi32(0x01400140)); // 0000kkkk LLllllll 0000JJJJ JJjjKKKK // 0000hhhh IIiiiiii 0000GGGG GGggHHHH // 0000eeee FFffffff 0000DDDD DDddEEEE // 0000bbbb CCcccccc 0000AAAA AAaaBBBB const __m128i out = _mm_madd_epi16(merge_ab_and_bc, _mm_set1_epi32(0x00011000)); // 00000000 JJJJJJjj KKKKkkkk LLllllll // 00000000 GGGGGGgg HHHHhhhh IIiiiiii // 00000000 DDDDDDdd EEEEeeee FFffffff // 00000000 AAAAAAaa BBBBbbbb CCcccccc // Pack bytes together: return _mm_shuffle_epi8(out, _mm_setr_epi8( 2, 1, 0, 6, 5, 4, 10, 9, 8, 14, 13, 12, -1, -1, -1, -1)); // 00000000 00000000 00000000 00000000 // LLllllll KKKKkkkk JJJJJJjj IIiiiiii // HHHHhhhh GGGGGGgg FFffffff EEEEeeee // DDDDDDdd CCcccccc BBBBbbbb AAAAAAaa } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/ssse3/enc_loop.c0000644000175100017510000000301515200142331017344 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE void enc_loop_ssse3_inner (const uint8_t **s, uint8_t **o) { // Load input: __m128i str = _mm_loadu_si128((__m128i *) *s); // Reshuffle: str = enc_reshuffle(str); // Translate reshuffled bytes to the Base64 alphabet: str = enc_translate(str); // Store: _mm_storeu_si128((__m128i *) *o, str); *s += 12; *o += 16; } static inline void enc_loop_ssse3 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { if (*slen < 16) { return; } // Process blocks of 12 bytes at a time. Because blocks are loaded 16 // bytes at a time, ensure that there will be at least 4 remaining // bytes after the last round, so that the final read will not pass // beyond the bounds of the input buffer: size_t rounds = (*slen - 4) / 12; *slen -= rounds * 12; // 12 bytes consumed per round *olen += rounds * 16; // 16 bytes produced per round do { if (rounds >= 8) { enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); rounds -= 8; continue; } if (rounds >= 4) { enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); rounds -= 4; continue; } if (rounds >= 2) { enc_loop_ssse3_inner(s, o); enc_loop_ssse3_inner(s, o); rounds -= 2; continue; } enc_loop_ssse3_inner(s, o); break; } while (rounds > 0); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/ssse3/enc_loop_asm.c0000644000175100017510000002213615200142331020211 0ustar00runnerrunner// Apologies in advance for combining the preprocessor with inline assembly, // two notoriously gnarly parts of C, but it was necessary to avoid a lot of // code repetition. The preprocessor is used to template large sections of // inline assembly that differ only in the registers used. If the code was // written out by hand, it would become very large and hard to audit. // Generate a block of inline assembly that loads register R0 from memory. The // offset at which the register is loaded is set by the given round. #define LOAD(R0, ROUND) \ "lddqu ("#ROUND" * 12)(%[src]), %["R0"] \n\t" // Generate a block of inline assembly that deinterleaves and shuffles register // R0 using preloaded constants. Outputs in R0 and R1. #define SHUF(R0, R1) \ "pshufb %[lut0], %["R0"] \n\t" \ "movdqa %["R0"], %["R1"] \n\t" \ "pand %[msk0], %["R0"] \n\t" \ "pand %[msk2], %["R1"] \n\t" \ "pmulhuw %[msk1], %["R0"] \n\t" \ "pmullw %[msk3], %["R1"] \n\t" \ "por %["R1"], %["R0"] \n\t" // Generate a block of inline assembly that takes R0 and R1 and translates // their contents to the base64 alphabet, using preloaded constants. #define TRAN(R0, R1, R2) \ "movdqa %["R0"], %["R1"] \n\t" \ "movdqa %["R0"], %["R2"] \n\t" \ "psubusb %[n51], %["R1"] \n\t" \ "pcmpgtb %[n25], %["R2"] \n\t" \ "psubb %["R2"], %["R1"] \n\t" \ "movdqa %[lut1], %["R2"] \n\t" \ "pshufb %["R1"], %["R2"] \n\t" \ "paddb %["R2"], %["R0"] \n\t" // Generate a block of inline assembly that stores the given register R0 at an // offset set by the given round. #define STOR(R0, ROUND) \ "movdqu %["R0"], ("#ROUND" * 16)(%[dst]) \n\t" // Generate a block of inline assembly that generates a single self-contained // encoder round: fetch the data, process it, and store the result. Then update // the source and destination pointers. #define ROUND() \ LOAD("a", 0) \ SHUF("a", "b") \ TRAN("a", "b", "c") \ STOR("a", 0) \ "add $12, %[src] \n\t" \ "add $16, %[dst] \n\t" // Define a macro that initiates a three-way interleaved encoding round by // preloading registers a, b and c from memory. // The register graph shows which registers are in use during each step, and // is a visual aid for choosing registers for that step. Symbol index: // // + indicates that a register is loaded by that step. // | indicates that a register is in use and must not be touched. // - indicates that a register is decommissioned by that step. // x indicates that a register is used as a temporary by that step. // V indicates that a register is an input or output to the macro. // #define ROUND_3_INIT() /* a b c d e f */ \ LOAD("a", 0) /* + */ \ SHUF("a", "d") /* | + */ \ LOAD("b", 1) /* | + | */ \ TRAN("a", "d", "e") /* | | - x */ \ LOAD("c", 2) /* V V V */ // Define a macro that translates, shuffles and stores the input registers A, B // and C, and preloads registers D, E and F for the next round. // This macro can be arbitrarily daisy-chained by feeding output registers D, E // and F back into the next round as input registers A, B and C. The macro // carefully interleaves memory operations with data operations for optimal // pipelined performance. #define ROUND_3(ROUND, A,B,C,D,E,F) /* A B C D E F */ \ LOAD(D, (ROUND + 3)) /* V V V + */ \ SHUF(B, E) /* | | | | + */ \ STOR(A, (ROUND + 0)) /* - | | | | */ \ TRAN(B, E, F) /* | | | - x */ \ LOAD(E, (ROUND + 4)) /* | | | + */ \ SHUF(C, A) /* + | | | | */ \ STOR(B, (ROUND + 1)) /* | - | | | */ \ TRAN(C, A, F) /* - | | | x */ \ LOAD(F, (ROUND + 5)) /* | | | + */ \ SHUF(D, A) /* + | | | | */ \ STOR(C, (ROUND + 2)) /* | - | | | */ \ TRAN(D, A, B) /* - x V V V */ // Define a macro that terminates a ROUND_3 macro by taking pre-loaded // registers D, E and F, and translating, shuffling and storing them. #define ROUND_3_END(ROUND, A,B,C,D,E,F) /* A B C D E F */ \ SHUF(E, A) /* + V V V */ \ STOR(D, (ROUND + 3)) /* | - | | */ \ TRAN(E, A, B) /* - x | | */ \ SHUF(F, C) /* + | | */ \ STOR(E, (ROUND + 4)) /* | - | */ \ TRAN(F, C, D) /* - x | */ \ STOR(F, (ROUND + 5)) /* - */ // Define a type A round. Inputs are a, b, and c, outputs are d, e, and f. #define ROUND_3_A(ROUND) \ ROUND_3(ROUND, "a", "b", "c", "d", "e", "f") // Define a type B round. Inputs and outputs are swapped with regard to type A. #define ROUND_3_B(ROUND) \ ROUND_3(ROUND, "d", "e", "f", "a", "b", "c") // Terminating macro for a type A round. #define ROUND_3_A_LAST(ROUND) \ ROUND_3_A(ROUND) \ ROUND_3_END(ROUND, "a", "b", "c", "d", "e", "f") // Terminating macro for a type B round. #define ROUND_3_B_LAST(ROUND) \ ROUND_3_B(ROUND) \ ROUND_3_END(ROUND, "d", "e", "f", "a", "b", "c") // Suppress clang's warning that the literal string in the asm statement is // overlong (longer than the ISO-mandated minimum size of 4095 bytes for C99 // compilers). It may be true, but the goal here is not C99 portability. #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Woverlength-strings" static inline void enc_loop_ssse3 (const uint8_t **s, size_t *slen, uint8_t **o, size_t *olen) { // For a clearer explanation of the algorithm used by this function, // please refer to the plain (not inline assembly) implementation. This // function follows the same basic logic. if (*slen < 16) { return; } // Process blocks of 12 bytes at a time. Input is read in blocks of 16 // bytes, so "reserve" four bytes from the input buffer to ensure that // we never read beyond the end of the input buffer. size_t rounds = (*slen - 4) / 12; *slen -= rounds * 12; // 12 bytes consumed per round *olen += rounds * 16; // 16 bytes produced per round // Number of times to go through the 36x loop. size_t loops = rounds / 36; // Number of rounds remaining after the 36x loop. rounds %= 36; // Lookup tables. const __m128i lut0 = _mm_set_epi8( 10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1); const __m128i lut1 = _mm_setr_epi8( 65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0); // Temporary registers. __m128i a, b, c, d, e, f; __asm__ volatile ( // If there are 36 rounds or more, enter a 36x unrolled loop of // interleaved encoding rounds. The rounds interleave memory // operations (load/store) with data operations (table lookups, // etc) to maximize pipeline throughput. " test %[loops], %[loops] \n\t" " jz 18f \n\t" " jmp 36f \n\t" " \n\t" ".balign 64 \n\t" "36: " ROUND_3_INIT() " " ROUND_3_A( 0) " " ROUND_3_B( 3) " " ROUND_3_A( 6) " " ROUND_3_B( 9) " " ROUND_3_A(12) " " ROUND_3_B(15) " " ROUND_3_A(18) " " ROUND_3_B(21) " " ROUND_3_A(24) " " ROUND_3_B(27) " " ROUND_3_A_LAST(30) " add $(12 * 36), %[src] \n\t" " add $(16 * 36), %[dst] \n\t" " dec %[loops] \n\t" " jnz 36b \n\t" // Enter an 18x unrolled loop for rounds of 18 or more. "18: cmp $18, %[rounds] \n\t" " jl 9f \n\t" " " ROUND_3_INIT() " " ROUND_3_A(0) " " ROUND_3_B(3) " " ROUND_3_A(6) " " ROUND_3_B(9) " " ROUND_3_A_LAST(12) " sub $18, %[rounds] \n\t" " add $(12 * 18), %[src] \n\t" " add $(16 * 18), %[dst] \n\t" // Enter a 9x unrolled loop for rounds of 9 or more. "9: cmp $9, %[rounds] \n\t" " jl 6f \n\t" " " ROUND_3_INIT() " " ROUND_3_A(0) " " ROUND_3_B_LAST(3) " sub $9, %[rounds] \n\t" " add $(12 * 9), %[src] \n\t" " add $(16 * 9), %[dst] \n\t" // Enter a 6x unrolled loop for rounds of 6 or more. "6: cmp $6, %[rounds] \n\t" " jl 55f \n\t" " " ROUND_3_INIT() " " ROUND_3_A_LAST(0) " sub $6, %[rounds] \n\t" " add $(12 * 6), %[src] \n\t" " add $(16 * 6), %[dst] \n\t" // Dispatch the remaining rounds 0..5. "55: cmp $3, %[rounds] \n\t" " jg 45f \n\t" " je 3f \n\t" " cmp $1, %[rounds] \n\t" " jg 2f \n\t" " je 1f \n\t" " jmp 0f \n\t" "45: cmp $4, %[rounds] \n\t" " je 4f \n\t" // Block of non-interlaced encoding rounds, which can each // individually be jumped to. Rounds fall through to the next. "5: " ROUND() "4: " ROUND() "3: " ROUND() "2: " ROUND() "1: " ROUND() "0: \n\t" // Outputs (modified). : [rounds] "+r" (rounds), [loops] "+r" (loops), [src] "+r" (*s), [dst] "+r" (*o), [a] "=&x" (a), [b] "=&x" (b), [c] "=&x" (c), [d] "=&x" (d), [e] "=&x" (e), [f] "=&x" (f) // Inputs (not modified). : [lut0] "x" (lut0), [lut1] "x" (lut1), [msk0] "x" (_mm_set1_epi32(0x0FC0FC00)), [msk1] "x" (_mm_set1_epi32(0x04000040)), [msk2] "x" (_mm_set1_epi32(0x003F03F0)), [msk3] "x" (_mm_set1_epi32(0x01000010)), [n51] "x" (_mm_set1_epi8(51)), [n25] "x" (_mm_set1_epi8(25)) // Clobbers. : "cc", "memory" ); } #pragma GCC diagnostic pop ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/ssse3/enc_reshuffle.c0000644000175100017510000000275215200142331020365 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE __m128i enc_reshuffle (__m128i in) { // Input, bytes MSB to LSB: // 0 0 0 0 l k j i h g f e d c b a in = _mm_shuffle_epi8(in, _mm_set_epi8( 10, 11, 9, 10, 7, 8, 6, 7, 4, 5, 3, 4, 1, 2, 0, 1)); // in, bytes MSB to LSB: // k l j k // h i g h // e f d e // b c a b const __m128i t0 = _mm_and_si128(in, _mm_set1_epi32(0x0FC0FC00)); // bits, upper case are most significant bits, lower case are least significant bits // 0000kkkk LL000000 JJJJJJ00 00000000 // 0000hhhh II000000 GGGGGG00 00000000 // 0000eeee FF000000 DDDDDD00 00000000 // 0000bbbb CC000000 AAAAAA00 00000000 const __m128i t1 = _mm_mulhi_epu16(t0, _mm_set1_epi32(0x04000040)); // 00000000 00kkkkLL 00000000 00JJJJJJ // 00000000 00hhhhII 00000000 00GGGGGG // 00000000 00eeeeFF 00000000 00DDDDDD // 00000000 00bbbbCC 00000000 00AAAAAA const __m128i t2 = _mm_and_si128(in, _mm_set1_epi32(0x003F03F0)); // 00000000 00llllll 000000jj KKKK0000 // 00000000 00iiiiii 000000gg HHHH0000 // 00000000 00ffffff 000000dd EEEE0000 // 00000000 00cccccc 000000aa BBBB0000 const __m128i t3 = _mm_mullo_epi16(t2, _mm_set1_epi32(0x01000010)); // 00llllll 00000000 00jjKKKK 00000000 // 00iiiiii 00000000 00ggHHHH 00000000 // 00ffffff 00000000 00ddEEEE 00000000 // 00cccccc 00000000 00aaBBBB 00000000 return _mm_or_si128(t1, t3); // 00llllll 00kkkkLL 00jjKKKK 00JJJJJJ // 00iiiiii 00hhhhII 00ggHHHH 00GGGGGG // 00ffffff 00eeeeFF 00ddEEEE 00DDDDDD // 00cccccc 00bbbbCC 00aaBBBB 00AAAAAA } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/arch/ssse3/enc_translate.c0000644000175100017510000000222315200142331020370 0ustar00runnerrunnerstatic BASE64_FORCE_INLINE __m128i enc_translate (const __m128i in) { // A lookup table containing the absolute offsets for all ranges: const __m128i lut = _mm_setr_epi8( 65, 71, -4, -4, -4, -4, -4, -4, -4, -4, -4, -4, -19, -16, 0, 0 ); // Translate values 0..63 to the Base64 alphabet. There are five sets: // # From To Abs Index Characters // 0 [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ // 1 [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz // 2 [52..61] [48..57] -4 [2..11] 0123456789 // 3 [62] [43] -19 12 + // 4 [63] [47] -16 13 / // Create LUT indices from the input. The index for range #0 is right, // others are 1 less than expected: __m128i indices = _mm_subs_epu8(in, _mm_set1_epi8(51)); // mask is 0xFF (-1) for range #[1..4] and 0x00 for range #0: __m128i mask = _mm_cmpgt_epi8(in, _mm_set1_epi8(25)); // Subtract -1, so add 1 to indices for range #[1..4]. All indices are // now correct: indices = _mm_sub_epi8(indices, mask); // Add offsets to input values: return _mm_add_epi8(in, _mm_shuffle_epi8(lut, indices)); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/codec_choose.c0000644000175100017510000001664615200142331016224 0ustar00runnerrunner#include #include #include #include #include #include "libbase64.h" #include "codecs.h" #include "config.h" #include "env.h" #if (__x86_64__ || __i386__ || _M_X86 || _M_X64) #define BASE64_X86 #if (HAVE_SSSE3 || HAVE_SSE41 || HAVE_SSE42 || HAVE_AVX || HAVE_AVX2 || HAVE_AVX512) #define BASE64_X86_SIMD #endif #endif #ifdef BASE64_X86 #ifdef _MSC_VER #include #define __cpuid_count(__level, __count, __eax, __ebx, __ecx, __edx) \ { \ int info[4]; \ __cpuidex(info, __level, __count); \ __eax = info[0]; \ __ebx = info[1]; \ __ecx = info[2]; \ __edx = info[3]; \ } #define __cpuid(__level, __eax, __ebx, __ecx, __edx) \ __cpuid_count(__level, 0, __eax, __ebx, __ecx, __edx) #else #include #if HAVE_AVX512 || HAVE_AVX2 || HAVE_AVX #if ((__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 2) || (__clang_major__ >= 3)) static inline uint64_t _xgetbv (uint32_t index) { uint32_t eax, edx; __asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index)); return ((uint64_t)edx << 32) | eax; } #else #error "Platform not supported" #endif #endif #endif #ifndef bit_AVX512vl #define bit_AVX512vl (1 << 31) #endif #ifndef bit_AVX512vbmi #define bit_AVX512vbmi (1 << 1) #endif #ifndef bit_AVX2 #define bit_AVX2 (1 << 5) #endif #ifndef bit_SSSE3 #define bit_SSSE3 (1 << 9) #endif #ifndef bit_SSE41 #define bit_SSE41 (1 << 19) #endif #ifndef bit_SSE42 #define bit_SSE42 (1 << 20) #endif #ifndef bit_AVX #define bit_AVX (1 << 28) #endif #define bit_XSAVE_XRSTORE (1 << 27) #ifndef _XCR_XFEATURE_ENABLED_MASK #define _XCR_XFEATURE_ENABLED_MASK 0 #endif #define bit_XMM (1 << 1) #define bit_YMM (1 << 2) #define bit_OPMASK (1 << 5) #define bit_ZMM (1 << 6) #define bit_HIGH_ZMM (1 << 7) #define _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS (bit_XMM | bit_YMM) #define _AVX_512_ENABLED_BY_OS (bit_XMM | bit_YMM | bit_OPMASK | bit_ZMM | bit_HIGH_ZMM) #endif // Function declarations: #define BASE64_CODEC_FUNCS(arch) \ extern void base64_stream_encode_ ## arch BASE64_ENC_PARAMS; \ extern int base64_stream_decode_ ## arch BASE64_DEC_PARAMS; BASE64_CODEC_FUNCS(avx512) BASE64_CODEC_FUNCS(avx2) BASE64_CODEC_FUNCS(neon32) BASE64_CODEC_FUNCS(neon64) BASE64_CODEC_FUNCS(plain) BASE64_CODEC_FUNCS(ssse3) BASE64_CODEC_FUNCS(sse41) BASE64_CODEC_FUNCS(sse42) BASE64_CODEC_FUNCS(avx) static bool codec_choose_forced (struct codec *codec, int flags) { // If the user wants to use a certain codec, // always allow it, even if the codec is a no-op. // For testing purposes. if (!(flags & 0xFFFF)) { return false; } if (flags & BASE64_FORCE_AVX2) { codec->enc = base64_stream_encode_avx2; codec->dec = base64_stream_decode_avx2; return true; } if (flags & BASE64_FORCE_NEON32) { codec->enc = base64_stream_encode_neon32; codec->dec = base64_stream_decode_neon32; return true; } if (flags & BASE64_FORCE_NEON64) { codec->enc = base64_stream_encode_neon64; codec->dec = base64_stream_decode_neon64; return true; } if (flags & BASE64_FORCE_PLAIN) { codec->enc = base64_stream_encode_plain; codec->dec = base64_stream_decode_plain; return true; } if (flags & BASE64_FORCE_SSSE3) { codec->enc = base64_stream_encode_ssse3; codec->dec = base64_stream_decode_ssse3; return true; } if (flags & BASE64_FORCE_SSE41) { codec->enc = base64_stream_encode_sse41; codec->dec = base64_stream_decode_sse41; return true; } if (flags & BASE64_FORCE_SSE42) { codec->enc = base64_stream_encode_sse42; codec->dec = base64_stream_decode_sse42; return true; } if (flags & BASE64_FORCE_AVX) { codec->enc = base64_stream_encode_avx; codec->dec = base64_stream_decode_avx; return true; } if (flags & BASE64_FORCE_AVX512) { codec->enc = base64_stream_encode_avx512; codec->dec = base64_stream_decode_avx512; return true; } return false; } static bool codec_choose_arm (struct codec *codec) { #if HAVE_NEON64 || ((defined(__ARM_NEON__) || defined(__ARM_NEON)) && HAVE_NEON32) // Unfortunately there is no portable way to check for NEON // support at runtime from userland in the same way that x86 // has cpuid, so just stick to the compile-time configuration: #if HAVE_NEON64 codec->enc = base64_stream_encode_neon64; codec->dec = base64_stream_decode_neon64; #else codec->enc = base64_stream_encode_neon32; codec->dec = base64_stream_decode_neon32; #endif return true; #else (void)codec; return false; #endif } static bool codec_choose_x86 (struct codec *codec) { #ifdef BASE64_X86_SIMD unsigned int eax, ebx = 0, ecx = 0, edx; unsigned int max_level; #ifdef _MSC_VER int info[4]; __cpuidex(info, 0, 0); max_level = info[0]; #else max_level = __get_cpuid_max(0, NULL); #endif #if HAVE_AVX512 || HAVE_AVX2 || HAVE_AVX // Check for AVX/AVX2/AVX512 support: // Checking for AVX requires 3 things: // 1) CPUID indicates that the OS uses XSAVE and XRSTORE instructions // (allowing saving YMM registers on context switch) // 2) CPUID indicates support for AVX // 3) XGETBV indicates the AVX registers will be saved and restored on // context switch // // Note that XGETBV is only available on 686 or later CPUs, so the // instruction needs to be conditionally run. if (max_level >= 1) { __cpuid_count(1, 0, eax, ebx, ecx, edx); if (ecx & bit_XSAVE_XRSTORE) { uint64_t xcr_mask; xcr_mask = _xgetbv(_XCR_XFEATURE_ENABLED_MASK); if ((xcr_mask & _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS) == _XCR_XMM_AND_YMM_STATE_ENABLED_BY_OS) { // check multiple bits at once #if HAVE_AVX512 if (max_level >= 7 && ((xcr_mask & _AVX_512_ENABLED_BY_OS) == _AVX_512_ENABLED_BY_OS)) { __cpuid_count(7, 0, eax, ebx, ecx, edx); if ((ebx & bit_AVX512vl) && (ecx & bit_AVX512vbmi)) { codec->enc = base64_stream_encode_avx512; codec->dec = base64_stream_decode_avx512; return true; } } #endif #if HAVE_AVX2 if (max_level >= 7) { __cpuid_count(7, 0, eax, ebx, ecx, edx); if (ebx & bit_AVX2) { codec->enc = base64_stream_encode_avx2; codec->dec = base64_stream_decode_avx2; return true; } } #endif #if HAVE_AVX __cpuid_count(1, 0, eax, ebx, ecx, edx); if (ecx & bit_AVX) { codec->enc = base64_stream_encode_avx; codec->dec = base64_stream_decode_avx; return true; } #endif } } } #endif #if HAVE_SSE42 // Check for SSE42 support: if (max_level >= 1) { __cpuid(1, eax, ebx, ecx, edx); if (ecx & bit_SSE42) { codec->enc = base64_stream_encode_sse42; codec->dec = base64_stream_decode_sse42; return true; } } #endif #if HAVE_SSE41 // Check for SSE41 support: if (max_level >= 1) { __cpuid(1, eax, ebx, ecx, edx); if (ecx & bit_SSE41) { codec->enc = base64_stream_encode_sse41; codec->dec = base64_stream_decode_sse41; return true; } } #endif #if HAVE_SSSE3 // Check for SSSE3 support: if (max_level >= 1) { __cpuid(1, eax, ebx, ecx, edx); if (ecx & bit_SSSE3) { codec->enc = base64_stream_encode_ssse3; codec->dec = base64_stream_decode_ssse3; return true; } } #endif #else (void)codec; #endif return false; } void codec_choose (struct codec *codec, int flags) { // User forced a codec: if (codec_choose_forced(codec, flags)) { return; } // Runtime feature detection: if (codec_choose_arm(codec)) { return; } if (codec_choose_x86(codec)) { return; } codec->enc = base64_stream_encode_plain; codec->dec = base64_stream_decode_plain; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/codecs.h0000644000175100017510000000224415200142331015041 0ustar00runnerrunner#include "libbase64.h" // Function parameters for encoding functions: #define BASE64_ENC_PARAMS \ ( struct base64_state *state \ , const char *src \ , size_t srclen \ , char *out \ , size_t *outlen \ ) // Function parameters for decoding functions: #define BASE64_DEC_PARAMS \ ( struct base64_state *state \ , const char *src \ , size_t srclen \ , char *out \ , size_t *outlen \ ) // This function is used as a stub when a certain encoder is not compiled in. // It discards the inputs and returns zero output bytes. static inline void base64_enc_stub BASE64_ENC_PARAMS { (void) state; (void) src; (void) srclen; (void) out; *outlen = 0; } // This function is used as a stub when a certain decoder is not compiled in. // It discards the inputs and returns an invalid decoding result. static inline int base64_dec_stub BASE64_DEC_PARAMS { (void) state; (void) src; (void) srclen; (void) out; (void) outlen; return -1; } typedef void (* base64_enc_fn) BASE64_ENC_PARAMS; typedef int (* base64_dec_fn) BASE64_DEC_PARAMS; struct codec { base64_enc_fn enc; base64_dec_fn dec; }; extern void codec_choose (struct codec *, int flags); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/config.h0000644000175100017510000000113015200142331015037 0ustar00runnerrunner#ifndef BASE64_CONFIG_H #define BASE64_CONFIG_H #if !defined(__APPLE__) && ((defined(__x86_64__) && defined(__LP64__)) || defined(_M_X64)) #define HAVE_SSSE3 1 #define HAVE_SSE41 1 #define HAVE_SSE42 1 #define HAVE_AVX 1 #define HAVE_AVX2 1 #define HAVE_AVX512 0 #elif (defined(__APPLE__) && defined(__aarch64__)) #define HAVE_NEON64 1 #elif (defined(__wasm__) && defined(__wasm_simd128__)) #include "emscripten/version.h" #if __EMSCRIPTEN_major__ == 3 #define HAVE_NEON32 1 #elif __EMSCRIPTEN_major__ > 3 #define HAVE_NEON64 1 #endif #endif #endif // BASE64_CONFIG_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/env.h0000644000175100017510000000462515200142331014376 0ustar00runnerrunner#ifndef BASE64_ENV_H #define BASE64_ENV_H #include // This header file contains macro definitions that describe certain aspects of // the compile-time environment. Compatibility and portability macros go here. // Define machine endianness. This is for GCC: #if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) # define BASE64_LITTLE_ENDIAN 1 #else # define BASE64_LITTLE_ENDIAN 0 #endif // This is for Clang: #ifdef __LITTLE_ENDIAN__ # define BASE64_LITTLE_ENDIAN 1 #endif #ifdef __BIG_ENDIAN__ # define BASE64_LITTLE_ENDIAN 0 #endif // MSVC++ needs intrin.h for _byteswap_uint64 (issue #68): #if BASE64_LITTLE_ENDIAN && defined(_MSC_VER) # include #endif // Endian conversion functions: #if BASE64_LITTLE_ENDIAN # ifdef _MSC_VER // Microsoft Visual C++: # define BASE64_HTOBE32(x) _byteswap_ulong(x) # define BASE64_HTOBE64(x) _byteswap_uint64(x) # else // GCC and Clang: # define BASE64_HTOBE32(x) __builtin_bswap32(x) # define BASE64_HTOBE64(x) __builtin_bswap64(x) # endif #else // No conversion needed: # define BASE64_HTOBE32(x) (x) # define BASE64_HTOBE64(x) (x) #endif // Detect word size: #if defined (__x86_64__) // This also works for the x32 ABI, which has a 64-bit word size. # define BASE64_WORDSIZE 64 #elif SIZE_MAX == UINT32_MAX # define BASE64_WORDSIZE 32 #elif SIZE_MAX == UINT64_MAX # define BASE64_WORDSIZE 64 #else # error BASE64_WORDSIZE_NOT_DEFINED #endif // End-of-file definitions. // Almost end-of-file when waiting for the last '=' character: #define BASE64_AEOF 1 // End-of-file when stream end has been reached or invalid input provided: #define BASE64_EOF 2 // GCC 7 defaults to issuing a warning for fallthrough in switch statements, // unless the fallthrough cases are marked with an attribute. As we use // fallthrough deliberately, define an alias for the attribute: #if __GNUC__ >= 7 # define BASE64_FALLTHROUGH __attribute__((fallthrough)); #else # define BASE64_FALLTHROUGH #endif // Declare macros to ensure that functions that are intended to be inlined, are // actually inlined, even when no optimization is applied. A lot of inner loop // code is factored into separate functions for reasons of readability, but // that code should always be inlined (and optimized) in the main loop. #ifdef _MSC_VER # define BASE64_FORCE_INLINE __forceinline #else # define BASE64_FORCE_INLINE inline __attribute__((always_inline)) #endif #endif // BASE64_ENV_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/lib.c0000644000175100017510000000630615200142331014345 0ustar00runnerrunner#include #include #ifdef _OPENMP #include #endif #include "libbase64.h" #include "tables/tables.h" #include "codecs.h" #include "env.h" // These static function pointers are initialized once when the library is // first used, and remain in use for the remaining lifetime of the program. // The idea being that CPU features don't change at runtime. static struct codec codec = { NULL, NULL }; void base64_stream_encode_init (struct base64_state *state, int flags) { // If any of the codec flags are set, redo choice: if (codec.enc == NULL || flags & 0xFF) { codec_choose(&codec, flags); } state->eof = 0; state->bytes = 0; state->carry = 0; state->flags = flags; } void base64_stream_encode ( struct base64_state *state , const char *src , size_t srclen , char *out , size_t *outlen ) { codec.enc(state, src, srclen, out, outlen); } void base64_stream_encode_final ( struct base64_state *state , char *out , size_t *outlen ) { uint8_t *o = (uint8_t *)out; if (state->bytes == 1) { *o++ = base64_table_enc_6bit[state->carry]; *o++ = '='; *o++ = '='; *outlen = 3; return; } if (state->bytes == 2) { *o++ = base64_table_enc_6bit[state->carry]; *o++ = '='; *outlen = 2; return; } *outlen = 0; } void base64_stream_decode_init (struct base64_state *state, int flags) { // If any of the codec flags are set, redo choice: if (codec.dec == NULL || flags & 0xFFFF) { codec_choose(&codec, flags); } state->eof = 0; state->bytes = 0; state->carry = 0; state->flags = flags; } int base64_stream_decode ( struct base64_state *state , const char *src , size_t srclen , char *out , size_t *outlen ) { return codec.dec(state, src, srclen, out, outlen); } #ifdef _OPENMP // Due to the overhead of initializing OpenMP and creating a team of // threads, we require the data length to be larger than a threshold: #define OMP_THRESHOLD 20000 // Conditionally include OpenMP-accelerated codec implementations: #include "lib_openmp.c" #endif void base64_encode ( const char *src , size_t srclen , char *out , size_t *outlen , int flags ) { size_t s; size_t t; struct base64_state state; #ifdef _OPENMP if (srclen >= OMP_THRESHOLD) { base64_encode_openmp(src, srclen, out, outlen, flags); return; } #endif // Init the stream reader: base64_stream_encode_init(&state, flags); // Feed the whole string to the stream reader: base64_stream_encode(&state, src, srclen, out, &s); // Finalize the stream by writing trailer if any: base64_stream_encode_final(&state, out + s, &t); // Final output length is stream length plus tail: *outlen = s + t; } int base64_decode ( const char *src , size_t srclen , char *out , size_t *outlen , int flags ) { int ret; struct base64_state state; #ifdef _OPENMP if (srclen >= OMP_THRESHOLD) { return base64_decode_openmp(src, srclen, out, outlen, flags); } #endif // Init the stream reader: base64_stream_decode_init(&state, flags); // Feed the whole string to the stream reader: ret = base64_stream_decode(&state, src, srclen, out, outlen); // If when decoding a whole block, we're still waiting for input then fail: if (ret && (state.bytes == 0)) { return ret; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/lib_openmp.c0000644000175100017510000001055115200142331015720 0ustar00runnerrunner// This code makes some assumptions on the implementation of // base64_stream_encode_init(), base64_stream_encode() and base64_stream_decode(). // Basically these assumptions boil down to that when breaking the src into // parts, out parts can be written without side effects. // This is met when: // 1) base64_stream_encode() and base64_stream_decode() don't use globals; // 2) the shared variables src and out are not read or written outside of the // bounds of their parts, i.e. when base64_stream_encode() reads a multiple // of 3 bytes, it must write no more then a multiple of 4 bytes, not even // temporarily; // 3) the state flag can be discarded after base64_stream_encode() and // base64_stream_decode() on the parts. static inline void base64_encode_openmp ( const char *src , size_t srclen , char *out , size_t *outlen , int flags ) { size_t s; size_t t; size_t sum = 0, len, last_len; struct base64_state state, initial_state; int num_threads, i; // Request a number of threads but not necessarily get them: #pragma omp parallel { // Get the number of threads used from one thread only, // as num_threads is a shared var: #pragma omp single { num_threads = omp_get_num_threads(); // Split the input string into num_threads parts, each // part a multiple of 3 bytes. The remaining bytes will // be done later: len = srclen / (num_threads * 3); len *= 3; last_len = srclen - num_threads * len; // Init the stream reader: base64_stream_encode_init(&state, flags); initial_state = state; } // Single has an implicit barrier for all threads to wait here // for the above to complete: #pragma omp for firstprivate(state) private(s) reduction(+:sum) schedule(static,1) for (i = 0; i < num_threads; i++) { // Feed each part of the string to the stream reader: base64_stream_encode(&state, src + i * len, len, out + i * len * 4 / 3, &s); sum += s; } } // As encoding should never fail and we encode an exact multiple // of 3 bytes, we can discard state: state = initial_state; // Encode the remaining bytes: base64_stream_encode(&state, src + num_threads * len, last_len, out + num_threads * len * 4 / 3, &s); // Finalize the stream by writing trailer if any: base64_stream_encode_final(&state, out + num_threads * len * 4 / 3 + s, &t); // Final output length is stream length plus tail: sum += s + t; *outlen = sum; } static inline int base64_decode_openmp ( const char *src , size_t srclen , char *out , size_t *outlen , int flags ) { int num_threads, result = 0, i; size_t sum = 0, len, last_len, s; struct base64_state state, initial_state; // Request a number of threads but not necessarily get them: #pragma omp parallel { // Get the number of threads used from one thread only, // as num_threads is a shared var: #pragma omp single { num_threads = omp_get_num_threads(); // Split the input string into num_threads parts, each // part a multiple of 4 bytes. The remaining bytes will // be done later: len = srclen / (num_threads * 4); len *= 4; last_len = srclen - num_threads * len; // Init the stream reader: base64_stream_decode_init(&state, flags); initial_state = state; } // Single has an implicit barrier to wait here for the above to // complete: #pragma omp for firstprivate(state) private(s) reduction(+:sum, result) schedule(static,1) for (i = 0; i < num_threads; i++) { int this_result; // Feed each part of the string to the stream reader: this_result = base64_stream_decode(&state, src + i * len, len, out + i * len * 3 / 4, &s); sum += s; result += this_result; } } // If `result' equals `-num_threads', then all threads returned -1, // indicating that the requested codec is not available: if (result == -num_threads) { return -1; } // If `result' does not equal `num_threads', then at least one of the // threads hit a decode error: if (result != num_threads) { return 0; } // So far so good, now decode whatever remains in the buffer. Reuse the // initial state, since we are at a 4-byte boundary: state = initial_state; result = base64_stream_decode(&state, src + num_threads * len, last_len, out + num_threads * len * 3 / 4, &s); sum += s; *outlen = sum; // If when decoding a whole block, we're still waiting for input then fail: if (result && (state.bytes == 0)) { return result; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/libbase64.h0000644000175100017510000001126515200142331015357 0ustar00runnerrunner#ifndef LIBBASE64_H #define LIBBASE64_H #include /* size_t */ #if defined(_WIN32) || defined(__CYGWIN__) #define BASE64_SYMBOL_IMPORT __declspec(dllimport) #define BASE64_SYMBOL_EXPORT __declspec(dllexport) #define BASE64_SYMBOL_PRIVATE #elif __GNUC__ >= 4 #define BASE64_SYMBOL_IMPORT __attribute__ ((visibility ("default"))) #define BASE64_SYMBOL_EXPORT __attribute__ ((visibility ("default"))) #define BASE64_SYMBOL_PRIVATE __attribute__ ((visibility ("hidden"))) #else #define BASE64_SYMBOL_IMPORT #define BASE64_SYMBOL_EXPORT #define BASE64_SYMBOL_PRIVATE #endif #if defined(BASE64_STATIC_DEFINE) #define BASE64_EXPORT #define BASE64_NO_EXPORT #else #if defined(BASE64_EXPORTS) // defined if we are building the shared library #define BASE64_EXPORT BASE64_SYMBOL_EXPORT #else #define BASE64_EXPORT BASE64_SYMBOL_IMPORT #endif #define BASE64_NO_EXPORT BASE64_SYMBOL_PRIVATE #endif #ifdef __cplusplus extern "C" { #endif /* These are the flags that can be passed in the `flags` argument. The values * below force the use of a given codec, even if that codec is a no-op in the * current build. Used in testing. Set to 0 for the default behavior, which is * runtime feature detection on x86, a compile-time fixed codec on ARM, and * the plain codec on other platforms: */ #define BASE64_FORCE_AVX2 (1 << 0) #define BASE64_FORCE_NEON32 (1 << 1) #define BASE64_FORCE_NEON64 (1 << 2) #define BASE64_FORCE_PLAIN (1 << 3) #define BASE64_FORCE_SSSE3 (1 << 4) #define BASE64_FORCE_SSE41 (1 << 5) #define BASE64_FORCE_SSE42 (1 << 6) #define BASE64_FORCE_AVX (1 << 7) #define BASE64_FORCE_AVX512 (1 << 8) struct base64_state { int eof; int bytes; int flags; unsigned char carry; }; /* Wrapper function to encode a plain string of given length. Output is written * to *out without trailing zero. Output length in bytes is written to *outlen. * The buffer in `out` has been allocated by the caller and is at least 4/3 the * size of the input. See above for `flags`; set to 0 for default operation: */ void BASE64_EXPORT base64_encode ( const char *src , size_t srclen , char *out , size_t *outlen , int flags ) ; /* Call this before calling base64_stream_encode() to init the state. See above * for `flags`; set to 0 for default operation: */ void BASE64_EXPORT base64_stream_encode_init ( struct base64_state *state , int flags ) ; /* Encodes the block of data of given length at `src`, into the buffer at * `out`. Caller is responsible for allocating a large enough out-buffer; it * must be at least 4/3 the size of the in-buffer, but take some margin. Places * the number of new bytes written into `outlen` (which is set to zero when the * function starts). Does not zero-terminate or finalize the output. */ void BASE64_EXPORT base64_stream_encode ( struct base64_state *state , const char *src , size_t srclen , char *out , size_t *outlen ) ; /* Finalizes the output begun by previous calls to `base64_stream_encode()`. * Adds the required end-of-stream markers if appropriate. `outlen` is modified * and will contain the number of new bytes written at `out` (which will quite * often be zero). */ void BASE64_EXPORT base64_stream_encode_final ( struct base64_state *state , char *out , size_t *outlen ) ; /* Wrapper function to decode a plain string of given length. Output is written * to *out without trailing zero. Output length in bytes is written to *outlen. * The buffer in `out` has been allocated by the caller and is at least 3/4 the * size of the input. See above for `flags`, set to 0 for default operation: */ int BASE64_EXPORT base64_decode ( const char *src , size_t srclen , char *out , size_t *outlen , int flags ) ; /* Call this before calling base64_stream_decode() to init the state. See above * for `flags`; set to 0 for default operation: */ void BASE64_EXPORT base64_stream_decode_init ( struct base64_state *state , int flags ) ; /* Decodes the block of data of given length at `src`, into the buffer at * `out`. Caller is responsible for allocating a large enough out-buffer; it * must be at least 3/4 the size of the in-buffer, but take some margin. Places * the number of new bytes written into `outlen` (which is set to zero when the * function starts). Does not zero-terminate the output. Returns 1 if all is * well, and 0 if a decoding error was found, such as an invalid character. * Returns -1 if the chosen codec is not included in the current build. Used by * the test harness to check whether a codec is available for testing. */ int BASE64_EXPORT base64_stream_decode ( struct base64_state *state , const char *src , size_t srclen , char *out , size_t *outlen ) ; #ifdef __cplusplus } #endif #endif /* LIBBASE64_H */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/librt_base64.c0000644000175100017510000002616715200142331016066 0ustar00runnerrunner#define PY_SSIZE_T_CLEAN #include #include #define BASE64_EXPORTS #include "librt_base64.h" #include "libbase64.h" #include "pythoncapi_compat.h" static PyObject * b64decode_handle_invalid_input( PyObject *out_bytes, char *outbuf, size_t max_out, const char *src, size_t srclen, bool freesrc); #define BASE64_MAXBIN ((PY_SSIZE_T_MAX - 3) / 2) #define STACK_BUFFER_SIZE 1024 static void convert_encoded_to_urlsafe(char *buf, size_t len) { // The loop is written to enable SIMD optimizations for (size_t i = 0; i < len; i++) { char ch = buf[i]; if (ch == '+') { ch = '-'; } else if (ch == '/') { ch = '_'; } buf[i] = ch; } } static void convert_urlsafe_to_encoded(const char *src, size_t len, char *buf) { // The loop is written to enable SIMD optimizations for (size_t i = 0; i < len; i++) { char ch = src[i]; if (ch == '-') { ch = '+'; } else if (ch == '_') { ch = '/'; } buf[i] = ch; } } static PyObject * b64encode_internal(PyObject *obj, bool urlsafe) { unsigned char *ascii_data; char *bin_data; int leftbits = 0; unsigned char this_ch; unsigned int leftchar = 0; Py_ssize_t bin_len, out_len; PyBytesWriter *writer; int newline = 0; // TODO if (!PyBytes_Check(obj)) { PyErr_SetString(PyExc_TypeError, "base64() expects a bytes object"); return NULL; } bin_data = PyBytes_AS_STRING(obj); bin_len = PyBytes_GET_SIZE(obj); assert(bin_len >= 0); if (bin_len > BASE64_MAXBIN) { PyErr_SetString(PyExc_ValueError, "Too much data for base64 line"); return NULL; } Py_ssize_t buflen = 4 * bin_len / 3 + 4; char *buf; char stack_buf[STACK_BUFFER_SIZE]; if (buflen <= STACK_BUFFER_SIZE) { buf = stack_buf; } else { buf = PyMem_Malloc(buflen); if (buf == NULL) { return PyErr_NoMemory(); } } size_t actual_len; base64_encode(bin_data, bin_len, buf, &actual_len, 0); if (urlsafe) { convert_encoded_to_urlsafe(buf, actual_len); } PyObject *res = PyBytes_FromStringAndSize(buf, actual_len); if (buflen > STACK_BUFFER_SIZE) PyMem_Free(buf); return res; } static PyObject* b64encode(PyObject *self, PyObject *const *args, size_t nargs) { if (nargs != 1) { PyErr_SetString(PyExc_TypeError, "b64encode() takes exactly one argument"); return 0; } return b64encode_internal(args[0], false); } static PyObject* urlsafe_b64encode(PyObject *self, PyObject *const *args, size_t nargs) { if (nargs != 1) { PyErr_SetString(PyExc_TypeError, "urlsafe_b64encode() takes exactly one argument"); return 0; } return b64encode_internal(args[0], true); } static inline int is_valid_base64_char(char c, bool allow_padding) { return ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '+') || (c == '/') || (allow_padding && c == '=')); } static PyObject * b64decode_internal(PyObject *arg, bool urlsafe) { const char *src; Py_ssize_t srclen_ssz; // Get input pointer and length if (PyBytes_Check(arg)) { src = PyBytes_AS_STRING(arg); srclen_ssz = PyBytes_GET_SIZE(arg); } else if (PyUnicode_Check(arg)) { if (!PyUnicode_IS_ASCII(arg)) { PyErr_SetString(PyExc_ValueError, "string argument should contain only ASCII characters"); return NULL; } src = (const char *)PyUnicode_1BYTE_DATA(arg); srclen_ssz = PyUnicode_GET_LENGTH(arg); } else { PyErr_SetString(PyExc_TypeError, "argument should be a bytes-like object or ASCII string"); return NULL; } // Fast-path: empty input if (srclen_ssz == 0) { return PyBytes_FromStringAndSize(NULL, 0); } if (urlsafe) { char *new_src = PyMem_Malloc(srclen_ssz + 1); if (new_src == NULL) { return PyErr_NoMemory(); } convert_urlsafe_to_encoded(src, srclen_ssz, new_src); src = new_src; } // Quickly ignore invalid characters at the end. Other invalid characters // are also accepted, but they need a slow path. while (srclen_ssz > 0 && !is_valid_base64_char(src[srclen_ssz - 1], true)) { srclen_ssz--; } // Compute an output capacity that's at least 3/4 of input, without overflow: // ceil(3/4 * N) == N - floor(N/4) size_t srclen = (size_t)srclen_ssz; size_t max_out = srclen - (srclen / 4); if (max_out == 0) { max_out = 1; // defensive (srclen > 0 implies >= 1 anyway) } if (max_out > (size_t)PY_SSIZE_T_MAX) { PyErr_SetString(PyExc_OverflowError, "input too large"); return NULL; } // Allocate output bytes (uninitialized) of the max capacity PyObject *out_bytes = PyBytes_FromStringAndSize(NULL, (Py_ssize_t)max_out); if (out_bytes == NULL) { if (urlsafe) { PyMem_Free((void *)src); } return NULL; // Propagate memory error } char *outbuf = PyBytes_AS_STRING(out_bytes); size_t outlen = max_out; int ret = base64_decode(src, srclen, outbuf, &outlen, 0); if (ret != 1) { if (ret == 0) { // Slow path: handle non-base64 input return b64decode_handle_invalid_input(out_bytes, outbuf, max_out, src, srclen, urlsafe); } Py_DECREF(out_bytes); if (urlsafe) { PyMem_Free((void *)src); } if (ret == -1) { PyErr_SetString(PyExc_NotImplementedError, "base64 codec not available in this build"); } else { PyErr_SetString(PyExc_RuntimeError, "base64_decode failed"); } return NULL; } if (urlsafe) { PyMem_Free((void *)src); } // Sanity-check contract (decoder must not overflow our buffer) if (outlen > max_out) { Py_DECREF(out_bytes); PyErr_SetString(PyExc_RuntimeError, "decoder wrote past output buffer"); return NULL; } // Shrink in place to the actual decoded length if (_PyBytes_Resize(&out_bytes, (Py_ssize_t)outlen) < 0) { // _PyBytes_Resize sets an exception and may free the old object return NULL; } return out_bytes; } // Process non-base64 input by ignoring non-base64 characters, for compatibility // with stdlib b64decode. static PyObject * b64decode_handle_invalid_input( PyObject *out_bytes, char *outbuf, size_t max_out, const char *src, size_t srclen, bool freesrc) { // Copy input to a temporary buffer, with non-base64 characters and extra suffix // characters removed size_t newbuf_len = 0; char *newbuf = PyMem_Malloc(srclen); if (newbuf == NULL) { Py_DECREF(out_bytes); if (freesrc) { PyMem_Free((void *)src); } return PyErr_NoMemory(); } int pad_chars = 0; // Copy base64 characters to the new buffer. Ignore padding to conform to RFC 4648 section 3.3. for (size_t i = 0; i < srclen; i++) { char c = src[i]; if (is_valid_base64_char(c, false)) { newbuf[newbuf_len++] = c; pad_chars = 0; } else if (c == '=') { pad_chars++; } } int quad_pos = newbuf_len % 4; // Stdlib always performs a non-strict padding check if (quad_pos != 0 && quad_pos + pad_chars < 4) { if (freesrc) { PyMem_Free((void *)src); } Py_DECREF(out_bytes); PyMem_Free(newbuf); PyErr_SetString(PyExc_ValueError, "Incorrect padding"); return NULL; } if (quad_pos != 0) { // Add padding at the end to make the input length a multiple of 4. We know that this padding // is present in src because otherwise we would report the "Incorrect padding" error above. while (quad_pos < 4) { newbuf[newbuf_len++] = '='; quad_pos++; } } size_t outlen = max_out; int ret = base64_decode(newbuf, newbuf_len, outbuf, &outlen, 0); PyMem_Free(newbuf); if (freesrc) { PyMem_Free((void *)src); } if (ret != 1) { Py_DECREF(out_bytes); if (ret == 0) { PyErr_SetString(PyExc_ValueError, "Only base64 data is allowed"); } if (ret == -1) { PyErr_SetString(PyExc_NotImplementedError, "base64 codec not available in this build"); } else { PyErr_SetString(PyExc_RuntimeError, "base64_decode failed"); } return NULL; } // Shrink in place to the actual decoded length if (_PyBytes_Resize(&out_bytes, (Py_ssize_t)outlen) < 0) { // _PyBytes_Resize sets an exception and may free the old object return NULL; } return out_bytes; } static PyObject* b64decode(PyObject *self, PyObject *const *args, size_t nargs) { if (nargs != 1) { PyErr_SetString(PyExc_TypeError, "b64decode() takes exactly one argument"); return 0; } return b64decode_internal(args[0], false); } static PyObject* urlsafe_b64decode(PyObject *self, PyObject *const *args, size_t nargs) { if (nargs != 1) { PyErr_SetString(PyExc_TypeError, "urlsafe_b64decode() takes exactly one argument"); return 0; } return b64decode_internal(args[0], true); } static PyMethodDef librt_base64_module_methods[] = { {"b64encode", (PyCFunction)b64encode, METH_FASTCALL, PyDoc_STR("Encode bytes object using Base64.")}, {"b64decode", (PyCFunction)b64decode, METH_FASTCALL, PyDoc_STR("Decode a Base64 encoded bytes object or ASCII string.")}, {"urlsafe_b64encode", (PyCFunction)urlsafe_b64encode, METH_FASTCALL, PyDoc_STR("Encode bytes object using URL and file system safe Base64 alphabet.")}, {"urlsafe_b64decode", (PyCFunction)urlsafe_b64decode, METH_FASTCALL, PyDoc_STR("Decode bytes or ASCII string using URL and file system safe Base64 alphabet.")}, {NULL, NULL, 0, NULL} }; static int base64_abi_version(void) { return LIBRT_BASE64_ABI_VERSION; } static int base64_api_version(void) { return LIBRT_BASE64_API_VERSION; } static int librt_base64_module_exec(PyObject *m) { // Export mypy internal C API, be careful with the order! static void *base64_api[LIBRT_BASE64_API_LEN] = { (void *)base64_abi_version, (void *)base64_api_version, (void *)b64encode_internal, (void *)b64decode_internal, }; PyObject *c_api_object = PyCapsule_New((void *)base64_api, "librt.base64._C_API", NULL); if (PyModule_Add(m, "_C_API", c_api_object) < 0) { return -1; } return 0; } static PyModuleDef_Slot librt_base64_module_slots[] = { {Py_mod_exec, librt_base64_module_exec}, #ifdef Py_MOD_GIL_NOT_USED {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} }; static PyModuleDef librt_base64_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "base64", .m_doc = "Fast base64 encoding and decoding optimized for mypyc", .m_size = 0, .m_methods = librt_base64_module_methods, .m_slots = librt_base64_module_slots, }; PyMODINIT_FUNC PyInit_base64(void) { return PyModuleDef_Init(&librt_base64_module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/librt_base64.h0000644000175100017510000000030415200142331016054 0ustar00runnerrunner#ifndef LIBRT_BASE64_H #define LIBRT_BASE64_H #include #define LIBRT_BASE64_ABI_VERSION 1 #define LIBRT_BASE64_API_VERSION 2 #define LIBRT_BASE64_API_LEN 4 #endif // LIBRT_BASE64_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/librt_base64_api.c0000644000175100017510000000304515200142331016705 0ustar00runnerrunner#include "librt_base64_api.h" void *LibRTBase64_API[LIBRT_BASE64_API_LEN] = {0}; int import_librt_base64(void) { PyObject *mod = PyImport_ImportModule("librt.base64"); if (mod == NULL) return -1; Py_DECREF(mod); // we import just for the side effect of making the below work. void **capsule = (void **)PyCapsule_Import("librt.base64._C_API", 0); if (capsule == NULL) return -1; // Only after version validation succeeds can we safely copy the full table. int (*abi_version)(void) = (int (*)(void))capsule[0]; int (*api_version)(void) = (int (*)(void))capsule[1]; if (abi_version() != LIBRT_BASE64_ABI_VERSION) { char err[128]; snprintf(err, sizeof(err), "ABI version conflict for librt.base64, expected %d, found %d", LIBRT_BASE64_ABI_VERSION, abi_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } if (api_version() < LIBRT_BASE64_API_VERSION) { char err[128]; snprintf(err, sizeof(err), "API version conflict for librt.base64, expected %d or newer, found %d (hint: upgrade librt)", LIBRT_BASE64_API_VERSION, api_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } // Provider API version is >= our expected version, which (by the API // compatibility contract) means it has at least LIBRT_BASE64_API_LEN // entries, so this copy is safe. memcpy(LibRTBase64_API, capsule, sizeof(LibRTBase64_API)); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/librt_base64_api.h0000644000175100017510000000105215200142331016706 0ustar00runnerrunner#ifndef LIBRT_BASE64_API_H #define LIBRT_BASE64_API_H #include "librt_base64.h" extern void *LibRTBase64_API[LIBRT_BASE64_API_LEN]; #define LibRTBase64_ABIVersion (*(int (*)(void)) LibRTBase64_API[0]) #define LibRTBase64_APIVersion (*(int (*)(void)) LibRTBase64_API[1]) #define LibRTBase64_b64encode_internal (*(PyObject* (*)(PyObject *source, bool urlsafe)) LibRTBase64_API[2]) #define LibRTBase64_b64decode_internal (*(PyObject* (*)(PyObject *source, bool urlsafe)) LibRTBase64_API[3]) int import_librt_base64(void); #endif // LIBRT_BASE64_API_H ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8545365 librt-0.11.0/base64/tables/0000755000175100017510000000000015200142335014704 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/tables/table_dec_32bit.h0000644000175100017510000006125215200142331017764 0ustar00runnerrunner#include #define CHAR62 '+' #define CHAR63 '/' #define CHARPAD '=' #if BASE64_LITTLE_ENDIAN /* SPECIAL DECODE TABLES FOR LITTLE ENDIAN (INTEL) CPUS */ const uint32_t base64_table_dec_32bit_d0[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000000f8, 0xffffffff, 0xffffffff, 0xffffffff, 0x000000fc, 0x000000d0, 0x000000d4, 0x000000d8, 0x000000dc, 0x000000e0, 0x000000e4, 0x000000e8, 0x000000ec, 0x000000f0, 0x000000f4, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000004, 0x00000008, 0x0000000c, 0x00000010, 0x00000014, 0x00000018, 0x0000001c, 0x00000020, 0x00000024, 0x00000028, 0x0000002c, 0x00000030, 0x00000034, 0x00000038, 0x0000003c, 0x00000040, 0x00000044, 0x00000048, 0x0000004c, 0x00000050, 0x00000054, 0x00000058, 0x0000005c, 0x00000060, 0x00000064, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000068, 0x0000006c, 0x00000070, 0x00000074, 0x00000078, 0x0000007c, 0x00000080, 0x00000084, 0x00000088, 0x0000008c, 0x00000090, 0x00000094, 0x00000098, 0x0000009c, 0x000000a0, 0x000000a4, 0x000000a8, 0x000000ac, 0x000000b0, 0x000000b4, 0x000000b8, 0x000000bc, 0x000000c0, 0x000000c4, 0x000000c8, 0x000000cc, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d1[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000e003, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000f003, 0x00004003, 0x00005003, 0x00006003, 0x00007003, 0x00008003, 0x00009003, 0x0000a003, 0x0000b003, 0x0000c003, 0x0000d003, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00001000, 0x00002000, 0x00003000, 0x00004000, 0x00005000, 0x00006000, 0x00007000, 0x00008000, 0x00009000, 0x0000a000, 0x0000b000, 0x0000c000, 0x0000d000, 0x0000e000, 0x0000f000, 0x00000001, 0x00001001, 0x00002001, 0x00003001, 0x00004001, 0x00005001, 0x00006001, 0x00007001, 0x00008001, 0x00009001, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x0000a001, 0x0000b001, 0x0000c001, 0x0000d001, 0x0000e001, 0x0000f001, 0x00000002, 0x00001002, 0x00002002, 0x00003002, 0x00004002, 0x00005002, 0x00006002, 0x00007002, 0x00008002, 0x00009002, 0x0000a002, 0x0000b002, 0x0000c002, 0x0000d002, 0x0000e002, 0x0000f002, 0x00000003, 0x00001003, 0x00002003, 0x00003003, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d2[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00800f00, 0xffffffff, 0xffffffff, 0xffffffff, 0x00c00f00, 0x00000d00, 0x00400d00, 0x00800d00, 0x00c00d00, 0x00000e00, 0x00400e00, 0x00800e00, 0x00c00e00, 0x00000f00, 0x00400f00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00400000, 0x00800000, 0x00c00000, 0x00000100, 0x00400100, 0x00800100, 0x00c00100, 0x00000200, 0x00400200, 0x00800200, 0x00c00200, 0x00000300, 0x00400300, 0x00800300, 0x00c00300, 0x00000400, 0x00400400, 0x00800400, 0x00c00400, 0x00000500, 0x00400500, 0x00800500, 0x00c00500, 0x00000600, 0x00400600, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00800600, 0x00c00600, 0x00000700, 0x00400700, 0x00800700, 0x00c00700, 0x00000800, 0x00400800, 0x00800800, 0x00c00800, 0x00000900, 0x00400900, 0x00800900, 0x00c00900, 0x00000a00, 0x00400a00, 0x00800a00, 0x00c00a00, 0x00000b00, 0x00400b00, 0x00800b00, 0x00c00b00, 0x00000c00, 0x00400c00, 0x00800c00, 0x00c00c00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d3[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x003e0000, 0xffffffff, 0xffffffff, 0xffffffff, 0x003f0000, 0x00340000, 0x00350000, 0x00360000, 0x00370000, 0x00380000, 0x00390000, 0x003a0000, 0x003b0000, 0x003c0000, 0x003d0000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00010000, 0x00020000, 0x00030000, 0x00040000, 0x00050000, 0x00060000, 0x00070000, 0x00080000, 0x00090000, 0x000a0000, 0x000b0000, 0x000c0000, 0x000d0000, 0x000e0000, 0x000f0000, 0x00100000, 0x00110000, 0x00120000, 0x00130000, 0x00140000, 0x00150000, 0x00160000, 0x00170000, 0x00180000, 0x00190000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x001a0000, 0x001b0000, 0x001c0000, 0x001d0000, 0x001e0000, 0x001f0000, 0x00200000, 0x00210000, 0x00220000, 0x00230000, 0x00240000, 0x00250000, 0x00260000, 0x00270000, 0x00280000, 0x00290000, 0x002a0000, 0x002b0000, 0x002c0000, 0x002d0000, 0x002e0000, 0x002f0000, 0x00300000, 0x00310000, 0x00320000, 0x00330000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; #else /* SPECIAL DECODE TABLES FOR BIG ENDIAN (IBM/MOTOROLA/SUN) CPUS */ const uint32_t base64_table_dec_32bit_d0[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xf8000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xfc000000, 0xd0000000, 0xd4000000, 0xd8000000, 0xdc000000, 0xe0000000, 0xe4000000, 0xe8000000, 0xec000000, 0xf0000000, 0xf4000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x04000000, 0x08000000, 0x0c000000, 0x10000000, 0x14000000, 0x18000000, 0x1c000000, 0x20000000, 0x24000000, 0x28000000, 0x2c000000, 0x30000000, 0x34000000, 0x38000000, 0x3c000000, 0x40000000, 0x44000000, 0x48000000, 0x4c000000, 0x50000000, 0x54000000, 0x58000000, 0x5c000000, 0x60000000, 0x64000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x68000000, 0x6c000000, 0x70000000, 0x74000000, 0x78000000, 0x7c000000, 0x80000000, 0x84000000, 0x88000000, 0x8c000000, 0x90000000, 0x94000000, 0x98000000, 0x9c000000, 0xa0000000, 0xa4000000, 0xa8000000, 0xac000000, 0xb0000000, 0xb4000000, 0xb8000000, 0xbc000000, 0xc0000000, 0xc4000000, 0xc8000000, 0xcc000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d1[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x03e00000, 0xffffffff, 0xffffffff, 0xffffffff, 0x03f00000, 0x03400000, 0x03500000, 0x03600000, 0x03700000, 0x03800000, 0x03900000, 0x03a00000, 0x03b00000, 0x03c00000, 0x03d00000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00100000, 0x00200000, 0x00300000, 0x00400000, 0x00500000, 0x00600000, 0x00700000, 0x00800000, 0x00900000, 0x00a00000, 0x00b00000, 0x00c00000, 0x00d00000, 0x00e00000, 0x00f00000, 0x01000000, 0x01100000, 0x01200000, 0x01300000, 0x01400000, 0x01500000, 0x01600000, 0x01700000, 0x01800000, 0x01900000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x01a00000, 0x01b00000, 0x01c00000, 0x01d00000, 0x01e00000, 0x01f00000, 0x02000000, 0x02100000, 0x02200000, 0x02300000, 0x02400000, 0x02500000, 0x02600000, 0x02700000, 0x02800000, 0x02900000, 0x02a00000, 0x02b00000, 0x02c00000, 0x02d00000, 0x02e00000, 0x02f00000, 0x03000000, 0x03100000, 0x03200000, 0x03300000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d2[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x000f8000, 0xffffffff, 0xffffffff, 0xffffffff, 0x000fc000, 0x000d0000, 0x000d4000, 0x000d8000, 0x000dc000, 0x000e0000, 0x000e4000, 0x000e8000, 0x000ec000, 0x000f0000, 0x000f4000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00004000, 0x00008000, 0x0000c000, 0x00010000, 0x00014000, 0x00018000, 0x0001c000, 0x00020000, 0x00024000, 0x00028000, 0x0002c000, 0x00030000, 0x00034000, 0x00038000, 0x0003c000, 0x00040000, 0x00044000, 0x00048000, 0x0004c000, 0x00050000, 0x00054000, 0x00058000, 0x0005c000, 0x00060000, 0x00064000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00068000, 0x0006c000, 0x00070000, 0x00074000, 0x00078000, 0x0007c000, 0x00080000, 0x00084000, 0x00088000, 0x0008c000, 0x00090000, 0x00094000, 0x00098000, 0x0009c000, 0x000a0000, 0x000a4000, 0x000a8000, 0x000ac000, 0x000b0000, 0x000b4000, 0x000b8000, 0x000bc000, 0x000c0000, 0x000c4000, 0x000c8000, 0x000cc000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; const uint32_t base64_table_dec_32bit_d3[256] = { 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00003e00, 0xffffffff, 0xffffffff, 0xffffffff, 0x00003f00, 0x00003400, 0x00003500, 0x00003600, 0x00003700, 0x00003800, 0x00003900, 0x00003a00, 0x00003b00, 0x00003c00, 0x00003d00, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000100, 0x00000200, 0x00000300, 0x00000400, 0x00000500, 0x00000600, 0x00000700, 0x00000800, 0x00000900, 0x00000a00, 0x00000b00, 0x00000c00, 0x00000d00, 0x00000e00, 0x00000f00, 0x00001000, 0x00001100, 0x00001200, 0x00001300, 0x00001400, 0x00001500, 0x00001600, 0x00001700, 0x00001800, 0x00001900, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00001a00, 0x00001b00, 0x00001c00, 0x00001d00, 0x00001e00, 0x00001f00, 0x00002000, 0x00002100, 0x00002200, 0x00002300, 0x00002400, 0x00002500, 0x00002600, 0x00002700, 0x00002800, 0x00002900, 0x00002a00, 0x00002b00, 0x00002c00, 0x00002d00, 0x00002e00, 0x00002f00, 0x00003000, 0x00003100, 0x00003200, 0x00003300, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff }; #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/tables/table_enc_12bit.h0000644000175100017510000022215215200142331017772 0ustar00runnerrunner#include const uint16_t base64_table_enc_12bit[] = { #if BASE64_LITTLE_ENDIAN 0x4141U, 0x4241U, 0x4341U, 0x4441U, 0x4541U, 0x4641U, 0x4741U, 0x4841U, 0x4941U, 0x4A41U, 0x4B41U, 0x4C41U, 0x4D41U, 0x4E41U, 0x4F41U, 0x5041U, 0x5141U, 0x5241U, 0x5341U, 0x5441U, 0x5541U, 0x5641U, 0x5741U, 0x5841U, 0x5941U, 0x5A41U, 0x6141U, 0x6241U, 0x6341U, 0x6441U, 0x6541U, 0x6641U, 0x6741U, 0x6841U, 0x6941U, 0x6A41U, 0x6B41U, 0x6C41U, 0x6D41U, 0x6E41U, 0x6F41U, 0x7041U, 0x7141U, 0x7241U, 0x7341U, 0x7441U, 0x7541U, 0x7641U, 0x7741U, 0x7841U, 0x7941U, 0x7A41U, 0x3041U, 0x3141U, 0x3241U, 0x3341U, 0x3441U, 0x3541U, 0x3641U, 0x3741U, 0x3841U, 0x3941U, 0x2B41U, 0x2F41U, 0x4142U, 0x4242U, 0x4342U, 0x4442U, 0x4542U, 0x4642U, 0x4742U, 0x4842U, 0x4942U, 0x4A42U, 0x4B42U, 0x4C42U, 0x4D42U, 0x4E42U, 0x4F42U, 0x5042U, 0x5142U, 0x5242U, 0x5342U, 0x5442U, 0x5542U, 0x5642U, 0x5742U, 0x5842U, 0x5942U, 0x5A42U, 0x6142U, 0x6242U, 0x6342U, 0x6442U, 0x6542U, 0x6642U, 0x6742U, 0x6842U, 0x6942U, 0x6A42U, 0x6B42U, 0x6C42U, 0x6D42U, 0x6E42U, 0x6F42U, 0x7042U, 0x7142U, 0x7242U, 0x7342U, 0x7442U, 0x7542U, 0x7642U, 0x7742U, 0x7842U, 0x7942U, 0x7A42U, 0x3042U, 0x3142U, 0x3242U, 0x3342U, 0x3442U, 0x3542U, 0x3642U, 0x3742U, 0x3842U, 0x3942U, 0x2B42U, 0x2F42U, 0x4143U, 0x4243U, 0x4343U, 0x4443U, 0x4543U, 0x4643U, 0x4743U, 0x4843U, 0x4943U, 0x4A43U, 0x4B43U, 0x4C43U, 0x4D43U, 0x4E43U, 0x4F43U, 0x5043U, 0x5143U, 0x5243U, 0x5343U, 0x5443U, 0x5543U, 0x5643U, 0x5743U, 0x5843U, 0x5943U, 0x5A43U, 0x6143U, 0x6243U, 0x6343U, 0x6443U, 0x6543U, 0x6643U, 0x6743U, 0x6843U, 0x6943U, 0x6A43U, 0x6B43U, 0x6C43U, 0x6D43U, 0x6E43U, 0x6F43U, 0x7043U, 0x7143U, 0x7243U, 0x7343U, 0x7443U, 0x7543U, 0x7643U, 0x7743U, 0x7843U, 0x7943U, 0x7A43U, 0x3043U, 0x3143U, 0x3243U, 0x3343U, 0x3443U, 0x3543U, 0x3643U, 0x3743U, 0x3843U, 0x3943U, 0x2B43U, 0x2F43U, 0x4144U, 0x4244U, 0x4344U, 0x4444U, 0x4544U, 0x4644U, 0x4744U, 0x4844U, 0x4944U, 0x4A44U, 0x4B44U, 0x4C44U, 0x4D44U, 0x4E44U, 0x4F44U, 0x5044U, 0x5144U, 0x5244U, 0x5344U, 0x5444U, 0x5544U, 0x5644U, 0x5744U, 0x5844U, 0x5944U, 0x5A44U, 0x6144U, 0x6244U, 0x6344U, 0x6444U, 0x6544U, 0x6644U, 0x6744U, 0x6844U, 0x6944U, 0x6A44U, 0x6B44U, 0x6C44U, 0x6D44U, 0x6E44U, 0x6F44U, 0x7044U, 0x7144U, 0x7244U, 0x7344U, 0x7444U, 0x7544U, 0x7644U, 0x7744U, 0x7844U, 0x7944U, 0x7A44U, 0x3044U, 0x3144U, 0x3244U, 0x3344U, 0x3444U, 0x3544U, 0x3644U, 0x3744U, 0x3844U, 0x3944U, 0x2B44U, 0x2F44U, 0x4145U, 0x4245U, 0x4345U, 0x4445U, 0x4545U, 0x4645U, 0x4745U, 0x4845U, 0x4945U, 0x4A45U, 0x4B45U, 0x4C45U, 0x4D45U, 0x4E45U, 0x4F45U, 0x5045U, 0x5145U, 0x5245U, 0x5345U, 0x5445U, 0x5545U, 0x5645U, 0x5745U, 0x5845U, 0x5945U, 0x5A45U, 0x6145U, 0x6245U, 0x6345U, 0x6445U, 0x6545U, 0x6645U, 0x6745U, 0x6845U, 0x6945U, 0x6A45U, 0x6B45U, 0x6C45U, 0x6D45U, 0x6E45U, 0x6F45U, 0x7045U, 0x7145U, 0x7245U, 0x7345U, 0x7445U, 0x7545U, 0x7645U, 0x7745U, 0x7845U, 0x7945U, 0x7A45U, 0x3045U, 0x3145U, 0x3245U, 0x3345U, 0x3445U, 0x3545U, 0x3645U, 0x3745U, 0x3845U, 0x3945U, 0x2B45U, 0x2F45U, 0x4146U, 0x4246U, 0x4346U, 0x4446U, 0x4546U, 0x4646U, 0x4746U, 0x4846U, 0x4946U, 0x4A46U, 0x4B46U, 0x4C46U, 0x4D46U, 0x4E46U, 0x4F46U, 0x5046U, 0x5146U, 0x5246U, 0x5346U, 0x5446U, 0x5546U, 0x5646U, 0x5746U, 0x5846U, 0x5946U, 0x5A46U, 0x6146U, 0x6246U, 0x6346U, 0x6446U, 0x6546U, 0x6646U, 0x6746U, 0x6846U, 0x6946U, 0x6A46U, 0x6B46U, 0x6C46U, 0x6D46U, 0x6E46U, 0x6F46U, 0x7046U, 0x7146U, 0x7246U, 0x7346U, 0x7446U, 0x7546U, 0x7646U, 0x7746U, 0x7846U, 0x7946U, 0x7A46U, 0x3046U, 0x3146U, 0x3246U, 0x3346U, 0x3446U, 0x3546U, 0x3646U, 0x3746U, 0x3846U, 0x3946U, 0x2B46U, 0x2F46U, 0x4147U, 0x4247U, 0x4347U, 0x4447U, 0x4547U, 0x4647U, 0x4747U, 0x4847U, 0x4947U, 0x4A47U, 0x4B47U, 0x4C47U, 0x4D47U, 0x4E47U, 0x4F47U, 0x5047U, 0x5147U, 0x5247U, 0x5347U, 0x5447U, 0x5547U, 0x5647U, 0x5747U, 0x5847U, 0x5947U, 0x5A47U, 0x6147U, 0x6247U, 0x6347U, 0x6447U, 0x6547U, 0x6647U, 0x6747U, 0x6847U, 0x6947U, 0x6A47U, 0x6B47U, 0x6C47U, 0x6D47U, 0x6E47U, 0x6F47U, 0x7047U, 0x7147U, 0x7247U, 0x7347U, 0x7447U, 0x7547U, 0x7647U, 0x7747U, 0x7847U, 0x7947U, 0x7A47U, 0x3047U, 0x3147U, 0x3247U, 0x3347U, 0x3447U, 0x3547U, 0x3647U, 0x3747U, 0x3847U, 0x3947U, 0x2B47U, 0x2F47U, 0x4148U, 0x4248U, 0x4348U, 0x4448U, 0x4548U, 0x4648U, 0x4748U, 0x4848U, 0x4948U, 0x4A48U, 0x4B48U, 0x4C48U, 0x4D48U, 0x4E48U, 0x4F48U, 0x5048U, 0x5148U, 0x5248U, 0x5348U, 0x5448U, 0x5548U, 0x5648U, 0x5748U, 0x5848U, 0x5948U, 0x5A48U, 0x6148U, 0x6248U, 0x6348U, 0x6448U, 0x6548U, 0x6648U, 0x6748U, 0x6848U, 0x6948U, 0x6A48U, 0x6B48U, 0x6C48U, 0x6D48U, 0x6E48U, 0x6F48U, 0x7048U, 0x7148U, 0x7248U, 0x7348U, 0x7448U, 0x7548U, 0x7648U, 0x7748U, 0x7848U, 0x7948U, 0x7A48U, 0x3048U, 0x3148U, 0x3248U, 0x3348U, 0x3448U, 0x3548U, 0x3648U, 0x3748U, 0x3848U, 0x3948U, 0x2B48U, 0x2F48U, 0x4149U, 0x4249U, 0x4349U, 0x4449U, 0x4549U, 0x4649U, 0x4749U, 0x4849U, 0x4949U, 0x4A49U, 0x4B49U, 0x4C49U, 0x4D49U, 0x4E49U, 0x4F49U, 0x5049U, 0x5149U, 0x5249U, 0x5349U, 0x5449U, 0x5549U, 0x5649U, 0x5749U, 0x5849U, 0x5949U, 0x5A49U, 0x6149U, 0x6249U, 0x6349U, 0x6449U, 0x6549U, 0x6649U, 0x6749U, 0x6849U, 0x6949U, 0x6A49U, 0x6B49U, 0x6C49U, 0x6D49U, 0x6E49U, 0x6F49U, 0x7049U, 0x7149U, 0x7249U, 0x7349U, 0x7449U, 0x7549U, 0x7649U, 0x7749U, 0x7849U, 0x7949U, 0x7A49U, 0x3049U, 0x3149U, 0x3249U, 0x3349U, 0x3449U, 0x3549U, 0x3649U, 0x3749U, 0x3849U, 0x3949U, 0x2B49U, 0x2F49U, 0x414AU, 0x424AU, 0x434AU, 0x444AU, 0x454AU, 0x464AU, 0x474AU, 0x484AU, 0x494AU, 0x4A4AU, 0x4B4AU, 0x4C4AU, 0x4D4AU, 0x4E4AU, 0x4F4AU, 0x504AU, 0x514AU, 0x524AU, 0x534AU, 0x544AU, 0x554AU, 0x564AU, 0x574AU, 0x584AU, 0x594AU, 0x5A4AU, 0x614AU, 0x624AU, 0x634AU, 0x644AU, 0x654AU, 0x664AU, 0x674AU, 0x684AU, 0x694AU, 0x6A4AU, 0x6B4AU, 0x6C4AU, 0x6D4AU, 0x6E4AU, 0x6F4AU, 0x704AU, 0x714AU, 0x724AU, 0x734AU, 0x744AU, 0x754AU, 0x764AU, 0x774AU, 0x784AU, 0x794AU, 0x7A4AU, 0x304AU, 0x314AU, 0x324AU, 0x334AU, 0x344AU, 0x354AU, 0x364AU, 0x374AU, 0x384AU, 0x394AU, 0x2B4AU, 0x2F4AU, 0x414BU, 0x424BU, 0x434BU, 0x444BU, 0x454BU, 0x464BU, 0x474BU, 0x484BU, 0x494BU, 0x4A4BU, 0x4B4BU, 0x4C4BU, 0x4D4BU, 0x4E4BU, 0x4F4BU, 0x504BU, 0x514BU, 0x524BU, 0x534BU, 0x544BU, 0x554BU, 0x564BU, 0x574BU, 0x584BU, 0x594BU, 0x5A4BU, 0x614BU, 0x624BU, 0x634BU, 0x644BU, 0x654BU, 0x664BU, 0x674BU, 0x684BU, 0x694BU, 0x6A4BU, 0x6B4BU, 0x6C4BU, 0x6D4BU, 0x6E4BU, 0x6F4BU, 0x704BU, 0x714BU, 0x724BU, 0x734BU, 0x744BU, 0x754BU, 0x764BU, 0x774BU, 0x784BU, 0x794BU, 0x7A4BU, 0x304BU, 0x314BU, 0x324BU, 0x334BU, 0x344BU, 0x354BU, 0x364BU, 0x374BU, 0x384BU, 0x394BU, 0x2B4BU, 0x2F4BU, 0x414CU, 0x424CU, 0x434CU, 0x444CU, 0x454CU, 0x464CU, 0x474CU, 0x484CU, 0x494CU, 0x4A4CU, 0x4B4CU, 0x4C4CU, 0x4D4CU, 0x4E4CU, 0x4F4CU, 0x504CU, 0x514CU, 0x524CU, 0x534CU, 0x544CU, 0x554CU, 0x564CU, 0x574CU, 0x584CU, 0x594CU, 0x5A4CU, 0x614CU, 0x624CU, 0x634CU, 0x644CU, 0x654CU, 0x664CU, 0x674CU, 0x684CU, 0x694CU, 0x6A4CU, 0x6B4CU, 0x6C4CU, 0x6D4CU, 0x6E4CU, 0x6F4CU, 0x704CU, 0x714CU, 0x724CU, 0x734CU, 0x744CU, 0x754CU, 0x764CU, 0x774CU, 0x784CU, 0x794CU, 0x7A4CU, 0x304CU, 0x314CU, 0x324CU, 0x334CU, 0x344CU, 0x354CU, 0x364CU, 0x374CU, 0x384CU, 0x394CU, 0x2B4CU, 0x2F4CU, 0x414DU, 0x424DU, 0x434DU, 0x444DU, 0x454DU, 0x464DU, 0x474DU, 0x484DU, 0x494DU, 0x4A4DU, 0x4B4DU, 0x4C4DU, 0x4D4DU, 0x4E4DU, 0x4F4DU, 0x504DU, 0x514DU, 0x524DU, 0x534DU, 0x544DU, 0x554DU, 0x564DU, 0x574DU, 0x584DU, 0x594DU, 0x5A4DU, 0x614DU, 0x624DU, 0x634DU, 0x644DU, 0x654DU, 0x664DU, 0x674DU, 0x684DU, 0x694DU, 0x6A4DU, 0x6B4DU, 0x6C4DU, 0x6D4DU, 0x6E4DU, 0x6F4DU, 0x704DU, 0x714DU, 0x724DU, 0x734DU, 0x744DU, 0x754DU, 0x764DU, 0x774DU, 0x784DU, 0x794DU, 0x7A4DU, 0x304DU, 0x314DU, 0x324DU, 0x334DU, 0x344DU, 0x354DU, 0x364DU, 0x374DU, 0x384DU, 0x394DU, 0x2B4DU, 0x2F4DU, 0x414EU, 0x424EU, 0x434EU, 0x444EU, 0x454EU, 0x464EU, 0x474EU, 0x484EU, 0x494EU, 0x4A4EU, 0x4B4EU, 0x4C4EU, 0x4D4EU, 0x4E4EU, 0x4F4EU, 0x504EU, 0x514EU, 0x524EU, 0x534EU, 0x544EU, 0x554EU, 0x564EU, 0x574EU, 0x584EU, 0x594EU, 0x5A4EU, 0x614EU, 0x624EU, 0x634EU, 0x644EU, 0x654EU, 0x664EU, 0x674EU, 0x684EU, 0x694EU, 0x6A4EU, 0x6B4EU, 0x6C4EU, 0x6D4EU, 0x6E4EU, 0x6F4EU, 0x704EU, 0x714EU, 0x724EU, 0x734EU, 0x744EU, 0x754EU, 0x764EU, 0x774EU, 0x784EU, 0x794EU, 0x7A4EU, 0x304EU, 0x314EU, 0x324EU, 0x334EU, 0x344EU, 0x354EU, 0x364EU, 0x374EU, 0x384EU, 0x394EU, 0x2B4EU, 0x2F4EU, 0x414FU, 0x424FU, 0x434FU, 0x444FU, 0x454FU, 0x464FU, 0x474FU, 0x484FU, 0x494FU, 0x4A4FU, 0x4B4FU, 0x4C4FU, 0x4D4FU, 0x4E4FU, 0x4F4FU, 0x504FU, 0x514FU, 0x524FU, 0x534FU, 0x544FU, 0x554FU, 0x564FU, 0x574FU, 0x584FU, 0x594FU, 0x5A4FU, 0x614FU, 0x624FU, 0x634FU, 0x644FU, 0x654FU, 0x664FU, 0x674FU, 0x684FU, 0x694FU, 0x6A4FU, 0x6B4FU, 0x6C4FU, 0x6D4FU, 0x6E4FU, 0x6F4FU, 0x704FU, 0x714FU, 0x724FU, 0x734FU, 0x744FU, 0x754FU, 0x764FU, 0x774FU, 0x784FU, 0x794FU, 0x7A4FU, 0x304FU, 0x314FU, 0x324FU, 0x334FU, 0x344FU, 0x354FU, 0x364FU, 0x374FU, 0x384FU, 0x394FU, 0x2B4FU, 0x2F4FU, 0x4150U, 0x4250U, 0x4350U, 0x4450U, 0x4550U, 0x4650U, 0x4750U, 0x4850U, 0x4950U, 0x4A50U, 0x4B50U, 0x4C50U, 0x4D50U, 0x4E50U, 0x4F50U, 0x5050U, 0x5150U, 0x5250U, 0x5350U, 0x5450U, 0x5550U, 0x5650U, 0x5750U, 0x5850U, 0x5950U, 0x5A50U, 0x6150U, 0x6250U, 0x6350U, 0x6450U, 0x6550U, 0x6650U, 0x6750U, 0x6850U, 0x6950U, 0x6A50U, 0x6B50U, 0x6C50U, 0x6D50U, 0x6E50U, 0x6F50U, 0x7050U, 0x7150U, 0x7250U, 0x7350U, 0x7450U, 0x7550U, 0x7650U, 0x7750U, 0x7850U, 0x7950U, 0x7A50U, 0x3050U, 0x3150U, 0x3250U, 0x3350U, 0x3450U, 0x3550U, 0x3650U, 0x3750U, 0x3850U, 0x3950U, 0x2B50U, 0x2F50U, 0x4151U, 0x4251U, 0x4351U, 0x4451U, 0x4551U, 0x4651U, 0x4751U, 0x4851U, 0x4951U, 0x4A51U, 0x4B51U, 0x4C51U, 0x4D51U, 0x4E51U, 0x4F51U, 0x5051U, 0x5151U, 0x5251U, 0x5351U, 0x5451U, 0x5551U, 0x5651U, 0x5751U, 0x5851U, 0x5951U, 0x5A51U, 0x6151U, 0x6251U, 0x6351U, 0x6451U, 0x6551U, 0x6651U, 0x6751U, 0x6851U, 0x6951U, 0x6A51U, 0x6B51U, 0x6C51U, 0x6D51U, 0x6E51U, 0x6F51U, 0x7051U, 0x7151U, 0x7251U, 0x7351U, 0x7451U, 0x7551U, 0x7651U, 0x7751U, 0x7851U, 0x7951U, 0x7A51U, 0x3051U, 0x3151U, 0x3251U, 0x3351U, 0x3451U, 0x3551U, 0x3651U, 0x3751U, 0x3851U, 0x3951U, 0x2B51U, 0x2F51U, 0x4152U, 0x4252U, 0x4352U, 0x4452U, 0x4552U, 0x4652U, 0x4752U, 0x4852U, 0x4952U, 0x4A52U, 0x4B52U, 0x4C52U, 0x4D52U, 0x4E52U, 0x4F52U, 0x5052U, 0x5152U, 0x5252U, 0x5352U, 0x5452U, 0x5552U, 0x5652U, 0x5752U, 0x5852U, 0x5952U, 0x5A52U, 0x6152U, 0x6252U, 0x6352U, 0x6452U, 0x6552U, 0x6652U, 0x6752U, 0x6852U, 0x6952U, 0x6A52U, 0x6B52U, 0x6C52U, 0x6D52U, 0x6E52U, 0x6F52U, 0x7052U, 0x7152U, 0x7252U, 0x7352U, 0x7452U, 0x7552U, 0x7652U, 0x7752U, 0x7852U, 0x7952U, 0x7A52U, 0x3052U, 0x3152U, 0x3252U, 0x3352U, 0x3452U, 0x3552U, 0x3652U, 0x3752U, 0x3852U, 0x3952U, 0x2B52U, 0x2F52U, 0x4153U, 0x4253U, 0x4353U, 0x4453U, 0x4553U, 0x4653U, 0x4753U, 0x4853U, 0x4953U, 0x4A53U, 0x4B53U, 0x4C53U, 0x4D53U, 0x4E53U, 0x4F53U, 0x5053U, 0x5153U, 0x5253U, 0x5353U, 0x5453U, 0x5553U, 0x5653U, 0x5753U, 0x5853U, 0x5953U, 0x5A53U, 0x6153U, 0x6253U, 0x6353U, 0x6453U, 0x6553U, 0x6653U, 0x6753U, 0x6853U, 0x6953U, 0x6A53U, 0x6B53U, 0x6C53U, 0x6D53U, 0x6E53U, 0x6F53U, 0x7053U, 0x7153U, 0x7253U, 0x7353U, 0x7453U, 0x7553U, 0x7653U, 0x7753U, 0x7853U, 0x7953U, 0x7A53U, 0x3053U, 0x3153U, 0x3253U, 0x3353U, 0x3453U, 0x3553U, 0x3653U, 0x3753U, 0x3853U, 0x3953U, 0x2B53U, 0x2F53U, 0x4154U, 0x4254U, 0x4354U, 0x4454U, 0x4554U, 0x4654U, 0x4754U, 0x4854U, 0x4954U, 0x4A54U, 0x4B54U, 0x4C54U, 0x4D54U, 0x4E54U, 0x4F54U, 0x5054U, 0x5154U, 0x5254U, 0x5354U, 0x5454U, 0x5554U, 0x5654U, 0x5754U, 0x5854U, 0x5954U, 0x5A54U, 0x6154U, 0x6254U, 0x6354U, 0x6454U, 0x6554U, 0x6654U, 0x6754U, 0x6854U, 0x6954U, 0x6A54U, 0x6B54U, 0x6C54U, 0x6D54U, 0x6E54U, 0x6F54U, 0x7054U, 0x7154U, 0x7254U, 0x7354U, 0x7454U, 0x7554U, 0x7654U, 0x7754U, 0x7854U, 0x7954U, 0x7A54U, 0x3054U, 0x3154U, 0x3254U, 0x3354U, 0x3454U, 0x3554U, 0x3654U, 0x3754U, 0x3854U, 0x3954U, 0x2B54U, 0x2F54U, 0x4155U, 0x4255U, 0x4355U, 0x4455U, 0x4555U, 0x4655U, 0x4755U, 0x4855U, 0x4955U, 0x4A55U, 0x4B55U, 0x4C55U, 0x4D55U, 0x4E55U, 0x4F55U, 0x5055U, 0x5155U, 0x5255U, 0x5355U, 0x5455U, 0x5555U, 0x5655U, 0x5755U, 0x5855U, 0x5955U, 0x5A55U, 0x6155U, 0x6255U, 0x6355U, 0x6455U, 0x6555U, 0x6655U, 0x6755U, 0x6855U, 0x6955U, 0x6A55U, 0x6B55U, 0x6C55U, 0x6D55U, 0x6E55U, 0x6F55U, 0x7055U, 0x7155U, 0x7255U, 0x7355U, 0x7455U, 0x7555U, 0x7655U, 0x7755U, 0x7855U, 0x7955U, 0x7A55U, 0x3055U, 0x3155U, 0x3255U, 0x3355U, 0x3455U, 0x3555U, 0x3655U, 0x3755U, 0x3855U, 0x3955U, 0x2B55U, 0x2F55U, 0x4156U, 0x4256U, 0x4356U, 0x4456U, 0x4556U, 0x4656U, 0x4756U, 0x4856U, 0x4956U, 0x4A56U, 0x4B56U, 0x4C56U, 0x4D56U, 0x4E56U, 0x4F56U, 0x5056U, 0x5156U, 0x5256U, 0x5356U, 0x5456U, 0x5556U, 0x5656U, 0x5756U, 0x5856U, 0x5956U, 0x5A56U, 0x6156U, 0x6256U, 0x6356U, 0x6456U, 0x6556U, 0x6656U, 0x6756U, 0x6856U, 0x6956U, 0x6A56U, 0x6B56U, 0x6C56U, 0x6D56U, 0x6E56U, 0x6F56U, 0x7056U, 0x7156U, 0x7256U, 0x7356U, 0x7456U, 0x7556U, 0x7656U, 0x7756U, 0x7856U, 0x7956U, 0x7A56U, 0x3056U, 0x3156U, 0x3256U, 0x3356U, 0x3456U, 0x3556U, 0x3656U, 0x3756U, 0x3856U, 0x3956U, 0x2B56U, 0x2F56U, 0x4157U, 0x4257U, 0x4357U, 0x4457U, 0x4557U, 0x4657U, 0x4757U, 0x4857U, 0x4957U, 0x4A57U, 0x4B57U, 0x4C57U, 0x4D57U, 0x4E57U, 0x4F57U, 0x5057U, 0x5157U, 0x5257U, 0x5357U, 0x5457U, 0x5557U, 0x5657U, 0x5757U, 0x5857U, 0x5957U, 0x5A57U, 0x6157U, 0x6257U, 0x6357U, 0x6457U, 0x6557U, 0x6657U, 0x6757U, 0x6857U, 0x6957U, 0x6A57U, 0x6B57U, 0x6C57U, 0x6D57U, 0x6E57U, 0x6F57U, 0x7057U, 0x7157U, 0x7257U, 0x7357U, 0x7457U, 0x7557U, 0x7657U, 0x7757U, 0x7857U, 0x7957U, 0x7A57U, 0x3057U, 0x3157U, 0x3257U, 0x3357U, 0x3457U, 0x3557U, 0x3657U, 0x3757U, 0x3857U, 0x3957U, 0x2B57U, 0x2F57U, 0x4158U, 0x4258U, 0x4358U, 0x4458U, 0x4558U, 0x4658U, 0x4758U, 0x4858U, 0x4958U, 0x4A58U, 0x4B58U, 0x4C58U, 0x4D58U, 0x4E58U, 0x4F58U, 0x5058U, 0x5158U, 0x5258U, 0x5358U, 0x5458U, 0x5558U, 0x5658U, 0x5758U, 0x5858U, 0x5958U, 0x5A58U, 0x6158U, 0x6258U, 0x6358U, 0x6458U, 0x6558U, 0x6658U, 0x6758U, 0x6858U, 0x6958U, 0x6A58U, 0x6B58U, 0x6C58U, 0x6D58U, 0x6E58U, 0x6F58U, 0x7058U, 0x7158U, 0x7258U, 0x7358U, 0x7458U, 0x7558U, 0x7658U, 0x7758U, 0x7858U, 0x7958U, 0x7A58U, 0x3058U, 0x3158U, 0x3258U, 0x3358U, 0x3458U, 0x3558U, 0x3658U, 0x3758U, 0x3858U, 0x3958U, 0x2B58U, 0x2F58U, 0x4159U, 0x4259U, 0x4359U, 0x4459U, 0x4559U, 0x4659U, 0x4759U, 0x4859U, 0x4959U, 0x4A59U, 0x4B59U, 0x4C59U, 0x4D59U, 0x4E59U, 0x4F59U, 0x5059U, 0x5159U, 0x5259U, 0x5359U, 0x5459U, 0x5559U, 0x5659U, 0x5759U, 0x5859U, 0x5959U, 0x5A59U, 0x6159U, 0x6259U, 0x6359U, 0x6459U, 0x6559U, 0x6659U, 0x6759U, 0x6859U, 0x6959U, 0x6A59U, 0x6B59U, 0x6C59U, 0x6D59U, 0x6E59U, 0x6F59U, 0x7059U, 0x7159U, 0x7259U, 0x7359U, 0x7459U, 0x7559U, 0x7659U, 0x7759U, 0x7859U, 0x7959U, 0x7A59U, 0x3059U, 0x3159U, 0x3259U, 0x3359U, 0x3459U, 0x3559U, 0x3659U, 0x3759U, 0x3859U, 0x3959U, 0x2B59U, 0x2F59U, 0x415AU, 0x425AU, 0x435AU, 0x445AU, 0x455AU, 0x465AU, 0x475AU, 0x485AU, 0x495AU, 0x4A5AU, 0x4B5AU, 0x4C5AU, 0x4D5AU, 0x4E5AU, 0x4F5AU, 0x505AU, 0x515AU, 0x525AU, 0x535AU, 0x545AU, 0x555AU, 0x565AU, 0x575AU, 0x585AU, 0x595AU, 0x5A5AU, 0x615AU, 0x625AU, 0x635AU, 0x645AU, 0x655AU, 0x665AU, 0x675AU, 0x685AU, 0x695AU, 0x6A5AU, 0x6B5AU, 0x6C5AU, 0x6D5AU, 0x6E5AU, 0x6F5AU, 0x705AU, 0x715AU, 0x725AU, 0x735AU, 0x745AU, 0x755AU, 0x765AU, 0x775AU, 0x785AU, 0x795AU, 0x7A5AU, 0x305AU, 0x315AU, 0x325AU, 0x335AU, 0x345AU, 0x355AU, 0x365AU, 0x375AU, 0x385AU, 0x395AU, 0x2B5AU, 0x2F5AU, 0x4161U, 0x4261U, 0x4361U, 0x4461U, 0x4561U, 0x4661U, 0x4761U, 0x4861U, 0x4961U, 0x4A61U, 0x4B61U, 0x4C61U, 0x4D61U, 0x4E61U, 0x4F61U, 0x5061U, 0x5161U, 0x5261U, 0x5361U, 0x5461U, 0x5561U, 0x5661U, 0x5761U, 0x5861U, 0x5961U, 0x5A61U, 0x6161U, 0x6261U, 0x6361U, 0x6461U, 0x6561U, 0x6661U, 0x6761U, 0x6861U, 0x6961U, 0x6A61U, 0x6B61U, 0x6C61U, 0x6D61U, 0x6E61U, 0x6F61U, 0x7061U, 0x7161U, 0x7261U, 0x7361U, 0x7461U, 0x7561U, 0x7661U, 0x7761U, 0x7861U, 0x7961U, 0x7A61U, 0x3061U, 0x3161U, 0x3261U, 0x3361U, 0x3461U, 0x3561U, 0x3661U, 0x3761U, 0x3861U, 0x3961U, 0x2B61U, 0x2F61U, 0x4162U, 0x4262U, 0x4362U, 0x4462U, 0x4562U, 0x4662U, 0x4762U, 0x4862U, 0x4962U, 0x4A62U, 0x4B62U, 0x4C62U, 0x4D62U, 0x4E62U, 0x4F62U, 0x5062U, 0x5162U, 0x5262U, 0x5362U, 0x5462U, 0x5562U, 0x5662U, 0x5762U, 0x5862U, 0x5962U, 0x5A62U, 0x6162U, 0x6262U, 0x6362U, 0x6462U, 0x6562U, 0x6662U, 0x6762U, 0x6862U, 0x6962U, 0x6A62U, 0x6B62U, 0x6C62U, 0x6D62U, 0x6E62U, 0x6F62U, 0x7062U, 0x7162U, 0x7262U, 0x7362U, 0x7462U, 0x7562U, 0x7662U, 0x7762U, 0x7862U, 0x7962U, 0x7A62U, 0x3062U, 0x3162U, 0x3262U, 0x3362U, 0x3462U, 0x3562U, 0x3662U, 0x3762U, 0x3862U, 0x3962U, 0x2B62U, 0x2F62U, 0x4163U, 0x4263U, 0x4363U, 0x4463U, 0x4563U, 0x4663U, 0x4763U, 0x4863U, 0x4963U, 0x4A63U, 0x4B63U, 0x4C63U, 0x4D63U, 0x4E63U, 0x4F63U, 0x5063U, 0x5163U, 0x5263U, 0x5363U, 0x5463U, 0x5563U, 0x5663U, 0x5763U, 0x5863U, 0x5963U, 0x5A63U, 0x6163U, 0x6263U, 0x6363U, 0x6463U, 0x6563U, 0x6663U, 0x6763U, 0x6863U, 0x6963U, 0x6A63U, 0x6B63U, 0x6C63U, 0x6D63U, 0x6E63U, 0x6F63U, 0x7063U, 0x7163U, 0x7263U, 0x7363U, 0x7463U, 0x7563U, 0x7663U, 0x7763U, 0x7863U, 0x7963U, 0x7A63U, 0x3063U, 0x3163U, 0x3263U, 0x3363U, 0x3463U, 0x3563U, 0x3663U, 0x3763U, 0x3863U, 0x3963U, 0x2B63U, 0x2F63U, 0x4164U, 0x4264U, 0x4364U, 0x4464U, 0x4564U, 0x4664U, 0x4764U, 0x4864U, 0x4964U, 0x4A64U, 0x4B64U, 0x4C64U, 0x4D64U, 0x4E64U, 0x4F64U, 0x5064U, 0x5164U, 0x5264U, 0x5364U, 0x5464U, 0x5564U, 0x5664U, 0x5764U, 0x5864U, 0x5964U, 0x5A64U, 0x6164U, 0x6264U, 0x6364U, 0x6464U, 0x6564U, 0x6664U, 0x6764U, 0x6864U, 0x6964U, 0x6A64U, 0x6B64U, 0x6C64U, 0x6D64U, 0x6E64U, 0x6F64U, 0x7064U, 0x7164U, 0x7264U, 0x7364U, 0x7464U, 0x7564U, 0x7664U, 0x7764U, 0x7864U, 0x7964U, 0x7A64U, 0x3064U, 0x3164U, 0x3264U, 0x3364U, 0x3464U, 0x3564U, 0x3664U, 0x3764U, 0x3864U, 0x3964U, 0x2B64U, 0x2F64U, 0x4165U, 0x4265U, 0x4365U, 0x4465U, 0x4565U, 0x4665U, 0x4765U, 0x4865U, 0x4965U, 0x4A65U, 0x4B65U, 0x4C65U, 0x4D65U, 0x4E65U, 0x4F65U, 0x5065U, 0x5165U, 0x5265U, 0x5365U, 0x5465U, 0x5565U, 0x5665U, 0x5765U, 0x5865U, 0x5965U, 0x5A65U, 0x6165U, 0x6265U, 0x6365U, 0x6465U, 0x6565U, 0x6665U, 0x6765U, 0x6865U, 0x6965U, 0x6A65U, 0x6B65U, 0x6C65U, 0x6D65U, 0x6E65U, 0x6F65U, 0x7065U, 0x7165U, 0x7265U, 0x7365U, 0x7465U, 0x7565U, 0x7665U, 0x7765U, 0x7865U, 0x7965U, 0x7A65U, 0x3065U, 0x3165U, 0x3265U, 0x3365U, 0x3465U, 0x3565U, 0x3665U, 0x3765U, 0x3865U, 0x3965U, 0x2B65U, 0x2F65U, 0x4166U, 0x4266U, 0x4366U, 0x4466U, 0x4566U, 0x4666U, 0x4766U, 0x4866U, 0x4966U, 0x4A66U, 0x4B66U, 0x4C66U, 0x4D66U, 0x4E66U, 0x4F66U, 0x5066U, 0x5166U, 0x5266U, 0x5366U, 0x5466U, 0x5566U, 0x5666U, 0x5766U, 0x5866U, 0x5966U, 0x5A66U, 0x6166U, 0x6266U, 0x6366U, 0x6466U, 0x6566U, 0x6666U, 0x6766U, 0x6866U, 0x6966U, 0x6A66U, 0x6B66U, 0x6C66U, 0x6D66U, 0x6E66U, 0x6F66U, 0x7066U, 0x7166U, 0x7266U, 0x7366U, 0x7466U, 0x7566U, 0x7666U, 0x7766U, 0x7866U, 0x7966U, 0x7A66U, 0x3066U, 0x3166U, 0x3266U, 0x3366U, 0x3466U, 0x3566U, 0x3666U, 0x3766U, 0x3866U, 0x3966U, 0x2B66U, 0x2F66U, 0x4167U, 0x4267U, 0x4367U, 0x4467U, 0x4567U, 0x4667U, 0x4767U, 0x4867U, 0x4967U, 0x4A67U, 0x4B67U, 0x4C67U, 0x4D67U, 0x4E67U, 0x4F67U, 0x5067U, 0x5167U, 0x5267U, 0x5367U, 0x5467U, 0x5567U, 0x5667U, 0x5767U, 0x5867U, 0x5967U, 0x5A67U, 0x6167U, 0x6267U, 0x6367U, 0x6467U, 0x6567U, 0x6667U, 0x6767U, 0x6867U, 0x6967U, 0x6A67U, 0x6B67U, 0x6C67U, 0x6D67U, 0x6E67U, 0x6F67U, 0x7067U, 0x7167U, 0x7267U, 0x7367U, 0x7467U, 0x7567U, 0x7667U, 0x7767U, 0x7867U, 0x7967U, 0x7A67U, 0x3067U, 0x3167U, 0x3267U, 0x3367U, 0x3467U, 0x3567U, 0x3667U, 0x3767U, 0x3867U, 0x3967U, 0x2B67U, 0x2F67U, 0x4168U, 0x4268U, 0x4368U, 0x4468U, 0x4568U, 0x4668U, 0x4768U, 0x4868U, 0x4968U, 0x4A68U, 0x4B68U, 0x4C68U, 0x4D68U, 0x4E68U, 0x4F68U, 0x5068U, 0x5168U, 0x5268U, 0x5368U, 0x5468U, 0x5568U, 0x5668U, 0x5768U, 0x5868U, 0x5968U, 0x5A68U, 0x6168U, 0x6268U, 0x6368U, 0x6468U, 0x6568U, 0x6668U, 0x6768U, 0x6868U, 0x6968U, 0x6A68U, 0x6B68U, 0x6C68U, 0x6D68U, 0x6E68U, 0x6F68U, 0x7068U, 0x7168U, 0x7268U, 0x7368U, 0x7468U, 0x7568U, 0x7668U, 0x7768U, 0x7868U, 0x7968U, 0x7A68U, 0x3068U, 0x3168U, 0x3268U, 0x3368U, 0x3468U, 0x3568U, 0x3668U, 0x3768U, 0x3868U, 0x3968U, 0x2B68U, 0x2F68U, 0x4169U, 0x4269U, 0x4369U, 0x4469U, 0x4569U, 0x4669U, 0x4769U, 0x4869U, 0x4969U, 0x4A69U, 0x4B69U, 0x4C69U, 0x4D69U, 0x4E69U, 0x4F69U, 0x5069U, 0x5169U, 0x5269U, 0x5369U, 0x5469U, 0x5569U, 0x5669U, 0x5769U, 0x5869U, 0x5969U, 0x5A69U, 0x6169U, 0x6269U, 0x6369U, 0x6469U, 0x6569U, 0x6669U, 0x6769U, 0x6869U, 0x6969U, 0x6A69U, 0x6B69U, 0x6C69U, 0x6D69U, 0x6E69U, 0x6F69U, 0x7069U, 0x7169U, 0x7269U, 0x7369U, 0x7469U, 0x7569U, 0x7669U, 0x7769U, 0x7869U, 0x7969U, 0x7A69U, 0x3069U, 0x3169U, 0x3269U, 0x3369U, 0x3469U, 0x3569U, 0x3669U, 0x3769U, 0x3869U, 0x3969U, 0x2B69U, 0x2F69U, 0x416AU, 0x426AU, 0x436AU, 0x446AU, 0x456AU, 0x466AU, 0x476AU, 0x486AU, 0x496AU, 0x4A6AU, 0x4B6AU, 0x4C6AU, 0x4D6AU, 0x4E6AU, 0x4F6AU, 0x506AU, 0x516AU, 0x526AU, 0x536AU, 0x546AU, 0x556AU, 0x566AU, 0x576AU, 0x586AU, 0x596AU, 0x5A6AU, 0x616AU, 0x626AU, 0x636AU, 0x646AU, 0x656AU, 0x666AU, 0x676AU, 0x686AU, 0x696AU, 0x6A6AU, 0x6B6AU, 0x6C6AU, 0x6D6AU, 0x6E6AU, 0x6F6AU, 0x706AU, 0x716AU, 0x726AU, 0x736AU, 0x746AU, 0x756AU, 0x766AU, 0x776AU, 0x786AU, 0x796AU, 0x7A6AU, 0x306AU, 0x316AU, 0x326AU, 0x336AU, 0x346AU, 0x356AU, 0x366AU, 0x376AU, 0x386AU, 0x396AU, 0x2B6AU, 0x2F6AU, 0x416BU, 0x426BU, 0x436BU, 0x446BU, 0x456BU, 0x466BU, 0x476BU, 0x486BU, 0x496BU, 0x4A6BU, 0x4B6BU, 0x4C6BU, 0x4D6BU, 0x4E6BU, 0x4F6BU, 0x506BU, 0x516BU, 0x526BU, 0x536BU, 0x546BU, 0x556BU, 0x566BU, 0x576BU, 0x586BU, 0x596BU, 0x5A6BU, 0x616BU, 0x626BU, 0x636BU, 0x646BU, 0x656BU, 0x666BU, 0x676BU, 0x686BU, 0x696BU, 0x6A6BU, 0x6B6BU, 0x6C6BU, 0x6D6BU, 0x6E6BU, 0x6F6BU, 0x706BU, 0x716BU, 0x726BU, 0x736BU, 0x746BU, 0x756BU, 0x766BU, 0x776BU, 0x786BU, 0x796BU, 0x7A6BU, 0x306BU, 0x316BU, 0x326BU, 0x336BU, 0x346BU, 0x356BU, 0x366BU, 0x376BU, 0x386BU, 0x396BU, 0x2B6BU, 0x2F6BU, 0x416CU, 0x426CU, 0x436CU, 0x446CU, 0x456CU, 0x466CU, 0x476CU, 0x486CU, 0x496CU, 0x4A6CU, 0x4B6CU, 0x4C6CU, 0x4D6CU, 0x4E6CU, 0x4F6CU, 0x506CU, 0x516CU, 0x526CU, 0x536CU, 0x546CU, 0x556CU, 0x566CU, 0x576CU, 0x586CU, 0x596CU, 0x5A6CU, 0x616CU, 0x626CU, 0x636CU, 0x646CU, 0x656CU, 0x666CU, 0x676CU, 0x686CU, 0x696CU, 0x6A6CU, 0x6B6CU, 0x6C6CU, 0x6D6CU, 0x6E6CU, 0x6F6CU, 0x706CU, 0x716CU, 0x726CU, 0x736CU, 0x746CU, 0x756CU, 0x766CU, 0x776CU, 0x786CU, 0x796CU, 0x7A6CU, 0x306CU, 0x316CU, 0x326CU, 0x336CU, 0x346CU, 0x356CU, 0x366CU, 0x376CU, 0x386CU, 0x396CU, 0x2B6CU, 0x2F6CU, 0x416DU, 0x426DU, 0x436DU, 0x446DU, 0x456DU, 0x466DU, 0x476DU, 0x486DU, 0x496DU, 0x4A6DU, 0x4B6DU, 0x4C6DU, 0x4D6DU, 0x4E6DU, 0x4F6DU, 0x506DU, 0x516DU, 0x526DU, 0x536DU, 0x546DU, 0x556DU, 0x566DU, 0x576DU, 0x586DU, 0x596DU, 0x5A6DU, 0x616DU, 0x626DU, 0x636DU, 0x646DU, 0x656DU, 0x666DU, 0x676DU, 0x686DU, 0x696DU, 0x6A6DU, 0x6B6DU, 0x6C6DU, 0x6D6DU, 0x6E6DU, 0x6F6DU, 0x706DU, 0x716DU, 0x726DU, 0x736DU, 0x746DU, 0x756DU, 0x766DU, 0x776DU, 0x786DU, 0x796DU, 0x7A6DU, 0x306DU, 0x316DU, 0x326DU, 0x336DU, 0x346DU, 0x356DU, 0x366DU, 0x376DU, 0x386DU, 0x396DU, 0x2B6DU, 0x2F6DU, 0x416EU, 0x426EU, 0x436EU, 0x446EU, 0x456EU, 0x466EU, 0x476EU, 0x486EU, 0x496EU, 0x4A6EU, 0x4B6EU, 0x4C6EU, 0x4D6EU, 0x4E6EU, 0x4F6EU, 0x506EU, 0x516EU, 0x526EU, 0x536EU, 0x546EU, 0x556EU, 0x566EU, 0x576EU, 0x586EU, 0x596EU, 0x5A6EU, 0x616EU, 0x626EU, 0x636EU, 0x646EU, 0x656EU, 0x666EU, 0x676EU, 0x686EU, 0x696EU, 0x6A6EU, 0x6B6EU, 0x6C6EU, 0x6D6EU, 0x6E6EU, 0x6F6EU, 0x706EU, 0x716EU, 0x726EU, 0x736EU, 0x746EU, 0x756EU, 0x766EU, 0x776EU, 0x786EU, 0x796EU, 0x7A6EU, 0x306EU, 0x316EU, 0x326EU, 0x336EU, 0x346EU, 0x356EU, 0x366EU, 0x376EU, 0x386EU, 0x396EU, 0x2B6EU, 0x2F6EU, 0x416FU, 0x426FU, 0x436FU, 0x446FU, 0x456FU, 0x466FU, 0x476FU, 0x486FU, 0x496FU, 0x4A6FU, 0x4B6FU, 0x4C6FU, 0x4D6FU, 0x4E6FU, 0x4F6FU, 0x506FU, 0x516FU, 0x526FU, 0x536FU, 0x546FU, 0x556FU, 0x566FU, 0x576FU, 0x586FU, 0x596FU, 0x5A6FU, 0x616FU, 0x626FU, 0x636FU, 0x646FU, 0x656FU, 0x666FU, 0x676FU, 0x686FU, 0x696FU, 0x6A6FU, 0x6B6FU, 0x6C6FU, 0x6D6FU, 0x6E6FU, 0x6F6FU, 0x706FU, 0x716FU, 0x726FU, 0x736FU, 0x746FU, 0x756FU, 0x766FU, 0x776FU, 0x786FU, 0x796FU, 0x7A6FU, 0x306FU, 0x316FU, 0x326FU, 0x336FU, 0x346FU, 0x356FU, 0x366FU, 0x376FU, 0x386FU, 0x396FU, 0x2B6FU, 0x2F6FU, 0x4170U, 0x4270U, 0x4370U, 0x4470U, 0x4570U, 0x4670U, 0x4770U, 0x4870U, 0x4970U, 0x4A70U, 0x4B70U, 0x4C70U, 0x4D70U, 0x4E70U, 0x4F70U, 0x5070U, 0x5170U, 0x5270U, 0x5370U, 0x5470U, 0x5570U, 0x5670U, 0x5770U, 0x5870U, 0x5970U, 0x5A70U, 0x6170U, 0x6270U, 0x6370U, 0x6470U, 0x6570U, 0x6670U, 0x6770U, 0x6870U, 0x6970U, 0x6A70U, 0x6B70U, 0x6C70U, 0x6D70U, 0x6E70U, 0x6F70U, 0x7070U, 0x7170U, 0x7270U, 0x7370U, 0x7470U, 0x7570U, 0x7670U, 0x7770U, 0x7870U, 0x7970U, 0x7A70U, 0x3070U, 0x3170U, 0x3270U, 0x3370U, 0x3470U, 0x3570U, 0x3670U, 0x3770U, 0x3870U, 0x3970U, 0x2B70U, 0x2F70U, 0x4171U, 0x4271U, 0x4371U, 0x4471U, 0x4571U, 0x4671U, 0x4771U, 0x4871U, 0x4971U, 0x4A71U, 0x4B71U, 0x4C71U, 0x4D71U, 0x4E71U, 0x4F71U, 0x5071U, 0x5171U, 0x5271U, 0x5371U, 0x5471U, 0x5571U, 0x5671U, 0x5771U, 0x5871U, 0x5971U, 0x5A71U, 0x6171U, 0x6271U, 0x6371U, 0x6471U, 0x6571U, 0x6671U, 0x6771U, 0x6871U, 0x6971U, 0x6A71U, 0x6B71U, 0x6C71U, 0x6D71U, 0x6E71U, 0x6F71U, 0x7071U, 0x7171U, 0x7271U, 0x7371U, 0x7471U, 0x7571U, 0x7671U, 0x7771U, 0x7871U, 0x7971U, 0x7A71U, 0x3071U, 0x3171U, 0x3271U, 0x3371U, 0x3471U, 0x3571U, 0x3671U, 0x3771U, 0x3871U, 0x3971U, 0x2B71U, 0x2F71U, 0x4172U, 0x4272U, 0x4372U, 0x4472U, 0x4572U, 0x4672U, 0x4772U, 0x4872U, 0x4972U, 0x4A72U, 0x4B72U, 0x4C72U, 0x4D72U, 0x4E72U, 0x4F72U, 0x5072U, 0x5172U, 0x5272U, 0x5372U, 0x5472U, 0x5572U, 0x5672U, 0x5772U, 0x5872U, 0x5972U, 0x5A72U, 0x6172U, 0x6272U, 0x6372U, 0x6472U, 0x6572U, 0x6672U, 0x6772U, 0x6872U, 0x6972U, 0x6A72U, 0x6B72U, 0x6C72U, 0x6D72U, 0x6E72U, 0x6F72U, 0x7072U, 0x7172U, 0x7272U, 0x7372U, 0x7472U, 0x7572U, 0x7672U, 0x7772U, 0x7872U, 0x7972U, 0x7A72U, 0x3072U, 0x3172U, 0x3272U, 0x3372U, 0x3472U, 0x3572U, 0x3672U, 0x3772U, 0x3872U, 0x3972U, 0x2B72U, 0x2F72U, 0x4173U, 0x4273U, 0x4373U, 0x4473U, 0x4573U, 0x4673U, 0x4773U, 0x4873U, 0x4973U, 0x4A73U, 0x4B73U, 0x4C73U, 0x4D73U, 0x4E73U, 0x4F73U, 0x5073U, 0x5173U, 0x5273U, 0x5373U, 0x5473U, 0x5573U, 0x5673U, 0x5773U, 0x5873U, 0x5973U, 0x5A73U, 0x6173U, 0x6273U, 0x6373U, 0x6473U, 0x6573U, 0x6673U, 0x6773U, 0x6873U, 0x6973U, 0x6A73U, 0x6B73U, 0x6C73U, 0x6D73U, 0x6E73U, 0x6F73U, 0x7073U, 0x7173U, 0x7273U, 0x7373U, 0x7473U, 0x7573U, 0x7673U, 0x7773U, 0x7873U, 0x7973U, 0x7A73U, 0x3073U, 0x3173U, 0x3273U, 0x3373U, 0x3473U, 0x3573U, 0x3673U, 0x3773U, 0x3873U, 0x3973U, 0x2B73U, 0x2F73U, 0x4174U, 0x4274U, 0x4374U, 0x4474U, 0x4574U, 0x4674U, 0x4774U, 0x4874U, 0x4974U, 0x4A74U, 0x4B74U, 0x4C74U, 0x4D74U, 0x4E74U, 0x4F74U, 0x5074U, 0x5174U, 0x5274U, 0x5374U, 0x5474U, 0x5574U, 0x5674U, 0x5774U, 0x5874U, 0x5974U, 0x5A74U, 0x6174U, 0x6274U, 0x6374U, 0x6474U, 0x6574U, 0x6674U, 0x6774U, 0x6874U, 0x6974U, 0x6A74U, 0x6B74U, 0x6C74U, 0x6D74U, 0x6E74U, 0x6F74U, 0x7074U, 0x7174U, 0x7274U, 0x7374U, 0x7474U, 0x7574U, 0x7674U, 0x7774U, 0x7874U, 0x7974U, 0x7A74U, 0x3074U, 0x3174U, 0x3274U, 0x3374U, 0x3474U, 0x3574U, 0x3674U, 0x3774U, 0x3874U, 0x3974U, 0x2B74U, 0x2F74U, 0x4175U, 0x4275U, 0x4375U, 0x4475U, 0x4575U, 0x4675U, 0x4775U, 0x4875U, 0x4975U, 0x4A75U, 0x4B75U, 0x4C75U, 0x4D75U, 0x4E75U, 0x4F75U, 0x5075U, 0x5175U, 0x5275U, 0x5375U, 0x5475U, 0x5575U, 0x5675U, 0x5775U, 0x5875U, 0x5975U, 0x5A75U, 0x6175U, 0x6275U, 0x6375U, 0x6475U, 0x6575U, 0x6675U, 0x6775U, 0x6875U, 0x6975U, 0x6A75U, 0x6B75U, 0x6C75U, 0x6D75U, 0x6E75U, 0x6F75U, 0x7075U, 0x7175U, 0x7275U, 0x7375U, 0x7475U, 0x7575U, 0x7675U, 0x7775U, 0x7875U, 0x7975U, 0x7A75U, 0x3075U, 0x3175U, 0x3275U, 0x3375U, 0x3475U, 0x3575U, 0x3675U, 0x3775U, 0x3875U, 0x3975U, 0x2B75U, 0x2F75U, 0x4176U, 0x4276U, 0x4376U, 0x4476U, 0x4576U, 0x4676U, 0x4776U, 0x4876U, 0x4976U, 0x4A76U, 0x4B76U, 0x4C76U, 0x4D76U, 0x4E76U, 0x4F76U, 0x5076U, 0x5176U, 0x5276U, 0x5376U, 0x5476U, 0x5576U, 0x5676U, 0x5776U, 0x5876U, 0x5976U, 0x5A76U, 0x6176U, 0x6276U, 0x6376U, 0x6476U, 0x6576U, 0x6676U, 0x6776U, 0x6876U, 0x6976U, 0x6A76U, 0x6B76U, 0x6C76U, 0x6D76U, 0x6E76U, 0x6F76U, 0x7076U, 0x7176U, 0x7276U, 0x7376U, 0x7476U, 0x7576U, 0x7676U, 0x7776U, 0x7876U, 0x7976U, 0x7A76U, 0x3076U, 0x3176U, 0x3276U, 0x3376U, 0x3476U, 0x3576U, 0x3676U, 0x3776U, 0x3876U, 0x3976U, 0x2B76U, 0x2F76U, 0x4177U, 0x4277U, 0x4377U, 0x4477U, 0x4577U, 0x4677U, 0x4777U, 0x4877U, 0x4977U, 0x4A77U, 0x4B77U, 0x4C77U, 0x4D77U, 0x4E77U, 0x4F77U, 0x5077U, 0x5177U, 0x5277U, 0x5377U, 0x5477U, 0x5577U, 0x5677U, 0x5777U, 0x5877U, 0x5977U, 0x5A77U, 0x6177U, 0x6277U, 0x6377U, 0x6477U, 0x6577U, 0x6677U, 0x6777U, 0x6877U, 0x6977U, 0x6A77U, 0x6B77U, 0x6C77U, 0x6D77U, 0x6E77U, 0x6F77U, 0x7077U, 0x7177U, 0x7277U, 0x7377U, 0x7477U, 0x7577U, 0x7677U, 0x7777U, 0x7877U, 0x7977U, 0x7A77U, 0x3077U, 0x3177U, 0x3277U, 0x3377U, 0x3477U, 0x3577U, 0x3677U, 0x3777U, 0x3877U, 0x3977U, 0x2B77U, 0x2F77U, 0x4178U, 0x4278U, 0x4378U, 0x4478U, 0x4578U, 0x4678U, 0x4778U, 0x4878U, 0x4978U, 0x4A78U, 0x4B78U, 0x4C78U, 0x4D78U, 0x4E78U, 0x4F78U, 0x5078U, 0x5178U, 0x5278U, 0x5378U, 0x5478U, 0x5578U, 0x5678U, 0x5778U, 0x5878U, 0x5978U, 0x5A78U, 0x6178U, 0x6278U, 0x6378U, 0x6478U, 0x6578U, 0x6678U, 0x6778U, 0x6878U, 0x6978U, 0x6A78U, 0x6B78U, 0x6C78U, 0x6D78U, 0x6E78U, 0x6F78U, 0x7078U, 0x7178U, 0x7278U, 0x7378U, 0x7478U, 0x7578U, 0x7678U, 0x7778U, 0x7878U, 0x7978U, 0x7A78U, 0x3078U, 0x3178U, 0x3278U, 0x3378U, 0x3478U, 0x3578U, 0x3678U, 0x3778U, 0x3878U, 0x3978U, 0x2B78U, 0x2F78U, 0x4179U, 0x4279U, 0x4379U, 0x4479U, 0x4579U, 0x4679U, 0x4779U, 0x4879U, 0x4979U, 0x4A79U, 0x4B79U, 0x4C79U, 0x4D79U, 0x4E79U, 0x4F79U, 0x5079U, 0x5179U, 0x5279U, 0x5379U, 0x5479U, 0x5579U, 0x5679U, 0x5779U, 0x5879U, 0x5979U, 0x5A79U, 0x6179U, 0x6279U, 0x6379U, 0x6479U, 0x6579U, 0x6679U, 0x6779U, 0x6879U, 0x6979U, 0x6A79U, 0x6B79U, 0x6C79U, 0x6D79U, 0x6E79U, 0x6F79U, 0x7079U, 0x7179U, 0x7279U, 0x7379U, 0x7479U, 0x7579U, 0x7679U, 0x7779U, 0x7879U, 0x7979U, 0x7A79U, 0x3079U, 0x3179U, 0x3279U, 0x3379U, 0x3479U, 0x3579U, 0x3679U, 0x3779U, 0x3879U, 0x3979U, 0x2B79U, 0x2F79U, 0x417AU, 0x427AU, 0x437AU, 0x447AU, 0x457AU, 0x467AU, 0x477AU, 0x487AU, 0x497AU, 0x4A7AU, 0x4B7AU, 0x4C7AU, 0x4D7AU, 0x4E7AU, 0x4F7AU, 0x507AU, 0x517AU, 0x527AU, 0x537AU, 0x547AU, 0x557AU, 0x567AU, 0x577AU, 0x587AU, 0x597AU, 0x5A7AU, 0x617AU, 0x627AU, 0x637AU, 0x647AU, 0x657AU, 0x667AU, 0x677AU, 0x687AU, 0x697AU, 0x6A7AU, 0x6B7AU, 0x6C7AU, 0x6D7AU, 0x6E7AU, 0x6F7AU, 0x707AU, 0x717AU, 0x727AU, 0x737AU, 0x747AU, 0x757AU, 0x767AU, 0x777AU, 0x787AU, 0x797AU, 0x7A7AU, 0x307AU, 0x317AU, 0x327AU, 0x337AU, 0x347AU, 0x357AU, 0x367AU, 0x377AU, 0x387AU, 0x397AU, 0x2B7AU, 0x2F7AU, 0x4130U, 0x4230U, 0x4330U, 0x4430U, 0x4530U, 0x4630U, 0x4730U, 0x4830U, 0x4930U, 0x4A30U, 0x4B30U, 0x4C30U, 0x4D30U, 0x4E30U, 0x4F30U, 0x5030U, 0x5130U, 0x5230U, 0x5330U, 0x5430U, 0x5530U, 0x5630U, 0x5730U, 0x5830U, 0x5930U, 0x5A30U, 0x6130U, 0x6230U, 0x6330U, 0x6430U, 0x6530U, 0x6630U, 0x6730U, 0x6830U, 0x6930U, 0x6A30U, 0x6B30U, 0x6C30U, 0x6D30U, 0x6E30U, 0x6F30U, 0x7030U, 0x7130U, 0x7230U, 0x7330U, 0x7430U, 0x7530U, 0x7630U, 0x7730U, 0x7830U, 0x7930U, 0x7A30U, 0x3030U, 0x3130U, 0x3230U, 0x3330U, 0x3430U, 0x3530U, 0x3630U, 0x3730U, 0x3830U, 0x3930U, 0x2B30U, 0x2F30U, 0x4131U, 0x4231U, 0x4331U, 0x4431U, 0x4531U, 0x4631U, 0x4731U, 0x4831U, 0x4931U, 0x4A31U, 0x4B31U, 0x4C31U, 0x4D31U, 0x4E31U, 0x4F31U, 0x5031U, 0x5131U, 0x5231U, 0x5331U, 0x5431U, 0x5531U, 0x5631U, 0x5731U, 0x5831U, 0x5931U, 0x5A31U, 0x6131U, 0x6231U, 0x6331U, 0x6431U, 0x6531U, 0x6631U, 0x6731U, 0x6831U, 0x6931U, 0x6A31U, 0x6B31U, 0x6C31U, 0x6D31U, 0x6E31U, 0x6F31U, 0x7031U, 0x7131U, 0x7231U, 0x7331U, 0x7431U, 0x7531U, 0x7631U, 0x7731U, 0x7831U, 0x7931U, 0x7A31U, 0x3031U, 0x3131U, 0x3231U, 0x3331U, 0x3431U, 0x3531U, 0x3631U, 0x3731U, 0x3831U, 0x3931U, 0x2B31U, 0x2F31U, 0x4132U, 0x4232U, 0x4332U, 0x4432U, 0x4532U, 0x4632U, 0x4732U, 0x4832U, 0x4932U, 0x4A32U, 0x4B32U, 0x4C32U, 0x4D32U, 0x4E32U, 0x4F32U, 0x5032U, 0x5132U, 0x5232U, 0x5332U, 0x5432U, 0x5532U, 0x5632U, 0x5732U, 0x5832U, 0x5932U, 0x5A32U, 0x6132U, 0x6232U, 0x6332U, 0x6432U, 0x6532U, 0x6632U, 0x6732U, 0x6832U, 0x6932U, 0x6A32U, 0x6B32U, 0x6C32U, 0x6D32U, 0x6E32U, 0x6F32U, 0x7032U, 0x7132U, 0x7232U, 0x7332U, 0x7432U, 0x7532U, 0x7632U, 0x7732U, 0x7832U, 0x7932U, 0x7A32U, 0x3032U, 0x3132U, 0x3232U, 0x3332U, 0x3432U, 0x3532U, 0x3632U, 0x3732U, 0x3832U, 0x3932U, 0x2B32U, 0x2F32U, 0x4133U, 0x4233U, 0x4333U, 0x4433U, 0x4533U, 0x4633U, 0x4733U, 0x4833U, 0x4933U, 0x4A33U, 0x4B33U, 0x4C33U, 0x4D33U, 0x4E33U, 0x4F33U, 0x5033U, 0x5133U, 0x5233U, 0x5333U, 0x5433U, 0x5533U, 0x5633U, 0x5733U, 0x5833U, 0x5933U, 0x5A33U, 0x6133U, 0x6233U, 0x6333U, 0x6433U, 0x6533U, 0x6633U, 0x6733U, 0x6833U, 0x6933U, 0x6A33U, 0x6B33U, 0x6C33U, 0x6D33U, 0x6E33U, 0x6F33U, 0x7033U, 0x7133U, 0x7233U, 0x7333U, 0x7433U, 0x7533U, 0x7633U, 0x7733U, 0x7833U, 0x7933U, 0x7A33U, 0x3033U, 0x3133U, 0x3233U, 0x3333U, 0x3433U, 0x3533U, 0x3633U, 0x3733U, 0x3833U, 0x3933U, 0x2B33U, 0x2F33U, 0x4134U, 0x4234U, 0x4334U, 0x4434U, 0x4534U, 0x4634U, 0x4734U, 0x4834U, 0x4934U, 0x4A34U, 0x4B34U, 0x4C34U, 0x4D34U, 0x4E34U, 0x4F34U, 0x5034U, 0x5134U, 0x5234U, 0x5334U, 0x5434U, 0x5534U, 0x5634U, 0x5734U, 0x5834U, 0x5934U, 0x5A34U, 0x6134U, 0x6234U, 0x6334U, 0x6434U, 0x6534U, 0x6634U, 0x6734U, 0x6834U, 0x6934U, 0x6A34U, 0x6B34U, 0x6C34U, 0x6D34U, 0x6E34U, 0x6F34U, 0x7034U, 0x7134U, 0x7234U, 0x7334U, 0x7434U, 0x7534U, 0x7634U, 0x7734U, 0x7834U, 0x7934U, 0x7A34U, 0x3034U, 0x3134U, 0x3234U, 0x3334U, 0x3434U, 0x3534U, 0x3634U, 0x3734U, 0x3834U, 0x3934U, 0x2B34U, 0x2F34U, 0x4135U, 0x4235U, 0x4335U, 0x4435U, 0x4535U, 0x4635U, 0x4735U, 0x4835U, 0x4935U, 0x4A35U, 0x4B35U, 0x4C35U, 0x4D35U, 0x4E35U, 0x4F35U, 0x5035U, 0x5135U, 0x5235U, 0x5335U, 0x5435U, 0x5535U, 0x5635U, 0x5735U, 0x5835U, 0x5935U, 0x5A35U, 0x6135U, 0x6235U, 0x6335U, 0x6435U, 0x6535U, 0x6635U, 0x6735U, 0x6835U, 0x6935U, 0x6A35U, 0x6B35U, 0x6C35U, 0x6D35U, 0x6E35U, 0x6F35U, 0x7035U, 0x7135U, 0x7235U, 0x7335U, 0x7435U, 0x7535U, 0x7635U, 0x7735U, 0x7835U, 0x7935U, 0x7A35U, 0x3035U, 0x3135U, 0x3235U, 0x3335U, 0x3435U, 0x3535U, 0x3635U, 0x3735U, 0x3835U, 0x3935U, 0x2B35U, 0x2F35U, 0x4136U, 0x4236U, 0x4336U, 0x4436U, 0x4536U, 0x4636U, 0x4736U, 0x4836U, 0x4936U, 0x4A36U, 0x4B36U, 0x4C36U, 0x4D36U, 0x4E36U, 0x4F36U, 0x5036U, 0x5136U, 0x5236U, 0x5336U, 0x5436U, 0x5536U, 0x5636U, 0x5736U, 0x5836U, 0x5936U, 0x5A36U, 0x6136U, 0x6236U, 0x6336U, 0x6436U, 0x6536U, 0x6636U, 0x6736U, 0x6836U, 0x6936U, 0x6A36U, 0x6B36U, 0x6C36U, 0x6D36U, 0x6E36U, 0x6F36U, 0x7036U, 0x7136U, 0x7236U, 0x7336U, 0x7436U, 0x7536U, 0x7636U, 0x7736U, 0x7836U, 0x7936U, 0x7A36U, 0x3036U, 0x3136U, 0x3236U, 0x3336U, 0x3436U, 0x3536U, 0x3636U, 0x3736U, 0x3836U, 0x3936U, 0x2B36U, 0x2F36U, 0x4137U, 0x4237U, 0x4337U, 0x4437U, 0x4537U, 0x4637U, 0x4737U, 0x4837U, 0x4937U, 0x4A37U, 0x4B37U, 0x4C37U, 0x4D37U, 0x4E37U, 0x4F37U, 0x5037U, 0x5137U, 0x5237U, 0x5337U, 0x5437U, 0x5537U, 0x5637U, 0x5737U, 0x5837U, 0x5937U, 0x5A37U, 0x6137U, 0x6237U, 0x6337U, 0x6437U, 0x6537U, 0x6637U, 0x6737U, 0x6837U, 0x6937U, 0x6A37U, 0x6B37U, 0x6C37U, 0x6D37U, 0x6E37U, 0x6F37U, 0x7037U, 0x7137U, 0x7237U, 0x7337U, 0x7437U, 0x7537U, 0x7637U, 0x7737U, 0x7837U, 0x7937U, 0x7A37U, 0x3037U, 0x3137U, 0x3237U, 0x3337U, 0x3437U, 0x3537U, 0x3637U, 0x3737U, 0x3837U, 0x3937U, 0x2B37U, 0x2F37U, 0x4138U, 0x4238U, 0x4338U, 0x4438U, 0x4538U, 0x4638U, 0x4738U, 0x4838U, 0x4938U, 0x4A38U, 0x4B38U, 0x4C38U, 0x4D38U, 0x4E38U, 0x4F38U, 0x5038U, 0x5138U, 0x5238U, 0x5338U, 0x5438U, 0x5538U, 0x5638U, 0x5738U, 0x5838U, 0x5938U, 0x5A38U, 0x6138U, 0x6238U, 0x6338U, 0x6438U, 0x6538U, 0x6638U, 0x6738U, 0x6838U, 0x6938U, 0x6A38U, 0x6B38U, 0x6C38U, 0x6D38U, 0x6E38U, 0x6F38U, 0x7038U, 0x7138U, 0x7238U, 0x7338U, 0x7438U, 0x7538U, 0x7638U, 0x7738U, 0x7838U, 0x7938U, 0x7A38U, 0x3038U, 0x3138U, 0x3238U, 0x3338U, 0x3438U, 0x3538U, 0x3638U, 0x3738U, 0x3838U, 0x3938U, 0x2B38U, 0x2F38U, 0x4139U, 0x4239U, 0x4339U, 0x4439U, 0x4539U, 0x4639U, 0x4739U, 0x4839U, 0x4939U, 0x4A39U, 0x4B39U, 0x4C39U, 0x4D39U, 0x4E39U, 0x4F39U, 0x5039U, 0x5139U, 0x5239U, 0x5339U, 0x5439U, 0x5539U, 0x5639U, 0x5739U, 0x5839U, 0x5939U, 0x5A39U, 0x6139U, 0x6239U, 0x6339U, 0x6439U, 0x6539U, 0x6639U, 0x6739U, 0x6839U, 0x6939U, 0x6A39U, 0x6B39U, 0x6C39U, 0x6D39U, 0x6E39U, 0x6F39U, 0x7039U, 0x7139U, 0x7239U, 0x7339U, 0x7439U, 0x7539U, 0x7639U, 0x7739U, 0x7839U, 0x7939U, 0x7A39U, 0x3039U, 0x3139U, 0x3239U, 0x3339U, 0x3439U, 0x3539U, 0x3639U, 0x3739U, 0x3839U, 0x3939U, 0x2B39U, 0x2F39U, 0x412BU, 0x422BU, 0x432BU, 0x442BU, 0x452BU, 0x462BU, 0x472BU, 0x482BU, 0x492BU, 0x4A2BU, 0x4B2BU, 0x4C2BU, 0x4D2BU, 0x4E2BU, 0x4F2BU, 0x502BU, 0x512BU, 0x522BU, 0x532BU, 0x542BU, 0x552BU, 0x562BU, 0x572BU, 0x582BU, 0x592BU, 0x5A2BU, 0x612BU, 0x622BU, 0x632BU, 0x642BU, 0x652BU, 0x662BU, 0x672BU, 0x682BU, 0x692BU, 0x6A2BU, 0x6B2BU, 0x6C2BU, 0x6D2BU, 0x6E2BU, 0x6F2BU, 0x702BU, 0x712BU, 0x722BU, 0x732BU, 0x742BU, 0x752BU, 0x762BU, 0x772BU, 0x782BU, 0x792BU, 0x7A2BU, 0x302BU, 0x312BU, 0x322BU, 0x332BU, 0x342BU, 0x352BU, 0x362BU, 0x372BU, 0x382BU, 0x392BU, 0x2B2BU, 0x2F2BU, 0x412FU, 0x422FU, 0x432FU, 0x442FU, 0x452FU, 0x462FU, 0x472FU, 0x482FU, 0x492FU, 0x4A2FU, 0x4B2FU, 0x4C2FU, 0x4D2FU, 0x4E2FU, 0x4F2FU, 0x502FU, 0x512FU, 0x522FU, 0x532FU, 0x542FU, 0x552FU, 0x562FU, 0x572FU, 0x582FU, 0x592FU, 0x5A2FU, 0x612FU, 0x622FU, 0x632FU, 0x642FU, 0x652FU, 0x662FU, 0x672FU, 0x682FU, 0x692FU, 0x6A2FU, 0x6B2FU, 0x6C2FU, 0x6D2FU, 0x6E2FU, 0x6F2FU, 0x702FU, 0x712FU, 0x722FU, 0x732FU, 0x742FU, 0x752FU, 0x762FU, 0x772FU, 0x782FU, 0x792FU, 0x7A2FU, 0x302FU, 0x312FU, 0x322FU, 0x332FU, 0x342FU, 0x352FU, 0x362FU, 0x372FU, 0x382FU, 0x392FU, 0x2B2FU, 0x2F2FU, #else 0x4141U, 0x4142U, 0x4143U, 0x4144U, 0x4145U, 0x4146U, 0x4147U, 0x4148U, 0x4149U, 0x414AU, 0x414BU, 0x414CU, 0x414DU, 0x414EU, 0x414FU, 0x4150U, 0x4151U, 0x4152U, 0x4153U, 0x4154U, 0x4155U, 0x4156U, 0x4157U, 0x4158U, 0x4159U, 0x415AU, 0x4161U, 0x4162U, 0x4163U, 0x4164U, 0x4165U, 0x4166U, 0x4167U, 0x4168U, 0x4169U, 0x416AU, 0x416BU, 0x416CU, 0x416DU, 0x416EU, 0x416FU, 0x4170U, 0x4171U, 0x4172U, 0x4173U, 0x4174U, 0x4175U, 0x4176U, 0x4177U, 0x4178U, 0x4179U, 0x417AU, 0x4130U, 0x4131U, 0x4132U, 0x4133U, 0x4134U, 0x4135U, 0x4136U, 0x4137U, 0x4138U, 0x4139U, 0x412BU, 0x412FU, 0x4241U, 0x4242U, 0x4243U, 0x4244U, 0x4245U, 0x4246U, 0x4247U, 0x4248U, 0x4249U, 0x424AU, 0x424BU, 0x424CU, 0x424DU, 0x424EU, 0x424FU, 0x4250U, 0x4251U, 0x4252U, 0x4253U, 0x4254U, 0x4255U, 0x4256U, 0x4257U, 0x4258U, 0x4259U, 0x425AU, 0x4261U, 0x4262U, 0x4263U, 0x4264U, 0x4265U, 0x4266U, 0x4267U, 0x4268U, 0x4269U, 0x426AU, 0x426BU, 0x426CU, 0x426DU, 0x426EU, 0x426FU, 0x4270U, 0x4271U, 0x4272U, 0x4273U, 0x4274U, 0x4275U, 0x4276U, 0x4277U, 0x4278U, 0x4279U, 0x427AU, 0x4230U, 0x4231U, 0x4232U, 0x4233U, 0x4234U, 0x4235U, 0x4236U, 0x4237U, 0x4238U, 0x4239U, 0x422BU, 0x422FU, 0x4341U, 0x4342U, 0x4343U, 0x4344U, 0x4345U, 0x4346U, 0x4347U, 0x4348U, 0x4349U, 0x434AU, 0x434BU, 0x434CU, 0x434DU, 0x434EU, 0x434FU, 0x4350U, 0x4351U, 0x4352U, 0x4353U, 0x4354U, 0x4355U, 0x4356U, 0x4357U, 0x4358U, 0x4359U, 0x435AU, 0x4361U, 0x4362U, 0x4363U, 0x4364U, 0x4365U, 0x4366U, 0x4367U, 0x4368U, 0x4369U, 0x436AU, 0x436BU, 0x436CU, 0x436DU, 0x436EU, 0x436FU, 0x4370U, 0x4371U, 0x4372U, 0x4373U, 0x4374U, 0x4375U, 0x4376U, 0x4377U, 0x4378U, 0x4379U, 0x437AU, 0x4330U, 0x4331U, 0x4332U, 0x4333U, 0x4334U, 0x4335U, 0x4336U, 0x4337U, 0x4338U, 0x4339U, 0x432BU, 0x432FU, 0x4441U, 0x4442U, 0x4443U, 0x4444U, 0x4445U, 0x4446U, 0x4447U, 0x4448U, 0x4449U, 0x444AU, 0x444BU, 0x444CU, 0x444DU, 0x444EU, 0x444FU, 0x4450U, 0x4451U, 0x4452U, 0x4453U, 0x4454U, 0x4455U, 0x4456U, 0x4457U, 0x4458U, 0x4459U, 0x445AU, 0x4461U, 0x4462U, 0x4463U, 0x4464U, 0x4465U, 0x4466U, 0x4467U, 0x4468U, 0x4469U, 0x446AU, 0x446BU, 0x446CU, 0x446DU, 0x446EU, 0x446FU, 0x4470U, 0x4471U, 0x4472U, 0x4473U, 0x4474U, 0x4475U, 0x4476U, 0x4477U, 0x4478U, 0x4479U, 0x447AU, 0x4430U, 0x4431U, 0x4432U, 0x4433U, 0x4434U, 0x4435U, 0x4436U, 0x4437U, 0x4438U, 0x4439U, 0x442BU, 0x442FU, 0x4541U, 0x4542U, 0x4543U, 0x4544U, 0x4545U, 0x4546U, 0x4547U, 0x4548U, 0x4549U, 0x454AU, 0x454BU, 0x454CU, 0x454DU, 0x454EU, 0x454FU, 0x4550U, 0x4551U, 0x4552U, 0x4553U, 0x4554U, 0x4555U, 0x4556U, 0x4557U, 0x4558U, 0x4559U, 0x455AU, 0x4561U, 0x4562U, 0x4563U, 0x4564U, 0x4565U, 0x4566U, 0x4567U, 0x4568U, 0x4569U, 0x456AU, 0x456BU, 0x456CU, 0x456DU, 0x456EU, 0x456FU, 0x4570U, 0x4571U, 0x4572U, 0x4573U, 0x4574U, 0x4575U, 0x4576U, 0x4577U, 0x4578U, 0x4579U, 0x457AU, 0x4530U, 0x4531U, 0x4532U, 0x4533U, 0x4534U, 0x4535U, 0x4536U, 0x4537U, 0x4538U, 0x4539U, 0x452BU, 0x452FU, 0x4641U, 0x4642U, 0x4643U, 0x4644U, 0x4645U, 0x4646U, 0x4647U, 0x4648U, 0x4649U, 0x464AU, 0x464BU, 0x464CU, 0x464DU, 0x464EU, 0x464FU, 0x4650U, 0x4651U, 0x4652U, 0x4653U, 0x4654U, 0x4655U, 0x4656U, 0x4657U, 0x4658U, 0x4659U, 0x465AU, 0x4661U, 0x4662U, 0x4663U, 0x4664U, 0x4665U, 0x4666U, 0x4667U, 0x4668U, 0x4669U, 0x466AU, 0x466BU, 0x466CU, 0x466DU, 0x466EU, 0x466FU, 0x4670U, 0x4671U, 0x4672U, 0x4673U, 0x4674U, 0x4675U, 0x4676U, 0x4677U, 0x4678U, 0x4679U, 0x467AU, 0x4630U, 0x4631U, 0x4632U, 0x4633U, 0x4634U, 0x4635U, 0x4636U, 0x4637U, 0x4638U, 0x4639U, 0x462BU, 0x462FU, 0x4741U, 0x4742U, 0x4743U, 0x4744U, 0x4745U, 0x4746U, 0x4747U, 0x4748U, 0x4749U, 0x474AU, 0x474BU, 0x474CU, 0x474DU, 0x474EU, 0x474FU, 0x4750U, 0x4751U, 0x4752U, 0x4753U, 0x4754U, 0x4755U, 0x4756U, 0x4757U, 0x4758U, 0x4759U, 0x475AU, 0x4761U, 0x4762U, 0x4763U, 0x4764U, 0x4765U, 0x4766U, 0x4767U, 0x4768U, 0x4769U, 0x476AU, 0x476BU, 0x476CU, 0x476DU, 0x476EU, 0x476FU, 0x4770U, 0x4771U, 0x4772U, 0x4773U, 0x4774U, 0x4775U, 0x4776U, 0x4777U, 0x4778U, 0x4779U, 0x477AU, 0x4730U, 0x4731U, 0x4732U, 0x4733U, 0x4734U, 0x4735U, 0x4736U, 0x4737U, 0x4738U, 0x4739U, 0x472BU, 0x472FU, 0x4841U, 0x4842U, 0x4843U, 0x4844U, 0x4845U, 0x4846U, 0x4847U, 0x4848U, 0x4849U, 0x484AU, 0x484BU, 0x484CU, 0x484DU, 0x484EU, 0x484FU, 0x4850U, 0x4851U, 0x4852U, 0x4853U, 0x4854U, 0x4855U, 0x4856U, 0x4857U, 0x4858U, 0x4859U, 0x485AU, 0x4861U, 0x4862U, 0x4863U, 0x4864U, 0x4865U, 0x4866U, 0x4867U, 0x4868U, 0x4869U, 0x486AU, 0x486BU, 0x486CU, 0x486DU, 0x486EU, 0x486FU, 0x4870U, 0x4871U, 0x4872U, 0x4873U, 0x4874U, 0x4875U, 0x4876U, 0x4877U, 0x4878U, 0x4879U, 0x487AU, 0x4830U, 0x4831U, 0x4832U, 0x4833U, 0x4834U, 0x4835U, 0x4836U, 0x4837U, 0x4838U, 0x4839U, 0x482BU, 0x482FU, 0x4941U, 0x4942U, 0x4943U, 0x4944U, 0x4945U, 0x4946U, 0x4947U, 0x4948U, 0x4949U, 0x494AU, 0x494BU, 0x494CU, 0x494DU, 0x494EU, 0x494FU, 0x4950U, 0x4951U, 0x4952U, 0x4953U, 0x4954U, 0x4955U, 0x4956U, 0x4957U, 0x4958U, 0x4959U, 0x495AU, 0x4961U, 0x4962U, 0x4963U, 0x4964U, 0x4965U, 0x4966U, 0x4967U, 0x4968U, 0x4969U, 0x496AU, 0x496BU, 0x496CU, 0x496DU, 0x496EU, 0x496FU, 0x4970U, 0x4971U, 0x4972U, 0x4973U, 0x4974U, 0x4975U, 0x4976U, 0x4977U, 0x4978U, 0x4979U, 0x497AU, 0x4930U, 0x4931U, 0x4932U, 0x4933U, 0x4934U, 0x4935U, 0x4936U, 0x4937U, 0x4938U, 0x4939U, 0x492BU, 0x492FU, 0x4A41U, 0x4A42U, 0x4A43U, 0x4A44U, 0x4A45U, 0x4A46U, 0x4A47U, 0x4A48U, 0x4A49U, 0x4A4AU, 0x4A4BU, 0x4A4CU, 0x4A4DU, 0x4A4EU, 0x4A4FU, 0x4A50U, 0x4A51U, 0x4A52U, 0x4A53U, 0x4A54U, 0x4A55U, 0x4A56U, 0x4A57U, 0x4A58U, 0x4A59U, 0x4A5AU, 0x4A61U, 0x4A62U, 0x4A63U, 0x4A64U, 0x4A65U, 0x4A66U, 0x4A67U, 0x4A68U, 0x4A69U, 0x4A6AU, 0x4A6BU, 0x4A6CU, 0x4A6DU, 0x4A6EU, 0x4A6FU, 0x4A70U, 0x4A71U, 0x4A72U, 0x4A73U, 0x4A74U, 0x4A75U, 0x4A76U, 0x4A77U, 0x4A78U, 0x4A79U, 0x4A7AU, 0x4A30U, 0x4A31U, 0x4A32U, 0x4A33U, 0x4A34U, 0x4A35U, 0x4A36U, 0x4A37U, 0x4A38U, 0x4A39U, 0x4A2BU, 0x4A2FU, 0x4B41U, 0x4B42U, 0x4B43U, 0x4B44U, 0x4B45U, 0x4B46U, 0x4B47U, 0x4B48U, 0x4B49U, 0x4B4AU, 0x4B4BU, 0x4B4CU, 0x4B4DU, 0x4B4EU, 0x4B4FU, 0x4B50U, 0x4B51U, 0x4B52U, 0x4B53U, 0x4B54U, 0x4B55U, 0x4B56U, 0x4B57U, 0x4B58U, 0x4B59U, 0x4B5AU, 0x4B61U, 0x4B62U, 0x4B63U, 0x4B64U, 0x4B65U, 0x4B66U, 0x4B67U, 0x4B68U, 0x4B69U, 0x4B6AU, 0x4B6BU, 0x4B6CU, 0x4B6DU, 0x4B6EU, 0x4B6FU, 0x4B70U, 0x4B71U, 0x4B72U, 0x4B73U, 0x4B74U, 0x4B75U, 0x4B76U, 0x4B77U, 0x4B78U, 0x4B79U, 0x4B7AU, 0x4B30U, 0x4B31U, 0x4B32U, 0x4B33U, 0x4B34U, 0x4B35U, 0x4B36U, 0x4B37U, 0x4B38U, 0x4B39U, 0x4B2BU, 0x4B2FU, 0x4C41U, 0x4C42U, 0x4C43U, 0x4C44U, 0x4C45U, 0x4C46U, 0x4C47U, 0x4C48U, 0x4C49U, 0x4C4AU, 0x4C4BU, 0x4C4CU, 0x4C4DU, 0x4C4EU, 0x4C4FU, 0x4C50U, 0x4C51U, 0x4C52U, 0x4C53U, 0x4C54U, 0x4C55U, 0x4C56U, 0x4C57U, 0x4C58U, 0x4C59U, 0x4C5AU, 0x4C61U, 0x4C62U, 0x4C63U, 0x4C64U, 0x4C65U, 0x4C66U, 0x4C67U, 0x4C68U, 0x4C69U, 0x4C6AU, 0x4C6BU, 0x4C6CU, 0x4C6DU, 0x4C6EU, 0x4C6FU, 0x4C70U, 0x4C71U, 0x4C72U, 0x4C73U, 0x4C74U, 0x4C75U, 0x4C76U, 0x4C77U, 0x4C78U, 0x4C79U, 0x4C7AU, 0x4C30U, 0x4C31U, 0x4C32U, 0x4C33U, 0x4C34U, 0x4C35U, 0x4C36U, 0x4C37U, 0x4C38U, 0x4C39U, 0x4C2BU, 0x4C2FU, 0x4D41U, 0x4D42U, 0x4D43U, 0x4D44U, 0x4D45U, 0x4D46U, 0x4D47U, 0x4D48U, 0x4D49U, 0x4D4AU, 0x4D4BU, 0x4D4CU, 0x4D4DU, 0x4D4EU, 0x4D4FU, 0x4D50U, 0x4D51U, 0x4D52U, 0x4D53U, 0x4D54U, 0x4D55U, 0x4D56U, 0x4D57U, 0x4D58U, 0x4D59U, 0x4D5AU, 0x4D61U, 0x4D62U, 0x4D63U, 0x4D64U, 0x4D65U, 0x4D66U, 0x4D67U, 0x4D68U, 0x4D69U, 0x4D6AU, 0x4D6BU, 0x4D6CU, 0x4D6DU, 0x4D6EU, 0x4D6FU, 0x4D70U, 0x4D71U, 0x4D72U, 0x4D73U, 0x4D74U, 0x4D75U, 0x4D76U, 0x4D77U, 0x4D78U, 0x4D79U, 0x4D7AU, 0x4D30U, 0x4D31U, 0x4D32U, 0x4D33U, 0x4D34U, 0x4D35U, 0x4D36U, 0x4D37U, 0x4D38U, 0x4D39U, 0x4D2BU, 0x4D2FU, 0x4E41U, 0x4E42U, 0x4E43U, 0x4E44U, 0x4E45U, 0x4E46U, 0x4E47U, 0x4E48U, 0x4E49U, 0x4E4AU, 0x4E4BU, 0x4E4CU, 0x4E4DU, 0x4E4EU, 0x4E4FU, 0x4E50U, 0x4E51U, 0x4E52U, 0x4E53U, 0x4E54U, 0x4E55U, 0x4E56U, 0x4E57U, 0x4E58U, 0x4E59U, 0x4E5AU, 0x4E61U, 0x4E62U, 0x4E63U, 0x4E64U, 0x4E65U, 0x4E66U, 0x4E67U, 0x4E68U, 0x4E69U, 0x4E6AU, 0x4E6BU, 0x4E6CU, 0x4E6DU, 0x4E6EU, 0x4E6FU, 0x4E70U, 0x4E71U, 0x4E72U, 0x4E73U, 0x4E74U, 0x4E75U, 0x4E76U, 0x4E77U, 0x4E78U, 0x4E79U, 0x4E7AU, 0x4E30U, 0x4E31U, 0x4E32U, 0x4E33U, 0x4E34U, 0x4E35U, 0x4E36U, 0x4E37U, 0x4E38U, 0x4E39U, 0x4E2BU, 0x4E2FU, 0x4F41U, 0x4F42U, 0x4F43U, 0x4F44U, 0x4F45U, 0x4F46U, 0x4F47U, 0x4F48U, 0x4F49U, 0x4F4AU, 0x4F4BU, 0x4F4CU, 0x4F4DU, 0x4F4EU, 0x4F4FU, 0x4F50U, 0x4F51U, 0x4F52U, 0x4F53U, 0x4F54U, 0x4F55U, 0x4F56U, 0x4F57U, 0x4F58U, 0x4F59U, 0x4F5AU, 0x4F61U, 0x4F62U, 0x4F63U, 0x4F64U, 0x4F65U, 0x4F66U, 0x4F67U, 0x4F68U, 0x4F69U, 0x4F6AU, 0x4F6BU, 0x4F6CU, 0x4F6DU, 0x4F6EU, 0x4F6FU, 0x4F70U, 0x4F71U, 0x4F72U, 0x4F73U, 0x4F74U, 0x4F75U, 0x4F76U, 0x4F77U, 0x4F78U, 0x4F79U, 0x4F7AU, 0x4F30U, 0x4F31U, 0x4F32U, 0x4F33U, 0x4F34U, 0x4F35U, 0x4F36U, 0x4F37U, 0x4F38U, 0x4F39U, 0x4F2BU, 0x4F2FU, 0x5041U, 0x5042U, 0x5043U, 0x5044U, 0x5045U, 0x5046U, 0x5047U, 0x5048U, 0x5049U, 0x504AU, 0x504BU, 0x504CU, 0x504DU, 0x504EU, 0x504FU, 0x5050U, 0x5051U, 0x5052U, 0x5053U, 0x5054U, 0x5055U, 0x5056U, 0x5057U, 0x5058U, 0x5059U, 0x505AU, 0x5061U, 0x5062U, 0x5063U, 0x5064U, 0x5065U, 0x5066U, 0x5067U, 0x5068U, 0x5069U, 0x506AU, 0x506BU, 0x506CU, 0x506DU, 0x506EU, 0x506FU, 0x5070U, 0x5071U, 0x5072U, 0x5073U, 0x5074U, 0x5075U, 0x5076U, 0x5077U, 0x5078U, 0x5079U, 0x507AU, 0x5030U, 0x5031U, 0x5032U, 0x5033U, 0x5034U, 0x5035U, 0x5036U, 0x5037U, 0x5038U, 0x5039U, 0x502BU, 0x502FU, 0x5141U, 0x5142U, 0x5143U, 0x5144U, 0x5145U, 0x5146U, 0x5147U, 0x5148U, 0x5149U, 0x514AU, 0x514BU, 0x514CU, 0x514DU, 0x514EU, 0x514FU, 0x5150U, 0x5151U, 0x5152U, 0x5153U, 0x5154U, 0x5155U, 0x5156U, 0x5157U, 0x5158U, 0x5159U, 0x515AU, 0x5161U, 0x5162U, 0x5163U, 0x5164U, 0x5165U, 0x5166U, 0x5167U, 0x5168U, 0x5169U, 0x516AU, 0x516BU, 0x516CU, 0x516DU, 0x516EU, 0x516FU, 0x5170U, 0x5171U, 0x5172U, 0x5173U, 0x5174U, 0x5175U, 0x5176U, 0x5177U, 0x5178U, 0x5179U, 0x517AU, 0x5130U, 0x5131U, 0x5132U, 0x5133U, 0x5134U, 0x5135U, 0x5136U, 0x5137U, 0x5138U, 0x5139U, 0x512BU, 0x512FU, 0x5241U, 0x5242U, 0x5243U, 0x5244U, 0x5245U, 0x5246U, 0x5247U, 0x5248U, 0x5249U, 0x524AU, 0x524BU, 0x524CU, 0x524DU, 0x524EU, 0x524FU, 0x5250U, 0x5251U, 0x5252U, 0x5253U, 0x5254U, 0x5255U, 0x5256U, 0x5257U, 0x5258U, 0x5259U, 0x525AU, 0x5261U, 0x5262U, 0x5263U, 0x5264U, 0x5265U, 0x5266U, 0x5267U, 0x5268U, 0x5269U, 0x526AU, 0x526BU, 0x526CU, 0x526DU, 0x526EU, 0x526FU, 0x5270U, 0x5271U, 0x5272U, 0x5273U, 0x5274U, 0x5275U, 0x5276U, 0x5277U, 0x5278U, 0x5279U, 0x527AU, 0x5230U, 0x5231U, 0x5232U, 0x5233U, 0x5234U, 0x5235U, 0x5236U, 0x5237U, 0x5238U, 0x5239U, 0x522BU, 0x522FU, 0x5341U, 0x5342U, 0x5343U, 0x5344U, 0x5345U, 0x5346U, 0x5347U, 0x5348U, 0x5349U, 0x534AU, 0x534BU, 0x534CU, 0x534DU, 0x534EU, 0x534FU, 0x5350U, 0x5351U, 0x5352U, 0x5353U, 0x5354U, 0x5355U, 0x5356U, 0x5357U, 0x5358U, 0x5359U, 0x535AU, 0x5361U, 0x5362U, 0x5363U, 0x5364U, 0x5365U, 0x5366U, 0x5367U, 0x5368U, 0x5369U, 0x536AU, 0x536BU, 0x536CU, 0x536DU, 0x536EU, 0x536FU, 0x5370U, 0x5371U, 0x5372U, 0x5373U, 0x5374U, 0x5375U, 0x5376U, 0x5377U, 0x5378U, 0x5379U, 0x537AU, 0x5330U, 0x5331U, 0x5332U, 0x5333U, 0x5334U, 0x5335U, 0x5336U, 0x5337U, 0x5338U, 0x5339U, 0x532BU, 0x532FU, 0x5441U, 0x5442U, 0x5443U, 0x5444U, 0x5445U, 0x5446U, 0x5447U, 0x5448U, 0x5449U, 0x544AU, 0x544BU, 0x544CU, 0x544DU, 0x544EU, 0x544FU, 0x5450U, 0x5451U, 0x5452U, 0x5453U, 0x5454U, 0x5455U, 0x5456U, 0x5457U, 0x5458U, 0x5459U, 0x545AU, 0x5461U, 0x5462U, 0x5463U, 0x5464U, 0x5465U, 0x5466U, 0x5467U, 0x5468U, 0x5469U, 0x546AU, 0x546BU, 0x546CU, 0x546DU, 0x546EU, 0x546FU, 0x5470U, 0x5471U, 0x5472U, 0x5473U, 0x5474U, 0x5475U, 0x5476U, 0x5477U, 0x5478U, 0x5479U, 0x547AU, 0x5430U, 0x5431U, 0x5432U, 0x5433U, 0x5434U, 0x5435U, 0x5436U, 0x5437U, 0x5438U, 0x5439U, 0x542BU, 0x542FU, 0x5541U, 0x5542U, 0x5543U, 0x5544U, 0x5545U, 0x5546U, 0x5547U, 0x5548U, 0x5549U, 0x554AU, 0x554BU, 0x554CU, 0x554DU, 0x554EU, 0x554FU, 0x5550U, 0x5551U, 0x5552U, 0x5553U, 0x5554U, 0x5555U, 0x5556U, 0x5557U, 0x5558U, 0x5559U, 0x555AU, 0x5561U, 0x5562U, 0x5563U, 0x5564U, 0x5565U, 0x5566U, 0x5567U, 0x5568U, 0x5569U, 0x556AU, 0x556BU, 0x556CU, 0x556DU, 0x556EU, 0x556FU, 0x5570U, 0x5571U, 0x5572U, 0x5573U, 0x5574U, 0x5575U, 0x5576U, 0x5577U, 0x5578U, 0x5579U, 0x557AU, 0x5530U, 0x5531U, 0x5532U, 0x5533U, 0x5534U, 0x5535U, 0x5536U, 0x5537U, 0x5538U, 0x5539U, 0x552BU, 0x552FU, 0x5641U, 0x5642U, 0x5643U, 0x5644U, 0x5645U, 0x5646U, 0x5647U, 0x5648U, 0x5649U, 0x564AU, 0x564BU, 0x564CU, 0x564DU, 0x564EU, 0x564FU, 0x5650U, 0x5651U, 0x5652U, 0x5653U, 0x5654U, 0x5655U, 0x5656U, 0x5657U, 0x5658U, 0x5659U, 0x565AU, 0x5661U, 0x5662U, 0x5663U, 0x5664U, 0x5665U, 0x5666U, 0x5667U, 0x5668U, 0x5669U, 0x566AU, 0x566BU, 0x566CU, 0x566DU, 0x566EU, 0x566FU, 0x5670U, 0x5671U, 0x5672U, 0x5673U, 0x5674U, 0x5675U, 0x5676U, 0x5677U, 0x5678U, 0x5679U, 0x567AU, 0x5630U, 0x5631U, 0x5632U, 0x5633U, 0x5634U, 0x5635U, 0x5636U, 0x5637U, 0x5638U, 0x5639U, 0x562BU, 0x562FU, 0x5741U, 0x5742U, 0x5743U, 0x5744U, 0x5745U, 0x5746U, 0x5747U, 0x5748U, 0x5749U, 0x574AU, 0x574BU, 0x574CU, 0x574DU, 0x574EU, 0x574FU, 0x5750U, 0x5751U, 0x5752U, 0x5753U, 0x5754U, 0x5755U, 0x5756U, 0x5757U, 0x5758U, 0x5759U, 0x575AU, 0x5761U, 0x5762U, 0x5763U, 0x5764U, 0x5765U, 0x5766U, 0x5767U, 0x5768U, 0x5769U, 0x576AU, 0x576BU, 0x576CU, 0x576DU, 0x576EU, 0x576FU, 0x5770U, 0x5771U, 0x5772U, 0x5773U, 0x5774U, 0x5775U, 0x5776U, 0x5777U, 0x5778U, 0x5779U, 0x577AU, 0x5730U, 0x5731U, 0x5732U, 0x5733U, 0x5734U, 0x5735U, 0x5736U, 0x5737U, 0x5738U, 0x5739U, 0x572BU, 0x572FU, 0x5841U, 0x5842U, 0x5843U, 0x5844U, 0x5845U, 0x5846U, 0x5847U, 0x5848U, 0x5849U, 0x584AU, 0x584BU, 0x584CU, 0x584DU, 0x584EU, 0x584FU, 0x5850U, 0x5851U, 0x5852U, 0x5853U, 0x5854U, 0x5855U, 0x5856U, 0x5857U, 0x5858U, 0x5859U, 0x585AU, 0x5861U, 0x5862U, 0x5863U, 0x5864U, 0x5865U, 0x5866U, 0x5867U, 0x5868U, 0x5869U, 0x586AU, 0x586BU, 0x586CU, 0x586DU, 0x586EU, 0x586FU, 0x5870U, 0x5871U, 0x5872U, 0x5873U, 0x5874U, 0x5875U, 0x5876U, 0x5877U, 0x5878U, 0x5879U, 0x587AU, 0x5830U, 0x5831U, 0x5832U, 0x5833U, 0x5834U, 0x5835U, 0x5836U, 0x5837U, 0x5838U, 0x5839U, 0x582BU, 0x582FU, 0x5941U, 0x5942U, 0x5943U, 0x5944U, 0x5945U, 0x5946U, 0x5947U, 0x5948U, 0x5949U, 0x594AU, 0x594BU, 0x594CU, 0x594DU, 0x594EU, 0x594FU, 0x5950U, 0x5951U, 0x5952U, 0x5953U, 0x5954U, 0x5955U, 0x5956U, 0x5957U, 0x5958U, 0x5959U, 0x595AU, 0x5961U, 0x5962U, 0x5963U, 0x5964U, 0x5965U, 0x5966U, 0x5967U, 0x5968U, 0x5969U, 0x596AU, 0x596BU, 0x596CU, 0x596DU, 0x596EU, 0x596FU, 0x5970U, 0x5971U, 0x5972U, 0x5973U, 0x5974U, 0x5975U, 0x5976U, 0x5977U, 0x5978U, 0x5979U, 0x597AU, 0x5930U, 0x5931U, 0x5932U, 0x5933U, 0x5934U, 0x5935U, 0x5936U, 0x5937U, 0x5938U, 0x5939U, 0x592BU, 0x592FU, 0x5A41U, 0x5A42U, 0x5A43U, 0x5A44U, 0x5A45U, 0x5A46U, 0x5A47U, 0x5A48U, 0x5A49U, 0x5A4AU, 0x5A4BU, 0x5A4CU, 0x5A4DU, 0x5A4EU, 0x5A4FU, 0x5A50U, 0x5A51U, 0x5A52U, 0x5A53U, 0x5A54U, 0x5A55U, 0x5A56U, 0x5A57U, 0x5A58U, 0x5A59U, 0x5A5AU, 0x5A61U, 0x5A62U, 0x5A63U, 0x5A64U, 0x5A65U, 0x5A66U, 0x5A67U, 0x5A68U, 0x5A69U, 0x5A6AU, 0x5A6BU, 0x5A6CU, 0x5A6DU, 0x5A6EU, 0x5A6FU, 0x5A70U, 0x5A71U, 0x5A72U, 0x5A73U, 0x5A74U, 0x5A75U, 0x5A76U, 0x5A77U, 0x5A78U, 0x5A79U, 0x5A7AU, 0x5A30U, 0x5A31U, 0x5A32U, 0x5A33U, 0x5A34U, 0x5A35U, 0x5A36U, 0x5A37U, 0x5A38U, 0x5A39U, 0x5A2BU, 0x5A2FU, 0x6141U, 0x6142U, 0x6143U, 0x6144U, 0x6145U, 0x6146U, 0x6147U, 0x6148U, 0x6149U, 0x614AU, 0x614BU, 0x614CU, 0x614DU, 0x614EU, 0x614FU, 0x6150U, 0x6151U, 0x6152U, 0x6153U, 0x6154U, 0x6155U, 0x6156U, 0x6157U, 0x6158U, 0x6159U, 0x615AU, 0x6161U, 0x6162U, 0x6163U, 0x6164U, 0x6165U, 0x6166U, 0x6167U, 0x6168U, 0x6169U, 0x616AU, 0x616BU, 0x616CU, 0x616DU, 0x616EU, 0x616FU, 0x6170U, 0x6171U, 0x6172U, 0x6173U, 0x6174U, 0x6175U, 0x6176U, 0x6177U, 0x6178U, 0x6179U, 0x617AU, 0x6130U, 0x6131U, 0x6132U, 0x6133U, 0x6134U, 0x6135U, 0x6136U, 0x6137U, 0x6138U, 0x6139U, 0x612BU, 0x612FU, 0x6241U, 0x6242U, 0x6243U, 0x6244U, 0x6245U, 0x6246U, 0x6247U, 0x6248U, 0x6249U, 0x624AU, 0x624BU, 0x624CU, 0x624DU, 0x624EU, 0x624FU, 0x6250U, 0x6251U, 0x6252U, 0x6253U, 0x6254U, 0x6255U, 0x6256U, 0x6257U, 0x6258U, 0x6259U, 0x625AU, 0x6261U, 0x6262U, 0x6263U, 0x6264U, 0x6265U, 0x6266U, 0x6267U, 0x6268U, 0x6269U, 0x626AU, 0x626BU, 0x626CU, 0x626DU, 0x626EU, 0x626FU, 0x6270U, 0x6271U, 0x6272U, 0x6273U, 0x6274U, 0x6275U, 0x6276U, 0x6277U, 0x6278U, 0x6279U, 0x627AU, 0x6230U, 0x6231U, 0x6232U, 0x6233U, 0x6234U, 0x6235U, 0x6236U, 0x6237U, 0x6238U, 0x6239U, 0x622BU, 0x622FU, 0x6341U, 0x6342U, 0x6343U, 0x6344U, 0x6345U, 0x6346U, 0x6347U, 0x6348U, 0x6349U, 0x634AU, 0x634BU, 0x634CU, 0x634DU, 0x634EU, 0x634FU, 0x6350U, 0x6351U, 0x6352U, 0x6353U, 0x6354U, 0x6355U, 0x6356U, 0x6357U, 0x6358U, 0x6359U, 0x635AU, 0x6361U, 0x6362U, 0x6363U, 0x6364U, 0x6365U, 0x6366U, 0x6367U, 0x6368U, 0x6369U, 0x636AU, 0x636BU, 0x636CU, 0x636DU, 0x636EU, 0x636FU, 0x6370U, 0x6371U, 0x6372U, 0x6373U, 0x6374U, 0x6375U, 0x6376U, 0x6377U, 0x6378U, 0x6379U, 0x637AU, 0x6330U, 0x6331U, 0x6332U, 0x6333U, 0x6334U, 0x6335U, 0x6336U, 0x6337U, 0x6338U, 0x6339U, 0x632BU, 0x632FU, 0x6441U, 0x6442U, 0x6443U, 0x6444U, 0x6445U, 0x6446U, 0x6447U, 0x6448U, 0x6449U, 0x644AU, 0x644BU, 0x644CU, 0x644DU, 0x644EU, 0x644FU, 0x6450U, 0x6451U, 0x6452U, 0x6453U, 0x6454U, 0x6455U, 0x6456U, 0x6457U, 0x6458U, 0x6459U, 0x645AU, 0x6461U, 0x6462U, 0x6463U, 0x6464U, 0x6465U, 0x6466U, 0x6467U, 0x6468U, 0x6469U, 0x646AU, 0x646BU, 0x646CU, 0x646DU, 0x646EU, 0x646FU, 0x6470U, 0x6471U, 0x6472U, 0x6473U, 0x6474U, 0x6475U, 0x6476U, 0x6477U, 0x6478U, 0x6479U, 0x647AU, 0x6430U, 0x6431U, 0x6432U, 0x6433U, 0x6434U, 0x6435U, 0x6436U, 0x6437U, 0x6438U, 0x6439U, 0x642BU, 0x642FU, 0x6541U, 0x6542U, 0x6543U, 0x6544U, 0x6545U, 0x6546U, 0x6547U, 0x6548U, 0x6549U, 0x654AU, 0x654BU, 0x654CU, 0x654DU, 0x654EU, 0x654FU, 0x6550U, 0x6551U, 0x6552U, 0x6553U, 0x6554U, 0x6555U, 0x6556U, 0x6557U, 0x6558U, 0x6559U, 0x655AU, 0x6561U, 0x6562U, 0x6563U, 0x6564U, 0x6565U, 0x6566U, 0x6567U, 0x6568U, 0x6569U, 0x656AU, 0x656BU, 0x656CU, 0x656DU, 0x656EU, 0x656FU, 0x6570U, 0x6571U, 0x6572U, 0x6573U, 0x6574U, 0x6575U, 0x6576U, 0x6577U, 0x6578U, 0x6579U, 0x657AU, 0x6530U, 0x6531U, 0x6532U, 0x6533U, 0x6534U, 0x6535U, 0x6536U, 0x6537U, 0x6538U, 0x6539U, 0x652BU, 0x652FU, 0x6641U, 0x6642U, 0x6643U, 0x6644U, 0x6645U, 0x6646U, 0x6647U, 0x6648U, 0x6649U, 0x664AU, 0x664BU, 0x664CU, 0x664DU, 0x664EU, 0x664FU, 0x6650U, 0x6651U, 0x6652U, 0x6653U, 0x6654U, 0x6655U, 0x6656U, 0x6657U, 0x6658U, 0x6659U, 0x665AU, 0x6661U, 0x6662U, 0x6663U, 0x6664U, 0x6665U, 0x6666U, 0x6667U, 0x6668U, 0x6669U, 0x666AU, 0x666BU, 0x666CU, 0x666DU, 0x666EU, 0x666FU, 0x6670U, 0x6671U, 0x6672U, 0x6673U, 0x6674U, 0x6675U, 0x6676U, 0x6677U, 0x6678U, 0x6679U, 0x667AU, 0x6630U, 0x6631U, 0x6632U, 0x6633U, 0x6634U, 0x6635U, 0x6636U, 0x6637U, 0x6638U, 0x6639U, 0x662BU, 0x662FU, 0x6741U, 0x6742U, 0x6743U, 0x6744U, 0x6745U, 0x6746U, 0x6747U, 0x6748U, 0x6749U, 0x674AU, 0x674BU, 0x674CU, 0x674DU, 0x674EU, 0x674FU, 0x6750U, 0x6751U, 0x6752U, 0x6753U, 0x6754U, 0x6755U, 0x6756U, 0x6757U, 0x6758U, 0x6759U, 0x675AU, 0x6761U, 0x6762U, 0x6763U, 0x6764U, 0x6765U, 0x6766U, 0x6767U, 0x6768U, 0x6769U, 0x676AU, 0x676BU, 0x676CU, 0x676DU, 0x676EU, 0x676FU, 0x6770U, 0x6771U, 0x6772U, 0x6773U, 0x6774U, 0x6775U, 0x6776U, 0x6777U, 0x6778U, 0x6779U, 0x677AU, 0x6730U, 0x6731U, 0x6732U, 0x6733U, 0x6734U, 0x6735U, 0x6736U, 0x6737U, 0x6738U, 0x6739U, 0x672BU, 0x672FU, 0x6841U, 0x6842U, 0x6843U, 0x6844U, 0x6845U, 0x6846U, 0x6847U, 0x6848U, 0x6849U, 0x684AU, 0x684BU, 0x684CU, 0x684DU, 0x684EU, 0x684FU, 0x6850U, 0x6851U, 0x6852U, 0x6853U, 0x6854U, 0x6855U, 0x6856U, 0x6857U, 0x6858U, 0x6859U, 0x685AU, 0x6861U, 0x6862U, 0x6863U, 0x6864U, 0x6865U, 0x6866U, 0x6867U, 0x6868U, 0x6869U, 0x686AU, 0x686BU, 0x686CU, 0x686DU, 0x686EU, 0x686FU, 0x6870U, 0x6871U, 0x6872U, 0x6873U, 0x6874U, 0x6875U, 0x6876U, 0x6877U, 0x6878U, 0x6879U, 0x687AU, 0x6830U, 0x6831U, 0x6832U, 0x6833U, 0x6834U, 0x6835U, 0x6836U, 0x6837U, 0x6838U, 0x6839U, 0x682BU, 0x682FU, 0x6941U, 0x6942U, 0x6943U, 0x6944U, 0x6945U, 0x6946U, 0x6947U, 0x6948U, 0x6949U, 0x694AU, 0x694BU, 0x694CU, 0x694DU, 0x694EU, 0x694FU, 0x6950U, 0x6951U, 0x6952U, 0x6953U, 0x6954U, 0x6955U, 0x6956U, 0x6957U, 0x6958U, 0x6959U, 0x695AU, 0x6961U, 0x6962U, 0x6963U, 0x6964U, 0x6965U, 0x6966U, 0x6967U, 0x6968U, 0x6969U, 0x696AU, 0x696BU, 0x696CU, 0x696DU, 0x696EU, 0x696FU, 0x6970U, 0x6971U, 0x6972U, 0x6973U, 0x6974U, 0x6975U, 0x6976U, 0x6977U, 0x6978U, 0x6979U, 0x697AU, 0x6930U, 0x6931U, 0x6932U, 0x6933U, 0x6934U, 0x6935U, 0x6936U, 0x6937U, 0x6938U, 0x6939U, 0x692BU, 0x692FU, 0x6A41U, 0x6A42U, 0x6A43U, 0x6A44U, 0x6A45U, 0x6A46U, 0x6A47U, 0x6A48U, 0x6A49U, 0x6A4AU, 0x6A4BU, 0x6A4CU, 0x6A4DU, 0x6A4EU, 0x6A4FU, 0x6A50U, 0x6A51U, 0x6A52U, 0x6A53U, 0x6A54U, 0x6A55U, 0x6A56U, 0x6A57U, 0x6A58U, 0x6A59U, 0x6A5AU, 0x6A61U, 0x6A62U, 0x6A63U, 0x6A64U, 0x6A65U, 0x6A66U, 0x6A67U, 0x6A68U, 0x6A69U, 0x6A6AU, 0x6A6BU, 0x6A6CU, 0x6A6DU, 0x6A6EU, 0x6A6FU, 0x6A70U, 0x6A71U, 0x6A72U, 0x6A73U, 0x6A74U, 0x6A75U, 0x6A76U, 0x6A77U, 0x6A78U, 0x6A79U, 0x6A7AU, 0x6A30U, 0x6A31U, 0x6A32U, 0x6A33U, 0x6A34U, 0x6A35U, 0x6A36U, 0x6A37U, 0x6A38U, 0x6A39U, 0x6A2BU, 0x6A2FU, 0x6B41U, 0x6B42U, 0x6B43U, 0x6B44U, 0x6B45U, 0x6B46U, 0x6B47U, 0x6B48U, 0x6B49U, 0x6B4AU, 0x6B4BU, 0x6B4CU, 0x6B4DU, 0x6B4EU, 0x6B4FU, 0x6B50U, 0x6B51U, 0x6B52U, 0x6B53U, 0x6B54U, 0x6B55U, 0x6B56U, 0x6B57U, 0x6B58U, 0x6B59U, 0x6B5AU, 0x6B61U, 0x6B62U, 0x6B63U, 0x6B64U, 0x6B65U, 0x6B66U, 0x6B67U, 0x6B68U, 0x6B69U, 0x6B6AU, 0x6B6BU, 0x6B6CU, 0x6B6DU, 0x6B6EU, 0x6B6FU, 0x6B70U, 0x6B71U, 0x6B72U, 0x6B73U, 0x6B74U, 0x6B75U, 0x6B76U, 0x6B77U, 0x6B78U, 0x6B79U, 0x6B7AU, 0x6B30U, 0x6B31U, 0x6B32U, 0x6B33U, 0x6B34U, 0x6B35U, 0x6B36U, 0x6B37U, 0x6B38U, 0x6B39U, 0x6B2BU, 0x6B2FU, 0x6C41U, 0x6C42U, 0x6C43U, 0x6C44U, 0x6C45U, 0x6C46U, 0x6C47U, 0x6C48U, 0x6C49U, 0x6C4AU, 0x6C4BU, 0x6C4CU, 0x6C4DU, 0x6C4EU, 0x6C4FU, 0x6C50U, 0x6C51U, 0x6C52U, 0x6C53U, 0x6C54U, 0x6C55U, 0x6C56U, 0x6C57U, 0x6C58U, 0x6C59U, 0x6C5AU, 0x6C61U, 0x6C62U, 0x6C63U, 0x6C64U, 0x6C65U, 0x6C66U, 0x6C67U, 0x6C68U, 0x6C69U, 0x6C6AU, 0x6C6BU, 0x6C6CU, 0x6C6DU, 0x6C6EU, 0x6C6FU, 0x6C70U, 0x6C71U, 0x6C72U, 0x6C73U, 0x6C74U, 0x6C75U, 0x6C76U, 0x6C77U, 0x6C78U, 0x6C79U, 0x6C7AU, 0x6C30U, 0x6C31U, 0x6C32U, 0x6C33U, 0x6C34U, 0x6C35U, 0x6C36U, 0x6C37U, 0x6C38U, 0x6C39U, 0x6C2BU, 0x6C2FU, 0x6D41U, 0x6D42U, 0x6D43U, 0x6D44U, 0x6D45U, 0x6D46U, 0x6D47U, 0x6D48U, 0x6D49U, 0x6D4AU, 0x6D4BU, 0x6D4CU, 0x6D4DU, 0x6D4EU, 0x6D4FU, 0x6D50U, 0x6D51U, 0x6D52U, 0x6D53U, 0x6D54U, 0x6D55U, 0x6D56U, 0x6D57U, 0x6D58U, 0x6D59U, 0x6D5AU, 0x6D61U, 0x6D62U, 0x6D63U, 0x6D64U, 0x6D65U, 0x6D66U, 0x6D67U, 0x6D68U, 0x6D69U, 0x6D6AU, 0x6D6BU, 0x6D6CU, 0x6D6DU, 0x6D6EU, 0x6D6FU, 0x6D70U, 0x6D71U, 0x6D72U, 0x6D73U, 0x6D74U, 0x6D75U, 0x6D76U, 0x6D77U, 0x6D78U, 0x6D79U, 0x6D7AU, 0x6D30U, 0x6D31U, 0x6D32U, 0x6D33U, 0x6D34U, 0x6D35U, 0x6D36U, 0x6D37U, 0x6D38U, 0x6D39U, 0x6D2BU, 0x6D2FU, 0x6E41U, 0x6E42U, 0x6E43U, 0x6E44U, 0x6E45U, 0x6E46U, 0x6E47U, 0x6E48U, 0x6E49U, 0x6E4AU, 0x6E4BU, 0x6E4CU, 0x6E4DU, 0x6E4EU, 0x6E4FU, 0x6E50U, 0x6E51U, 0x6E52U, 0x6E53U, 0x6E54U, 0x6E55U, 0x6E56U, 0x6E57U, 0x6E58U, 0x6E59U, 0x6E5AU, 0x6E61U, 0x6E62U, 0x6E63U, 0x6E64U, 0x6E65U, 0x6E66U, 0x6E67U, 0x6E68U, 0x6E69U, 0x6E6AU, 0x6E6BU, 0x6E6CU, 0x6E6DU, 0x6E6EU, 0x6E6FU, 0x6E70U, 0x6E71U, 0x6E72U, 0x6E73U, 0x6E74U, 0x6E75U, 0x6E76U, 0x6E77U, 0x6E78U, 0x6E79U, 0x6E7AU, 0x6E30U, 0x6E31U, 0x6E32U, 0x6E33U, 0x6E34U, 0x6E35U, 0x6E36U, 0x6E37U, 0x6E38U, 0x6E39U, 0x6E2BU, 0x6E2FU, 0x6F41U, 0x6F42U, 0x6F43U, 0x6F44U, 0x6F45U, 0x6F46U, 0x6F47U, 0x6F48U, 0x6F49U, 0x6F4AU, 0x6F4BU, 0x6F4CU, 0x6F4DU, 0x6F4EU, 0x6F4FU, 0x6F50U, 0x6F51U, 0x6F52U, 0x6F53U, 0x6F54U, 0x6F55U, 0x6F56U, 0x6F57U, 0x6F58U, 0x6F59U, 0x6F5AU, 0x6F61U, 0x6F62U, 0x6F63U, 0x6F64U, 0x6F65U, 0x6F66U, 0x6F67U, 0x6F68U, 0x6F69U, 0x6F6AU, 0x6F6BU, 0x6F6CU, 0x6F6DU, 0x6F6EU, 0x6F6FU, 0x6F70U, 0x6F71U, 0x6F72U, 0x6F73U, 0x6F74U, 0x6F75U, 0x6F76U, 0x6F77U, 0x6F78U, 0x6F79U, 0x6F7AU, 0x6F30U, 0x6F31U, 0x6F32U, 0x6F33U, 0x6F34U, 0x6F35U, 0x6F36U, 0x6F37U, 0x6F38U, 0x6F39U, 0x6F2BU, 0x6F2FU, 0x7041U, 0x7042U, 0x7043U, 0x7044U, 0x7045U, 0x7046U, 0x7047U, 0x7048U, 0x7049U, 0x704AU, 0x704BU, 0x704CU, 0x704DU, 0x704EU, 0x704FU, 0x7050U, 0x7051U, 0x7052U, 0x7053U, 0x7054U, 0x7055U, 0x7056U, 0x7057U, 0x7058U, 0x7059U, 0x705AU, 0x7061U, 0x7062U, 0x7063U, 0x7064U, 0x7065U, 0x7066U, 0x7067U, 0x7068U, 0x7069U, 0x706AU, 0x706BU, 0x706CU, 0x706DU, 0x706EU, 0x706FU, 0x7070U, 0x7071U, 0x7072U, 0x7073U, 0x7074U, 0x7075U, 0x7076U, 0x7077U, 0x7078U, 0x7079U, 0x707AU, 0x7030U, 0x7031U, 0x7032U, 0x7033U, 0x7034U, 0x7035U, 0x7036U, 0x7037U, 0x7038U, 0x7039U, 0x702BU, 0x702FU, 0x7141U, 0x7142U, 0x7143U, 0x7144U, 0x7145U, 0x7146U, 0x7147U, 0x7148U, 0x7149U, 0x714AU, 0x714BU, 0x714CU, 0x714DU, 0x714EU, 0x714FU, 0x7150U, 0x7151U, 0x7152U, 0x7153U, 0x7154U, 0x7155U, 0x7156U, 0x7157U, 0x7158U, 0x7159U, 0x715AU, 0x7161U, 0x7162U, 0x7163U, 0x7164U, 0x7165U, 0x7166U, 0x7167U, 0x7168U, 0x7169U, 0x716AU, 0x716BU, 0x716CU, 0x716DU, 0x716EU, 0x716FU, 0x7170U, 0x7171U, 0x7172U, 0x7173U, 0x7174U, 0x7175U, 0x7176U, 0x7177U, 0x7178U, 0x7179U, 0x717AU, 0x7130U, 0x7131U, 0x7132U, 0x7133U, 0x7134U, 0x7135U, 0x7136U, 0x7137U, 0x7138U, 0x7139U, 0x712BU, 0x712FU, 0x7241U, 0x7242U, 0x7243U, 0x7244U, 0x7245U, 0x7246U, 0x7247U, 0x7248U, 0x7249U, 0x724AU, 0x724BU, 0x724CU, 0x724DU, 0x724EU, 0x724FU, 0x7250U, 0x7251U, 0x7252U, 0x7253U, 0x7254U, 0x7255U, 0x7256U, 0x7257U, 0x7258U, 0x7259U, 0x725AU, 0x7261U, 0x7262U, 0x7263U, 0x7264U, 0x7265U, 0x7266U, 0x7267U, 0x7268U, 0x7269U, 0x726AU, 0x726BU, 0x726CU, 0x726DU, 0x726EU, 0x726FU, 0x7270U, 0x7271U, 0x7272U, 0x7273U, 0x7274U, 0x7275U, 0x7276U, 0x7277U, 0x7278U, 0x7279U, 0x727AU, 0x7230U, 0x7231U, 0x7232U, 0x7233U, 0x7234U, 0x7235U, 0x7236U, 0x7237U, 0x7238U, 0x7239U, 0x722BU, 0x722FU, 0x7341U, 0x7342U, 0x7343U, 0x7344U, 0x7345U, 0x7346U, 0x7347U, 0x7348U, 0x7349U, 0x734AU, 0x734BU, 0x734CU, 0x734DU, 0x734EU, 0x734FU, 0x7350U, 0x7351U, 0x7352U, 0x7353U, 0x7354U, 0x7355U, 0x7356U, 0x7357U, 0x7358U, 0x7359U, 0x735AU, 0x7361U, 0x7362U, 0x7363U, 0x7364U, 0x7365U, 0x7366U, 0x7367U, 0x7368U, 0x7369U, 0x736AU, 0x736BU, 0x736CU, 0x736DU, 0x736EU, 0x736FU, 0x7370U, 0x7371U, 0x7372U, 0x7373U, 0x7374U, 0x7375U, 0x7376U, 0x7377U, 0x7378U, 0x7379U, 0x737AU, 0x7330U, 0x7331U, 0x7332U, 0x7333U, 0x7334U, 0x7335U, 0x7336U, 0x7337U, 0x7338U, 0x7339U, 0x732BU, 0x732FU, 0x7441U, 0x7442U, 0x7443U, 0x7444U, 0x7445U, 0x7446U, 0x7447U, 0x7448U, 0x7449U, 0x744AU, 0x744BU, 0x744CU, 0x744DU, 0x744EU, 0x744FU, 0x7450U, 0x7451U, 0x7452U, 0x7453U, 0x7454U, 0x7455U, 0x7456U, 0x7457U, 0x7458U, 0x7459U, 0x745AU, 0x7461U, 0x7462U, 0x7463U, 0x7464U, 0x7465U, 0x7466U, 0x7467U, 0x7468U, 0x7469U, 0x746AU, 0x746BU, 0x746CU, 0x746DU, 0x746EU, 0x746FU, 0x7470U, 0x7471U, 0x7472U, 0x7473U, 0x7474U, 0x7475U, 0x7476U, 0x7477U, 0x7478U, 0x7479U, 0x747AU, 0x7430U, 0x7431U, 0x7432U, 0x7433U, 0x7434U, 0x7435U, 0x7436U, 0x7437U, 0x7438U, 0x7439U, 0x742BU, 0x742FU, 0x7541U, 0x7542U, 0x7543U, 0x7544U, 0x7545U, 0x7546U, 0x7547U, 0x7548U, 0x7549U, 0x754AU, 0x754BU, 0x754CU, 0x754DU, 0x754EU, 0x754FU, 0x7550U, 0x7551U, 0x7552U, 0x7553U, 0x7554U, 0x7555U, 0x7556U, 0x7557U, 0x7558U, 0x7559U, 0x755AU, 0x7561U, 0x7562U, 0x7563U, 0x7564U, 0x7565U, 0x7566U, 0x7567U, 0x7568U, 0x7569U, 0x756AU, 0x756BU, 0x756CU, 0x756DU, 0x756EU, 0x756FU, 0x7570U, 0x7571U, 0x7572U, 0x7573U, 0x7574U, 0x7575U, 0x7576U, 0x7577U, 0x7578U, 0x7579U, 0x757AU, 0x7530U, 0x7531U, 0x7532U, 0x7533U, 0x7534U, 0x7535U, 0x7536U, 0x7537U, 0x7538U, 0x7539U, 0x752BU, 0x752FU, 0x7641U, 0x7642U, 0x7643U, 0x7644U, 0x7645U, 0x7646U, 0x7647U, 0x7648U, 0x7649U, 0x764AU, 0x764BU, 0x764CU, 0x764DU, 0x764EU, 0x764FU, 0x7650U, 0x7651U, 0x7652U, 0x7653U, 0x7654U, 0x7655U, 0x7656U, 0x7657U, 0x7658U, 0x7659U, 0x765AU, 0x7661U, 0x7662U, 0x7663U, 0x7664U, 0x7665U, 0x7666U, 0x7667U, 0x7668U, 0x7669U, 0x766AU, 0x766BU, 0x766CU, 0x766DU, 0x766EU, 0x766FU, 0x7670U, 0x7671U, 0x7672U, 0x7673U, 0x7674U, 0x7675U, 0x7676U, 0x7677U, 0x7678U, 0x7679U, 0x767AU, 0x7630U, 0x7631U, 0x7632U, 0x7633U, 0x7634U, 0x7635U, 0x7636U, 0x7637U, 0x7638U, 0x7639U, 0x762BU, 0x762FU, 0x7741U, 0x7742U, 0x7743U, 0x7744U, 0x7745U, 0x7746U, 0x7747U, 0x7748U, 0x7749U, 0x774AU, 0x774BU, 0x774CU, 0x774DU, 0x774EU, 0x774FU, 0x7750U, 0x7751U, 0x7752U, 0x7753U, 0x7754U, 0x7755U, 0x7756U, 0x7757U, 0x7758U, 0x7759U, 0x775AU, 0x7761U, 0x7762U, 0x7763U, 0x7764U, 0x7765U, 0x7766U, 0x7767U, 0x7768U, 0x7769U, 0x776AU, 0x776BU, 0x776CU, 0x776DU, 0x776EU, 0x776FU, 0x7770U, 0x7771U, 0x7772U, 0x7773U, 0x7774U, 0x7775U, 0x7776U, 0x7777U, 0x7778U, 0x7779U, 0x777AU, 0x7730U, 0x7731U, 0x7732U, 0x7733U, 0x7734U, 0x7735U, 0x7736U, 0x7737U, 0x7738U, 0x7739U, 0x772BU, 0x772FU, 0x7841U, 0x7842U, 0x7843U, 0x7844U, 0x7845U, 0x7846U, 0x7847U, 0x7848U, 0x7849U, 0x784AU, 0x784BU, 0x784CU, 0x784DU, 0x784EU, 0x784FU, 0x7850U, 0x7851U, 0x7852U, 0x7853U, 0x7854U, 0x7855U, 0x7856U, 0x7857U, 0x7858U, 0x7859U, 0x785AU, 0x7861U, 0x7862U, 0x7863U, 0x7864U, 0x7865U, 0x7866U, 0x7867U, 0x7868U, 0x7869U, 0x786AU, 0x786BU, 0x786CU, 0x786DU, 0x786EU, 0x786FU, 0x7870U, 0x7871U, 0x7872U, 0x7873U, 0x7874U, 0x7875U, 0x7876U, 0x7877U, 0x7878U, 0x7879U, 0x787AU, 0x7830U, 0x7831U, 0x7832U, 0x7833U, 0x7834U, 0x7835U, 0x7836U, 0x7837U, 0x7838U, 0x7839U, 0x782BU, 0x782FU, 0x7941U, 0x7942U, 0x7943U, 0x7944U, 0x7945U, 0x7946U, 0x7947U, 0x7948U, 0x7949U, 0x794AU, 0x794BU, 0x794CU, 0x794DU, 0x794EU, 0x794FU, 0x7950U, 0x7951U, 0x7952U, 0x7953U, 0x7954U, 0x7955U, 0x7956U, 0x7957U, 0x7958U, 0x7959U, 0x795AU, 0x7961U, 0x7962U, 0x7963U, 0x7964U, 0x7965U, 0x7966U, 0x7967U, 0x7968U, 0x7969U, 0x796AU, 0x796BU, 0x796CU, 0x796DU, 0x796EU, 0x796FU, 0x7970U, 0x7971U, 0x7972U, 0x7973U, 0x7974U, 0x7975U, 0x7976U, 0x7977U, 0x7978U, 0x7979U, 0x797AU, 0x7930U, 0x7931U, 0x7932U, 0x7933U, 0x7934U, 0x7935U, 0x7936U, 0x7937U, 0x7938U, 0x7939U, 0x792BU, 0x792FU, 0x7A41U, 0x7A42U, 0x7A43U, 0x7A44U, 0x7A45U, 0x7A46U, 0x7A47U, 0x7A48U, 0x7A49U, 0x7A4AU, 0x7A4BU, 0x7A4CU, 0x7A4DU, 0x7A4EU, 0x7A4FU, 0x7A50U, 0x7A51U, 0x7A52U, 0x7A53U, 0x7A54U, 0x7A55U, 0x7A56U, 0x7A57U, 0x7A58U, 0x7A59U, 0x7A5AU, 0x7A61U, 0x7A62U, 0x7A63U, 0x7A64U, 0x7A65U, 0x7A66U, 0x7A67U, 0x7A68U, 0x7A69U, 0x7A6AU, 0x7A6BU, 0x7A6CU, 0x7A6DU, 0x7A6EU, 0x7A6FU, 0x7A70U, 0x7A71U, 0x7A72U, 0x7A73U, 0x7A74U, 0x7A75U, 0x7A76U, 0x7A77U, 0x7A78U, 0x7A79U, 0x7A7AU, 0x7A30U, 0x7A31U, 0x7A32U, 0x7A33U, 0x7A34U, 0x7A35U, 0x7A36U, 0x7A37U, 0x7A38U, 0x7A39U, 0x7A2BU, 0x7A2FU, 0x3041U, 0x3042U, 0x3043U, 0x3044U, 0x3045U, 0x3046U, 0x3047U, 0x3048U, 0x3049U, 0x304AU, 0x304BU, 0x304CU, 0x304DU, 0x304EU, 0x304FU, 0x3050U, 0x3051U, 0x3052U, 0x3053U, 0x3054U, 0x3055U, 0x3056U, 0x3057U, 0x3058U, 0x3059U, 0x305AU, 0x3061U, 0x3062U, 0x3063U, 0x3064U, 0x3065U, 0x3066U, 0x3067U, 0x3068U, 0x3069U, 0x306AU, 0x306BU, 0x306CU, 0x306DU, 0x306EU, 0x306FU, 0x3070U, 0x3071U, 0x3072U, 0x3073U, 0x3074U, 0x3075U, 0x3076U, 0x3077U, 0x3078U, 0x3079U, 0x307AU, 0x3030U, 0x3031U, 0x3032U, 0x3033U, 0x3034U, 0x3035U, 0x3036U, 0x3037U, 0x3038U, 0x3039U, 0x302BU, 0x302FU, 0x3141U, 0x3142U, 0x3143U, 0x3144U, 0x3145U, 0x3146U, 0x3147U, 0x3148U, 0x3149U, 0x314AU, 0x314BU, 0x314CU, 0x314DU, 0x314EU, 0x314FU, 0x3150U, 0x3151U, 0x3152U, 0x3153U, 0x3154U, 0x3155U, 0x3156U, 0x3157U, 0x3158U, 0x3159U, 0x315AU, 0x3161U, 0x3162U, 0x3163U, 0x3164U, 0x3165U, 0x3166U, 0x3167U, 0x3168U, 0x3169U, 0x316AU, 0x316BU, 0x316CU, 0x316DU, 0x316EU, 0x316FU, 0x3170U, 0x3171U, 0x3172U, 0x3173U, 0x3174U, 0x3175U, 0x3176U, 0x3177U, 0x3178U, 0x3179U, 0x317AU, 0x3130U, 0x3131U, 0x3132U, 0x3133U, 0x3134U, 0x3135U, 0x3136U, 0x3137U, 0x3138U, 0x3139U, 0x312BU, 0x312FU, 0x3241U, 0x3242U, 0x3243U, 0x3244U, 0x3245U, 0x3246U, 0x3247U, 0x3248U, 0x3249U, 0x324AU, 0x324BU, 0x324CU, 0x324DU, 0x324EU, 0x324FU, 0x3250U, 0x3251U, 0x3252U, 0x3253U, 0x3254U, 0x3255U, 0x3256U, 0x3257U, 0x3258U, 0x3259U, 0x325AU, 0x3261U, 0x3262U, 0x3263U, 0x3264U, 0x3265U, 0x3266U, 0x3267U, 0x3268U, 0x3269U, 0x326AU, 0x326BU, 0x326CU, 0x326DU, 0x326EU, 0x326FU, 0x3270U, 0x3271U, 0x3272U, 0x3273U, 0x3274U, 0x3275U, 0x3276U, 0x3277U, 0x3278U, 0x3279U, 0x327AU, 0x3230U, 0x3231U, 0x3232U, 0x3233U, 0x3234U, 0x3235U, 0x3236U, 0x3237U, 0x3238U, 0x3239U, 0x322BU, 0x322FU, 0x3341U, 0x3342U, 0x3343U, 0x3344U, 0x3345U, 0x3346U, 0x3347U, 0x3348U, 0x3349U, 0x334AU, 0x334BU, 0x334CU, 0x334DU, 0x334EU, 0x334FU, 0x3350U, 0x3351U, 0x3352U, 0x3353U, 0x3354U, 0x3355U, 0x3356U, 0x3357U, 0x3358U, 0x3359U, 0x335AU, 0x3361U, 0x3362U, 0x3363U, 0x3364U, 0x3365U, 0x3366U, 0x3367U, 0x3368U, 0x3369U, 0x336AU, 0x336BU, 0x336CU, 0x336DU, 0x336EU, 0x336FU, 0x3370U, 0x3371U, 0x3372U, 0x3373U, 0x3374U, 0x3375U, 0x3376U, 0x3377U, 0x3378U, 0x3379U, 0x337AU, 0x3330U, 0x3331U, 0x3332U, 0x3333U, 0x3334U, 0x3335U, 0x3336U, 0x3337U, 0x3338U, 0x3339U, 0x332BU, 0x332FU, 0x3441U, 0x3442U, 0x3443U, 0x3444U, 0x3445U, 0x3446U, 0x3447U, 0x3448U, 0x3449U, 0x344AU, 0x344BU, 0x344CU, 0x344DU, 0x344EU, 0x344FU, 0x3450U, 0x3451U, 0x3452U, 0x3453U, 0x3454U, 0x3455U, 0x3456U, 0x3457U, 0x3458U, 0x3459U, 0x345AU, 0x3461U, 0x3462U, 0x3463U, 0x3464U, 0x3465U, 0x3466U, 0x3467U, 0x3468U, 0x3469U, 0x346AU, 0x346BU, 0x346CU, 0x346DU, 0x346EU, 0x346FU, 0x3470U, 0x3471U, 0x3472U, 0x3473U, 0x3474U, 0x3475U, 0x3476U, 0x3477U, 0x3478U, 0x3479U, 0x347AU, 0x3430U, 0x3431U, 0x3432U, 0x3433U, 0x3434U, 0x3435U, 0x3436U, 0x3437U, 0x3438U, 0x3439U, 0x342BU, 0x342FU, 0x3541U, 0x3542U, 0x3543U, 0x3544U, 0x3545U, 0x3546U, 0x3547U, 0x3548U, 0x3549U, 0x354AU, 0x354BU, 0x354CU, 0x354DU, 0x354EU, 0x354FU, 0x3550U, 0x3551U, 0x3552U, 0x3553U, 0x3554U, 0x3555U, 0x3556U, 0x3557U, 0x3558U, 0x3559U, 0x355AU, 0x3561U, 0x3562U, 0x3563U, 0x3564U, 0x3565U, 0x3566U, 0x3567U, 0x3568U, 0x3569U, 0x356AU, 0x356BU, 0x356CU, 0x356DU, 0x356EU, 0x356FU, 0x3570U, 0x3571U, 0x3572U, 0x3573U, 0x3574U, 0x3575U, 0x3576U, 0x3577U, 0x3578U, 0x3579U, 0x357AU, 0x3530U, 0x3531U, 0x3532U, 0x3533U, 0x3534U, 0x3535U, 0x3536U, 0x3537U, 0x3538U, 0x3539U, 0x352BU, 0x352FU, 0x3641U, 0x3642U, 0x3643U, 0x3644U, 0x3645U, 0x3646U, 0x3647U, 0x3648U, 0x3649U, 0x364AU, 0x364BU, 0x364CU, 0x364DU, 0x364EU, 0x364FU, 0x3650U, 0x3651U, 0x3652U, 0x3653U, 0x3654U, 0x3655U, 0x3656U, 0x3657U, 0x3658U, 0x3659U, 0x365AU, 0x3661U, 0x3662U, 0x3663U, 0x3664U, 0x3665U, 0x3666U, 0x3667U, 0x3668U, 0x3669U, 0x366AU, 0x366BU, 0x366CU, 0x366DU, 0x366EU, 0x366FU, 0x3670U, 0x3671U, 0x3672U, 0x3673U, 0x3674U, 0x3675U, 0x3676U, 0x3677U, 0x3678U, 0x3679U, 0x367AU, 0x3630U, 0x3631U, 0x3632U, 0x3633U, 0x3634U, 0x3635U, 0x3636U, 0x3637U, 0x3638U, 0x3639U, 0x362BU, 0x362FU, 0x3741U, 0x3742U, 0x3743U, 0x3744U, 0x3745U, 0x3746U, 0x3747U, 0x3748U, 0x3749U, 0x374AU, 0x374BU, 0x374CU, 0x374DU, 0x374EU, 0x374FU, 0x3750U, 0x3751U, 0x3752U, 0x3753U, 0x3754U, 0x3755U, 0x3756U, 0x3757U, 0x3758U, 0x3759U, 0x375AU, 0x3761U, 0x3762U, 0x3763U, 0x3764U, 0x3765U, 0x3766U, 0x3767U, 0x3768U, 0x3769U, 0x376AU, 0x376BU, 0x376CU, 0x376DU, 0x376EU, 0x376FU, 0x3770U, 0x3771U, 0x3772U, 0x3773U, 0x3774U, 0x3775U, 0x3776U, 0x3777U, 0x3778U, 0x3779U, 0x377AU, 0x3730U, 0x3731U, 0x3732U, 0x3733U, 0x3734U, 0x3735U, 0x3736U, 0x3737U, 0x3738U, 0x3739U, 0x372BU, 0x372FU, 0x3841U, 0x3842U, 0x3843U, 0x3844U, 0x3845U, 0x3846U, 0x3847U, 0x3848U, 0x3849U, 0x384AU, 0x384BU, 0x384CU, 0x384DU, 0x384EU, 0x384FU, 0x3850U, 0x3851U, 0x3852U, 0x3853U, 0x3854U, 0x3855U, 0x3856U, 0x3857U, 0x3858U, 0x3859U, 0x385AU, 0x3861U, 0x3862U, 0x3863U, 0x3864U, 0x3865U, 0x3866U, 0x3867U, 0x3868U, 0x3869U, 0x386AU, 0x386BU, 0x386CU, 0x386DU, 0x386EU, 0x386FU, 0x3870U, 0x3871U, 0x3872U, 0x3873U, 0x3874U, 0x3875U, 0x3876U, 0x3877U, 0x3878U, 0x3879U, 0x387AU, 0x3830U, 0x3831U, 0x3832U, 0x3833U, 0x3834U, 0x3835U, 0x3836U, 0x3837U, 0x3838U, 0x3839U, 0x382BU, 0x382FU, 0x3941U, 0x3942U, 0x3943U, 0x3944U, 0x3945U, 0x3946U, 0x3947U, 0x3948U, 0x3949U, 0x394AU, 0x394BU, 0x394CU, 0x394DU, 0x394EU, 0x394FU, 0x3950U, 0x3951U, 0x3952U, 0x3953U, 0x3954U, 0x3955U, 0x3956U, 0x3957U, 0x3958U, 0x3959U, 0x395AU, 0x3961U, 0x3962U, 0x3963U, 0x3964U, 0x3965U, 0x3966U, 0x3967U, 0x3968U, 0x3969U, 0x396AU, 0x396BU, 0x396CU, 0x396DU, 0x396EU, 0x396FU, 0x3970U, 0x3971U, 0x3972U, 0x3973U, 0x3974U, 0x3975U, 0x3976U, 0x3977U, 0x3978U, 0x3979U, 0x397AU, 0x3930U, 0x3931U, 0x3932U, 0x3933U, 0x3934U, 0x3935U, 0x3936U, 0x3937U, 0x3938U, 0x3939U, 0x392BU, 0x392FU, 0x2B41U, 0x2B42U, 0x2B43U, 0x2B44U, 0x2B45U, 0x2B46U, 0x2B47U, 0x2B48U, 0x2B49U, 0x2B4AU, 0x2B4BU, 0x2B4CU, 0x2B4DU, 0x2B4EU, 0x2B4FU, 0x2B50U, 0x2B51U, 0x2B52U, 0x2B53U, 0x2B54U, 0x2B55U, 0x2B56U, 0x2B57U, 0x2B58U, 0x2B59U, 0x2B5AU, 0x2B61U, 0x2B62U, 0x2B63U, 0x2B64U, 0x2B65U, 0x2B66U, 0x2B67U, 0x2B68U, 0x2B69U, 0x2B6AU, 0x2B6BU, 0x2B6CU, 0x2B6DU, 0x2B6EU, 0x2B6FU, 0x2B70U, 0x2B71U, 0x2B72U, 0x2B73U, 0x2B74U, 0x2B75U, 0x2B76U, 0x2B77U, 0x2B78U, 0x2B79U, 0x2B7AU, 0x2B30U, 0x2B31U, 0x2B32U, 0x2B33U, 0x2B34U, 0x2B35U, 0x2B36U, 0x2B37U, 0x2B38U, 0x2B39U, 0x2B2BU, 0x2B2FU, 0x2F41U, 0x2F42U, 0x2F43U, 0x2F44U, 0x2F45U, 0x2F46U, 0x2F47U, 0x2F48U, 0x2F49U, 0x2F4AU, 0x2F4BU, 0x2F4CU, 0x2F4DU, 0x2F4EU, 0x2F4FU, 0x2F50U, 0x2F51U, 0x2F52U, 0x2F53U, 0x2F54U, 0x2F55U, 0x2F56U, 0x2F57U, 0x2F58U, 0x2F59U, 0x2F5AU, 0x2F61U, 0x2F62U, 0x2F63U, 0x2F64U, 0x2F65U, 0x2F66U, 0x2F67U, 0x2F68U, 0x2F69U, 0x2F6AU, 0x2F6BU, 0x2F6CU, 0x2F6DU, 0x2F6EU, 0x2F6FU, 0x2F70U, 0x2F71U, 0x2F72U, 0x2F73U, 0x2F74U, 0x2F75U, 0x2F76U, 0x2F77U, 0x2F78U, 0x2F79U, 0x2F7AU, 0x2F30U, 0x2F31U, 0x2F32U, 0x2F33U, 0x2F34U, 0x2F35U, 0x2F36U, 0x2F37U, 0x2F38U, 0x2F39U, 0x2F2BU, 0x2F2FU, #endif }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/tables/tables.c0000644000175100017510000000400315200142331016313 0ustar00runnerrunner#include "tables.h" const uint8_t base64_table_enc_6bit[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" "abcdefghijklmnopqrstuvwxyz" "0123456789" "+/"; // In the lookup table below, note that the value for '=' (character 61) is // 254, not 255. This character is used for in-band signaling of the end of // the datastream, and we will use that later. The characters A-Z, a-z, 0-9 // and + / are mapped to their "decoded" values. The other bytes all map to // the value 255, which flags them as "invalid input". const uint8_t base64_table_dec_8bit[] = { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 0..15 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 16..31 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, 255, 255, 63, // 32..47 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, 255, 254, 255, 255, // 48..63 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, // 64..79 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 255, 255, 255, 255, 255, // 80..95 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // 96..111 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 255, 255, 255, 255, 255, // 112..127 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, // 128..143 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, }; #if BASE64_WORDSIZE >= 32 # include "table_dec_32bit.h" # include "table_enc_12bit.h" #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/base64/tables/tables.h0000644000175100017510000000130015200142331016315 0ustar00runnerrunner#ifndef BASE64_TABLES_H #define BASE64_TABLES_H #include #include "../env.h" // These tables are used by all codecs for fallback plain encoding/decoding: extern const uint8_t base64_table_enc_6bit[]; extern const uint8_t base64_table_dec_8bit[]; // These tables are used for the 32-bit and 64-bit generic decoders: #if BASE64_WORDSIZE >= 32 extern const uint32_t base64_table_dec_32bit_d0[]; extern const uint32_t base64_table_dec_32bit_d1[]; extern const uint32_t base64_table_dec_32bit_d2[]; extern const uint32_t base64_table_dec_32bit_d3[]; // This table is used by the 32 and 64-bit generic encoders: extern const uint16_t base64_table_enc_12bit[]; #endif #endif // BASE64_TABLES_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/build_setup.py0000644000175100017510000000513515200142331015237 0ustar00runnerrunner# This file must have the same content for mypyc/build_setup.py and lib-rt/build_setup.py, # it exists to work around absence of support for per-file compile flags in setuptools. # The version in mypyc/ is the source of truth, and should be copied to lib-rt if modified. import os import platform import sys try: # Import setuptools so that it monkey-patch overrides distutils import setuptools # noqa: F401 except ImportError: pass if sys.version_info >= (3, 12): # From setuptools' monkeypatch from distutils import ccompiler # type: ignore[import-not-found] else: from distutils import ccompiler EXTRA_FLAGS_PER_COMPILER_TYPE_PER_PATH_COMPONENT = { "msvc": { "base64/arch/sse42": ["/arch:SSE4.2"], "base64/arch/avx2": ["/arch:AVX2"], "base64/arch/avx": ["/arch:AVX"], } } ccompiler.CCompiler.__spawn = ccompiler.CCompiler.spawn # type: ignore[attr-defined] X86_64 = platform.machine() in ("x86_64", "AMD64", "amd64") PYODIDE = "PYODIDE" in os.environ NO_EXTRA_FLAGS = "MYPYC_NO_EXTRA_FLAGS" in os.environ def spawn(self, cmd, **kwargs) -> None: # type: ignore[no-untyped-def] new_cmd = list(cmd) if PYODIDE: for argument in reversed(new_cmd): if not str(argument).endswith(".c"): continue if "base64/arch/" in str(argument): new_cmd.extend(["-msimd128"]) elif not NO_EXTRA_FLAGS: compiler_type: str = self.compiler_type extra_options = EXTRA_FLAGS_PER_COMPILER_TYPE_PER_PATH_COMPONENT.get(compiler_type, None) if X86_64 and extra_options is not None: # filenames are closer to the end of command line for argument in reversed(new_cmd): # Check if the matching argument contains a source filename. if not str(argument).endswith(".c"): continue for path in extra_options.keys(): if path in str(argument): if compiler_type == "bcpp": compiler = new_cmd.pop() # Borland accepts a source file name at the end, # insert the options before it new_cmd.extend(extra_options[path]) new_cmd.append(compiler) else: new_cmd.extend(extra_options[path]) # path component is found, no need to search any further break self.__spawn(new_cmd, **kwargs) ccompiler.CCompiler.spawn = spawn # type: ignore[method-assign] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/bytearray_extra_ops.c0000644000175100017510000000017215200142331016574 0ustar00runnerrunner#include "bytearray_extra_ops.h" PyObject *CPyByteArray_New(void) { return PyByteArray_FromStringAndSize(NULL, 0); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/bytearray_extra_ops.h0000644000175100017510000000026615200142331016605 0ustar00runnerrunner#ifndef MYPYC_BYTEARRAY_EXTRA_OPS_H #define MYPYC_BYTEARRAY_EXTRA_OPS_H #include #include "CPy.h" // Construct empty bytearray PyObject *CPyByteArray_New(void); #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/bytes_extra_ops.c0000644000175100017510000000277315200142331015731 0ustar00runnerrunner#include "bytes_extra_ops.h" PyObject *CPyBytes_Translate(PyObject *bytes, PyObject *table) { // Fast path: exact bytes object with exact bytes table if (PyBytes_CheckExact(bytes) && PyBytes_CheckExact(table)) { Py_ssize_t table_len = PyBytes_GET_SIZE(table); if (table_len != 256) { PyErr_SetString(PyExc_ValueError, "translation table must be 256 characters long"); return NULL; } Py_ssize_t len = PyBytes_GET_SIZE(bytes); const char *input = PyBytes_AS_STRING(bytes); const char *trans_table = PyBytes_AS_STRING(table); PyObject *result = PyBytes_FromStringAndSize(NULL, len); if (result == NULL) { return NULL; } char *output = PyBytes_AS_STRING(result); bool changed = false; // Without a loop unrolling hint performance can be worse than CPython CPY_UNROLL_LOOP(4) for (Py_ssize_t i = len; --i >= 0;) { char c = *input++; if ((*output++ = trans_table[(unsigned char)c]) != c) changed = true; } // If nothing changed, discard result and return the original object if (!changed) { Py_DECREF(result); Py_INCREF(bytes); return bytes; } return result; } // Fallback to Python method call for non-exact types or non-standard tables return PyObject_CallMethodOneArg(bytes, mypyc_interned_str.translate, table); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/bytes_extra_ops.h0000644000175100017510000000160015200142331015722 0ustar00runnerrunner#ifndef MYPYC_BYTES_EXTRA_OPS_H #define MYPYC_BYTES_EXTRA_OPS_H #include #include #include "CPy.h" // Optimized bytes translate operation PyObject *CPyBytes_Translate(PyObject *bytes, PyObject *table); // Optimized bytes.__getitem__ operations // If index is negative, convert to non-negative index (no range checking) static inline int64_t CPyBytes_AdjustIndex(PyObject *obj, int64_t index) { if (index < 0) { return index + Py_SIZE(obj); } return index; } // Check if index is in valid range [0, len) static inline bool CPyBytes_RangeCheck(PyObject *obj, int64_t index) { return index >= 0 && index < Py_SIZE(obj); } // Get byte at index (no bounds checking) - returns as CPyTagged static inline CPyTagged CPyBytes_GetItemUnsafe(PyObject *obj, int64_t index) { return ((CPyTagged)(uint8_t)(PyBytes_AS_STRING(obj))[index]) << 1; } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/bytes_ops.c0000644000175100017510000001555215200142331014525 0ustar00runnerrunner// Bytes primitive operations // // These are registered in mypyc.primitives.bytes_ops. #include #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) { 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; } 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 (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 { return PyObject_CallMethodOneArg(sep, mypyc_interned_str.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; } CPyTagged CPyBytes_Ord(PyObject *obj) { Py_ssize_t s = PyBytes_GET_SIZE(obj); if (s == 1) { return (unsigned char)(PyBytes_AS_STRING(obj)[0]) << 1; } PyErr_SetString(PyExc_TypeError, "ord() expects a character"); return CPY_INT_TAG; } PyObject *CPyBytes_Multiply(PyObject *bytes, CPyTagged count) { Py_ssize_t temp_count = CPyTagged_AsSsize_t(count); if (temp_count == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return NULL; } return PySequence_Repeat(bytes, temp_count); } int CPyBytes_Startswith(PyObject *self, PyObject *subobj) { if (PyBytes_CheckExact(self) && PyBytes_CheckExact(subobj)) { if (self == subobj) { return 1; } Py_ssize_t subobj_len = PyBytes_GET_SIZE(subobj); if (subobj_len == 0) { return 1; } Py_ssize_t self_len = PyBytes_GET_SIZE(self); if (subobj_len > self_len) { return 0; } const char *self_buf = PyBytes_AS_STRING(self); const char *subobj_buf = PyBytes_AS_STRING(subobj); return memcmp(self_buf, subobj_buf, (size_t)subobj_len) == 0 ? 1 : 0; } PyObject *result = PyObject_CallMethodOneArg(self, mypyc_interned_str.startswith, subobj); if (result == NULL) { return 2; } int ret = PyObject_IsTrue(result); Py_DECREF(result); if (ret < 0) { return 2; } return ret; } int CPyBytes_Endswith(PyObject *self, PyObject *subobj) { if (PyBytes_CheckExact(self) && PyBytes_CheckExact(subobj)) { if (self == subobj) { return 1; } Py_ssize_t subobj_len = PyBytes_GET_SIZE(subobj); if (subobj_len == 0) { return 1; } Py_ssize_t self_len = PyBytes_GET_SIZE(self); if (subobj_len > self_len) { return 0; } const char *self_buf = PyBytes_AS_STRING(self); const char *subobj_buf = PyBytes_AS_STRING(subobj); return memcmp(self_buf + (self_len - subobj_len), subobj_buf, (size_t)subobj_len) == 0 ? 1 : 0; } PyObject *result = PyObject_CallMethodOneArg(self, mypyc_interned_str.endswith, subobj); if (result == NULL) { return 2; } int ret = PyObject_IsTrue(result); Py_DECREF(result); if (ret < 0) { return 2; } return ret; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/byteswriter_extra_ops.c0000644000175100017510000000245015200142331017156 0ustar00runnerrunner// Primitives related to librt.strings.BytesWriter that get linked statically // with compiled modules, instead of being called via a capsule. #include "byteswriter_extra_ops.h" char CPyBytesWriter_Write(PyObject *obj, PyObject *value) { BytesWriterObject *self = (BytesWriterObject *)obj; const char *data; Py_ssize_t size; if (likely(PyBytes_Check(value))) { data = PyBytes_AS_STRING(value); size = PyBytes_GET_SIZE(value); } else { data = PyByteArray_AS_STRING(value); size = PyByteArray_GET_SIZE(value); } // Write bytes content. if (!CPyBytesWriter_EnsureSize(self, size)) return CPY_NONE_ERROR; if (size < 8) { // Loop tends to be faster for small sizes char *p = self->buf + self->len; for (Py_ssize_t i = 0; i < size; i++) { p[i] = data[i]; } } else { memcpy(self->buf + self->len, data, size); } self->len += size; return CPY_NONE; } void CPyBytes_ReadError(int64_t index, Py_ssize_t size) { if (index < 0) { PyErr_SetString(PyExc_ValueError, "index must be non-negative"); } else { PyErr_Format(PyExc_IndexError, "index %lld out of range for bytes of length %zd", (long long)index, size); } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/byteswriter_extra_ops.h0000644000175100017510000002227715200142331017174 0ustar00runnerrunner#ifndef BYTESWRITER_EXTRA_OPS_H #define BYTESWRITER_EXTRA_OPS_H #include #include #include #include "mypyc_util.h" #include "strings/librt_strings_api.h" #include "strings/librt_strings_common.h" // BytesWriter: Length and capacity static inline CPyTagged CPyBytesWriter_Len(PyObject *obj) { return (CPyTagged)((BytesWriterObject *)obj)->len << 1; } static inline bool CPyBytesWriter_EnsureSize(BytesWriterObject *data, Py_ssize_t n) { if (likely(data->capacity - data->len >= n)) { return true; } else { return LibRTStrings_ByteWriter_grow_buffer_internal(data, n); } } // BytesWriter: Basic write operations static inline char CPyBytesWriter_Append(PyObject *obj, uint8_t value) { BytesWriterObject *self = (BytesWriterObject *)obj; // Store length in a local variable to enable additional optimizations Py_ssize_t len = self->len; if (!CPyBytesWriter_EnsureSize(self, 1)) return CPY_NONE_ERROR; self->buf[len] = value; self->len = len + 1; return CPY_NONE; } char CPyBytesWriter_Write(PyObject *obj, PyObject *value); // BytesWriter: Indexing operations // If index is negative, convert to non-negative index (no range checking) static inline int64_t CPyBytesWriter_AdjustIndex(PyObject *obj, int64_t index) { if (index < 0) { return index + ((BytesWriterObject *)obj)->len; } return index; } static inline bool CPyBytesWriter_RangeCheck(PyObject *obj, int64_t index) { return index >= 0 && index < ((BytesWriterObject *)obj)->len; } static inline uint8_t CPyBytesWriter_GetItem(PyObject *obj, int64_t index) { return (((BytesWriterObject *)obj)->buf)[index]; } static inline void CPyBytesWriter_SetItem(PyObject *obj, int64_t index, uint8_t x) { (((BytesWriterObject *)obj)->buf)[index] = x; } // BytesWriter: Write integer operations (little-endian) static inline char CPyBytesWriter_WriteI16LE(PyObject *obj, int16_t value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 2)) return CPY_NONE_ERROR; BytesWriter_WriteI16LEUnsafe(self, value); return CPY_NONE; } static inline char CPyBytesWriter_WriteI16BE(PyObject *obj, int16_t value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 2)) return CPY_NONE_ERROR; BytesWriter_WriteI16BEUnsafe(self, value); return CPY_NONE; } static inline char CPyBytesWriter_WriteI32LE(PyObject *obj, int32_t value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 4)) return CPY_NONE_ERROR; BytesWriter_WriteI32LEUnsafe(self, value); return CPY_NONE; } static inline char CPyBytesWriter_WriteI32BE(PyObject *obj, int32_t value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 4)) return CPY_NONE_ERROR; BytesWriter_WriteI32BEUnsafe(self, value); return CPY_NONE; } static inline char CPyBytesWriter_WriteI64LE(PyObject *obj, int64_t value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 8)) return CPY_NONE_ERROR; BytesWriter_WriteI64LEUnsafe(self, value); return CPY_NONE; } static inline char CPyBytesWriter_WriteI64BE(PyObject *obj, int64_t value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 8)) return CPY_NONE_ERROR; BytesWriter_WriteI64BEUnsafe(self, value); return CPY_NONE; } // BytesWriter: Write float operations static inline char CPyBytesWriter_WriteF32LE(PyObject *obj, double value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 4)) return CPY_NONE_ERROR; BytesWriter_WriteF32LEUnsafe(self, (float)value); return CPY_NONE; } static inline char CPyBytesWriter_WriteF32BE(PyObject *obj, double value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 4)) return CPY_NONE_ERROR; BytesWriter_WriteF32BEUnsafe(self, (float)value); return CPY_NONE; } static inline char CPyBytesWriter_WriteF64LE(PyObject *obj, double value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 8)) return CPY_NONE_ERROR; BytesWriter_WriteF64LEUnsafe(self, value); return CPY_NONE; } static inline char CPyBytesWriter_WriteF64BE(PyObject *obj, double value) { BytesWriterObject *self = (BytesWriterObject *)obj; if (!CPyBytesWriter_EnsureSize(self, 8)) return CPY_NONE_ERROR; BytesWriter_WriteF64BEUnsafe(self, value); return CPY_NONE; } // Bytes: Read integer operations // Helper function for bytes read error handling (negative index or out of range) void CPyBytes_ReadError(int64_t index, Py_ssize_t size); static inline int16_t CPyBytes_ReadI16LE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 2)) { CPyBytes_ReadError(index, size); return CPY_LL_INT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadI16LEUnsafe(data + index); } static inline int16_t CPyBytes_ReadI16BE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 2)) { CPyBytes_ReadError(index, size); return CPY_LL_INT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadI16BEUnsafe(data + index); } static inline int32_t CPyBytes_ReadI32BE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 4)) { CPyBytes_ReadError(index, size); return CPY_LL_INT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadI32BEUnsafe(data + index); } static inline int32_t CPyBytes_ReadI32LE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 4)) { CPyBytes_ReadError(index, size); return CPY_LL_INT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadI32LEUnsafe(data + index); } static inline int64_t CPyBytes_ReadI64LE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 8)) { CPyBytes_ReadError(index, size); return CPY_LL_INT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadI64LEUnsafe(data + index); } static inline int64_t CPyBytes_ReadI64BE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 8)) { CPyBytes_ReadError(index, size); return CPY_LL_INT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadI64BEUnsafe(data + index); } // Bytes: Read float operations static inline double CPyBytes_ReadF32LE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 4)) { CPyBytes_ReadError(index, size); return CPY_FLOAT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return (double)CPyBytes_ReadF32LEUnsafe(data + index); } static inline double CPyBytes_ReadF32BE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 4)) { CPyBytes_ReadError(index, size); return CPY_FLOAT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return (double)CPyBytes_ReadF32BEUnsafe(data + index); } static inline double CPyBytes_ReadF64LE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 8)) { CPyBytes_ReadError(index, size); return CPY_FLOAT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadF64LEUnsafe(data + index); } static inline double CPyBytes_ReadF64BE(PyObject *bytes_obj, int64_t index) { // bytes_obj type is enforced by mypyc Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index < 0 || index > size - 8)) { CPyBytes_ReadError(index, size); return CPY_FLOAT_ERROR; } const unsigned char *data = (const unsigned char *)PyBytes_AS_STRING(bytes_obj); return CPyBytes_ReadF64BEUnsafe(data + index); } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/dict_ops.c0000644000175100017510000003024515200142331014316 0ustar00runnerrunner// Dict primitive operations // // These are registered in mypyc.primitives.dict_ops. #include #include "CPy.h" #ifndef Py_TPFLAGS_MAPPING #define Py_TPFLAGS_MAPPING (1 << 6) #endif // 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; } return PyObject_CallMethodObjArgs(dict, mypyc_interned_str.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 a 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) { PyObject *res = PyObject_CallMethodOneArg(dict, mypyc_interned_str.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 if (PyDict_Check(stuff) || PyObject_HasAttrWithError(stuff, mypyc_interned_str.keys) > 0) { 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; } if (PyObject_HasAttrWithError(obj, mypyc_interned_str.keys) > 0) { 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); } return PyObject_CallMethodNoArgs(dict, mypyc_interned_str.keys); } PyObject *CPyDict_ValuesView(PyObject *dict) { if (PyDict_CheckExact(dict)){ return _CPyDictView_New(dict, &PyDictValues_Type); } return PyObject_CallMethodNoArgs(dict, mypyc_interned_str.values); } PyObject *CPyDict_ItemsView(PyObject *dict) { if (PyDict_CheckExact(dict)){ return _CPyDictView_New(dict, &PyDictItems_Type); } return PyObject_CallMethodNoArgs(dict, mypyc_interned_str.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); PyObject *view = PyObject_CallMethodNoArgs(dict, mypyc_interned_str.keys); if (view == NULL) { return NULL; } int res = PyList_Extend(list, view); Py_DECREF(view); if (res < 0) { return NULL; } 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); PyObject *view = PyObject_CallMethodNoArgs(dict, mypyc_interned_str.values); if (view == NULL) { return NULL; } int res = PyList_Extend(list, view); Py_DECREF(view); if (res < 0) { return NULL; } 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); PyObject *view = PyObject_CallMethodNoArgs(dict, mypyc_interned_str.items); if (view == NULL) { return NULL; } int res = PyList_Extend(list, view); Py_DECREF(view); if (res < 0) { return NULL; } return list; } char CPyDict_Clear(PyObject *dict) { if (PyDict_CheckExact(dict)) { PyDict_Clear(dict); } else { PyObject *res = PyObject_CallMethodNoArgs(dict, mypyc_interned_str.clear); if (res == NULL) { return 0; } Py_DECREF(res); } return 1; } PyObject *CPyDict_Copy(PyObject *dict) { if (PyDict_CheckExact(dict)) { return PyDict_Copy(dict); } return PyObject_CallMethodNoArgs(dict, mypyc_interned_str.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; } PyObject *view = PyObject_CallMethodNoArgs(dict, mypyc_interned_str.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; } PyObject *view = PyObject_CallMethodNoArgs(dict, mypyc_interned_str.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"); Py_DECREF(item); } 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_INCREF(ret.f2); Py_INCREF(ret.f3); Py_DECREF(item); return ret; } } // PyDict_Next() returns borrowed references. Py_INCREF(ret.f2); Py_INCREF(ret.f3); return ret; } int CPyMapping_Check(PyObject *obj) { return Py_TYPE(obj)->tp_flags & Py_TPFLAGS_MAPPING; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/exc_ops.c0000644000175100017510000002022115200142331014143 0ustar00runnerrunner#include "pythoncapi_compat.h" // Exception related primitive operations // // These are registered in mypyc.primitives.exc_ops. #include #include "CPy.h" void CPy_Raise(PyObject *exc) { if (PyObject_IsInstance(exc, (PyObject *)&PyType_Type)) { PyObject *obj = PyObject_CallNoArgs(exc); 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) { if (!PyType_Check(type) && Py_IsNone(value)) { // The first argument must be an exception instance value = type; type = (PyObject *)Py_TYPE(value); } // 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((PyObject *)Py_TYPE(CPy_ExcState()->exc_value), 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_GetAttr(type, mypyc_interned_str.__module__); if (!module || !PyUnicode_Check(module)) { goto out; } name = PyObject_GetAttr(type, mypyc_interned_str.__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); } } // The PyFrameObject type definition (struct _frame) has been moved // to the internal C API: to the pycore_frame.h header file. // https://github.com/python/cpython/pull/31530 #if PY_VERSION_HEX >= 0x030b00a6 #include "internal/pycore_frame.h" #endif // 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: #if CPY_3_12_FEATURES _PyErr_ChainExceptions1(exc); #else _PyErr_ChainExceptions(exc, val, tb); #endif } CPy_NOINLINE void CPy_TypeErrorTraceback(const char *filename, const char *funcname, int line, PyObject *globals, const char *expected, PyObject *value) { CPy_TypeError(expected, value); CPy_AddTraceback(filename, funcname, line, globals); } void CPy_AttributeError(const char *filename, const char *funcname, const char *classname, const char *attrname, int line, PyObject *globals) { char buf[500]; snprintf(buf, sizeof(buf), "attribute '%.200s' of '%.200s' undefined", attrname, classname); PyErr_SetString(PyExc_AttributeError, buf); CPy_AddTraceback(filename, funcname, line, globals); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/float_ops.c0000644000175100017510000001426615200142331014505 0ustar00runnerrunner// Float primitive operations // // These are registered in mypyc.primitives.float_ops. #include #include "CPy.h" static double CPy_DomainError(void) { PyErr_SetString(PyExc_ValueError, "math domain error"); return CPY_FLOAT_ERROR; } static double CPy_MathRangeError(void) { PyErr_SetString(PyExc_OverflowError, "math range error"); return CPY_FLOAT_ERROR; } static double CPy_MathExpectedNonNegativeInputError(double x) { char *buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); if (buf) { PyErr_Format(PyExc_ValueError, "expected a nonnegative input, got %s", buf); PyMem_Free(buf); } return CPY_FLOAT_ERROR; } static double CPy_MathExpectedPositiveInputError(double x) { char *buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); if (buf) { PyErr_Format(PyExc_ValueError, "expected a positive input, got %s", buf); PyMem_Free(buf); } return CPY_FLOAT_ERROR; } static double CPy_MathExpectedFiniteInput(double x) { char *buf = PyOS_double_to_string(x, 'r', 0, Py_DTSF_ADD_DOT_0, NULL); if (buf) { PyErr_Format(PyExc_ValueError, "expected a finite input, got %s", buf); PyMem_Free(buf); } return CPY_FLOAT_ERROR; } double CPyFloat_FromTagged(CPyTagged x) { if (CPyTagged_CheckShort(x)) { return CPyTagged_ShortAsSsize_t(x); } double result = PyFloat_AsDouble(CPyTagged_LongAsObject(x)); if (unlikely(result == -1.0) && PyErr_Occurred()) { return CPY_FLOAT_ERROR; } return result; } double CPyFloat_Sin(double x) { double v = sin(x); if (unlikely(isnan(v)) && !isnan(x)) { #if CPY_3_14_FEATURES return CPy_MathExpectedFiniteInput(x); #else return CPy_DomainError(); #endif } return v; } double CPyFloat_Cos(double x) { double v = cos(x); if (unlikely(isnan(v)) && !isnan(x)) { #if CPY_3_14_FEATURES return CPy_MathExpectedFiniteInput(x); #else return CPy_DomainError(); #endif } return v; } double CPyFloat_Tan(double x) { if (unlikely(isinf(x))) { #if CPY_3_14_FEATURES return CPy_MathExpectedFiniteInput(x); #else return CPy_DomainError(); #endif } return tan(x); } double CPyFloat_Sqrt(double x) { if (x < 0.0) { #if CPY_3_14_FEATURES return CPy_MathExpectedNonNegativeInputError(x); #else return CPy_DomainError(); #endif } return sqrt(x); } double CPyFloat_Exp(double x) { double v = exp(x); if (unlikely(v == INFINITY) && x != INFINITY) { return CPy_MathRangeError(); } return v; } double CPyFloat_Log(double x) { if (x <= 0.0) { #if CPY_3_14_FEATURES return CPy_MathExpectedPositiveInputError(x); #else return CPy_DomainError(); #endif } return log(x); } CPyTagged CPyFloat_Floor(double x) { double v = floor(x); return CPyTagged_FromFloat(v); } CPyTagged CPyFloat_Ceil(double x) { double v = ceil(x); return CPyTagged_FromFloat(v); } bool CPyFloat_IsInf(double x) { return isinf(x) != 0; } bool CPyFloat_IsNaN(double x) { return isnan(x) != 0; } // From CPython 3.10.0, Objects/floatobject.c static void _float_div_mod(double vx, double wx, double *floordiv, double *mod) { double div; *mod = fmod(vx, wx); /* fmod is typically exact, so vx-mod is *mathematically* an exact multiple of wx. But this is fp arithmetic, and fp vx - mod is an approximation; the result is that div may not be an exact integral value after the division, although it will always be very close to one. */ div = (vx - *mod) / wx; if (*mod) { /* ensure the remainder has the same sign as the denominator */ if ((wx < 0) != (*mod < 0)) { *mod += wx; div -= 1.0; } } else { /* the remainder is zero, and in the presence of signed zeroes fmod returns different results across platforms; ensure it has the same sign as the denominator. */ *mod = copysign(0.0, wx); } /* snap quotient to nearest integral value */ if (div) { *floordiv = floor(div); if (div - *floordiv > 0.5) { *floordiv += 1.0; } } else { /* div is zero - get the same sign as the true quotient */ *floordiv = copysign(0.0, vx / wx); /* zero w/ sign of vx/wx */ } } double CPyFloat_FloorDivide(double x, double y) { double mod, floordiv; if (y == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "float floor division by zero"); return CPY_FLOAT_ERROR; } _float_div_mod(x, y, &floordiv, &mod); return floordiv; } // Adapted from CPython 3.10.7 double CPyFloat_Pow(double x, double y) { if (!isfinite(x) || !isfinite(y)) { if (isnan(x)) return y == 0.0 ? 1.0 : x; /* NaN**0 = 1 */ else if (isnan(y)) return x == 1.0 ? 1.0 : y; /* 1**NaN = 1 */ else if (isinf(x)) { int odd_y = isfinite(y) && fmod(fabs(y), 2.0) == 1.0; if (y > 0.0) return odd_y ? x : fabs(x); else if (y == 0.0) return 1.0; else /* y < 0. */ return odd_y ? copysign(0.0, x) : 0.0; } else if (isinf(y)) { if (fabs(x) == 1.0) return 1.0; else if (y > 0.0 && fabs(x) > 1.0) return y; else if (y < 0.0 && fabs(x) < 1.0) { #if PY_VERSION_HEX < 0x030B0000 if (x == 0.0) { /* 0**-inf: divide-by-zero */ return CPy_DomainError(); } #endif return -y; /* result is +inf */ } else return 0.0; } } double r = pow(x, y); if (!isfinite(r)) { if (isnan(r)) { return CPy_DomainError(); } /* an infinite result here arises either from: (A) (+/-0.)**negative (-> divide-by-zero) (B) overflow of x**y with x and y finite */ else if (isinf(r)) { if (x == 0.0) return CPy_DomainError(); else return CPy_MathRangeError(); } } return r; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/function_wrapper.c0000644000175100017510000002102315200142331016071 0ustar00runnerrunner#define PY_SSIZE_T_CLEAN #include "CPy.h" #include #define CPyFunction_weakreflist(f) (((PyCFunctionObject *)f)->m_weakreflist) #define CPyFunction_class(f) ((PyObject*) ((PyCMethodObject *) (f))->mm_class) #define CPyFunction_func_vectorcall(f) (((PyCFunctionObject *)f)->vectorcall) static int CPyFunction_clear(CPyFunction *m) { Py_CLEAR(((PyCFunctionObject*)m)->m_module); PyObject_ClearManagedDict((PyObject*)m); Py_CLEAR(m->func_name); Py_CLEAR(m->func_code); PyObject *cls = CPyFunction_class(m); ((PyCMethodObject *)m)->mm_class = NULL; Py_XDECREF(cls); return 0; } static void CPyFunction_dealloc(CPyFunction *m) { PyObject_GC_UnTrack(m); if (CPyFunction_weakreflist(m) != NULL) PyObject_ClearWeakRefs((PyObject *) m); CPyFunction_clear(m); PyMem_Free(m->func.func.m_ml); PyObject_GC_Del(m); } static PyObject* CPyFunction_repr(CPyFunction *op) { return PyUnicode_FromFormat("", op->func_name, (void *)op); } static PyObject* CPyFunction_call(PyObject *func, PyObject *args, PyObject *kw) { CPyFunction *f = (CPyFunction *)func; vectorcallfunc vc = CPyFunction_func_vectorcall(f); assert(vc); return PyVectorcall_Call(func, args, kw); } static int CPyFunction_traverse(CPyFunction *m, visitproc visit, void *arg) { Py_VISIT(((PyCFunctionObject *)m)->m_module); int e = PyObject_VisitManagedDict((PyObject*)m, visit, arg); if (e != 0) return e; Py_VISIT(m->func_name); Py_VISIT(m->func_code); Py_VISIT(CPyFunction_class(m)); return 0; } static PyMemberDef CPyFunction_members[] = { {"__module__", T_OBJECT, offsetof(PyCFunctionObject, m_module), 0, 0}, {"__vectorcalloffset__", T_PYSSIZET, offsetof(PyCFunctionObject, vectorcall), READONLY, 0}, {"__weaklistoffset__", T_PYSSIZET, offsetof(PyCFunctionObject, m_weakreflist), READONLY, 0}, {0, 0, 0, 0, 0} }; PyObject* CPyFunction_get_name(PyObject *op, void *context) { (void)context; CPyFunction *func = (CPyFunction *)op; if (unlikely(func->func_name == NULL)) { func->func_name = PyUnicode_InternFromString(((PyCFunctionObject *)func)->m_ml->ml_name); if (unlikely(func->func_name == NULL)) return NULL; } Py_INCREF(func->func_name); return func->func_name; } int CPyFunction_set_name(PyObject *op, PyObject *value, void *context) { (void)context; CPyFunction *func = (CPyFunction *)op; if (unlikely(!value || !PyUnicode_Check(value))) { PyErr_SetString(PyExc_TypeError, "__name__ must be set to a string object"); return -1; } Py_INCREF(value); Py_XDECREF(func->func_name); func->func_name = value; return 0; } PyObject* CPyFunction_get_code(PyObject *op, void *context) { (void)context; CPyFunction *func = (CPyFunction *)op; PyObject* result = (func->func_code) ? func->func_code : Py_None; Py_INCREF(result); return result; } static PyObject* CPyFunction_get_none(PyObject *op, void *context) { (void)op; (void)context; PyObject* result = Py_None; Py_INCREF(result); return result; } int CPyFunction_set_none(PyObject *op, PyObject *value, void *context) { (void)op; (void)value; (void)context; return 0; } PyObject* CPyFunction_get_defaults(PyObject *op, void *context) { return CPyFunction_get_none(op, context); } PyObject* CPyFunction_get_kwdefaults(PyObject *op, void *context) { return CPyFunction_get_none(op, context); } PyObject* CPyFunction_get_annotations(PyObject *op, void *context) { return CPyFunction_get_none(op, context); } int CPyFunction_set_annotations(PyObject *op, PyObject *value, void *context) { return CPyFunction_set_none(op, value, context); } static PyGetSetDef CPyFunction_getsets[] = { {"__dict__", (getter)PyObject_GenericGetDict, (setter)PyObject_GenericSetDict, 0, 0}, {"__name__", (getter)CPyFunction_get_name, (setter)CPyFunction_set_name, 0, 0}, {"__code__", (getter)CPyFunction_get_code, 0, 0, 0}, {"__defaults__", (getter)CPyFunction_get_defaults, 0, 0, 0}, {"__kwdefaults__", (getter)CPyFunction_get_kwdefaults, 0, 0, 0}, {"__annotations__", (getter)CPyFunction_get_annotations, CPyFunction_set_annotations, 0, 0}, {0, 0, 0, 0, 0} }; static PyObject* CPy_PyMethod_New(PyObject *func, PyObject *self, PyObject *typ) { (void)typ; if (!self) { Py_INCREF(func); return func; } return PyMethod_New(func, self); } static PyType_Slot CPyFunction_slots[] = { {Py_tp_dealloc, (void *)CPyFunction_dealloc}, {Py_tp_repr, (void *)CPyFunction_repr}, {Py_tp_call, (void *)CPyFunction_call}, {Py_tp_traverse, (void *)CPyFunction_traverse}, {Py_tp_clear, (void *)CPyFunction_clear}, {Py_tp_members, (void *)CPyFunction_members}, {Py_tp_getset, (void *)CPyFunction_getsets}, {Py_tp_descr_get, (void *)CPy_PyMethod_New}, {0, 0}, }; static PyType_Spec CPyFunction_spec = { .name = "Function compiled with mypyc", .basicsize = sizeof(CPyFunction), .itemsize = 0, .flags = Py_TPFLAGS_IMMUTABLETYPE | #if PY_VERSION_HEX >= 0x030C0000 Py_TPFLAGS_MANAGED_DICT | #endif Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_BASETYPE, .slots = CPyFunction_slots, }; static PyTypeObject *CPyFunctionType = NULL; static PyObject* CPyFunction_Vectorcall(PyObject *func, PyObject *const *args, size_t nargsf, PyObject *kwnames) { CPyFunction *f = (CPyFunction *)func; Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); PyObject *self; PyCFunction meth = ((PyCFunctionObject *)f)->m_ml->ml_meth; self = ((PyCFunctionObject *)f)->m_self; if (!self) { self = args[0]; args += 1; nargs -= 1; } return ((_PyCFunctionFastWithKeywords)(void(*)(void))meth)(self, args, nargs, kwnames); } static CPyFunction* CPyFunction_Init(CPyFunction *op, PyMethodDef *ml, PyObject* name, PyObject *module, PyObject* code, bool set_self) { PyCFunctionObject *cf = (PyCFunctionObject *)op; CPyFunction_weakreflist(op) = NULL; cf->m_ml = ml; cf->m_self = set_self ? (PyObject *) op : NULL; Py_XINCREF(module); cf->m_module = module; Py_INCREF(name); op->func_name = name; ((PyCMethodObject *)op)->mm_class = NULL; Py_XINCREF(code); op->func_code = code; CPyFunction_func_vectorcall(op) = CPyFunction_Vectorcall; return op; } static PyObject* CPyCode_New(const char *filename, const char *funcname, int first_line, int flags) { PyCodeObject *code_obj = PyCode_NewEmpty(filename, funcname, first_line); if (unlikely(!code_obj)) { return NULL; } code_obj->co_flags = flags; return (PyObject *)code_obj; } static PyMethodDef* CPyMethodDef_New(const char *name, PyCFunction func, int flags, const char *doc) { PyMethodDef *method = (PyMethodDef *)PyMem_Malloc(sizeof(PyMethodDef)); if (unlikely(!method)) { return NULL; } method->ml_name = name; method->ml_meth = func; method->ml_flags = flags; method->ml_doc = doc; return method; } PyObject* CPyFunction_New(PyObject *module, const char *filename, const char *funcname, PyCFunction func, int func_flags, const char *func_doc, int first_line, int code_flags, bool has_self_arg) { PyMethodDef *method = NULL; PyObject *code = NULL, *op = NULL; bool set_self = false; if (!CPyFunctionType) { CPyFunctionType = (PyTypeObject *)PyType_FromSpec(&CPyFunction_spec); if (unlikely(!CPyFunctionType)) { goto err; } } method = CPyMethodDef_New(funcname, func, func_flags, func_doc); if (unlikely(!method)) { goto err; } code = CPyCode_New(filename, funcname, first_line, code_flags); if (unlikely(!code)) { goto err; } // Set m_self inside the function wrapper only if the wrapped function has no self arg // to pass m_self as the self arg when the function is called. // When the function has a self arg, it will come in the args vector passed to the // vectorcall handler. set_self = !has_self_arg; op = (PyObject *)CPyFunction_Init(PyObject_GC_New(CPyFunction, CPyFunctionType), method, PyUnicode_FromString(funcname), module, code, set_self); if (unlikely(!op)) { goto err; } PyObject_GC_Track(op); return op; err: CPyError_OutOfMemory(); if (method) { PyMem_Free(method); } return NULL; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/generic_ops.c0000644000175100017510000000456315200142331015013 0ustar00runnerrunner// Generic primitive operations // // These are registered in mypyc.primitives.generic_ops. #include #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 *CPyNumber_InPlacePower(PyObject *base, PyObject *index) { return PyNumber_InPlacePower(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; } typedef PyObject *(*SetupFunction)(PyObject *); PyObject *CPy_SetupObject(PyObject *type) { PyTypeObject *tp = (PyTypeObject *)type; PyMethodDef *def = NULL; for(; tp; tp = tp->tp_base) { def = tp->tp_methods; if (!def || !def->ml_name) { continue; } if (!strcmp(def->ml_name, "__internal_mypyc_setup")) { return ((SetupFunction)(void(*)(void))def->ml_meth)(type); } } PyErr_SetString(PyExc_RuntimeError, "Internal mypyc error: Unable to find object setup function"); return NULL; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/getargs.c0000644000175100017510000003663115200142331014153 0ustar00runnerrunner/* 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 #include #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 */ /* 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 = Py_NewRef(PyTuple_GET_ITEM(args, i)); } else if (nkwargs && i >= pos) { if (unlikely(PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0)) { return 0; } if (current_arg) { --nkwargs; } } else { current_arg = NULL; } if (current_arg) { PyObject **p = va_arg(*p_va, PyObject **); *p = current_arg; Py_DECREF(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++) { PyObject *current_arg; if (unlikely(PyDict_GetItemStringRef(kwargs, kwlist[i], ¤t_arg) < 0)) { goto latefail; } if (unlikely(current_arg != NULL)) { Py_DECREF(current_arg); /* 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; } } /* 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 (PyUnicode_EqualToUTF8(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; format++; if (p_va != NULL) { (void) va_arg(*p_va, PyObject **); } *p_format = format; } #ifdef __cplusplus }; #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/getargsfast.c0000644000175100017510000004457015200142331015032 0ustar00runnerrunner/* 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 #include "CPy.h" #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; 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_Equal(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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/init.c0000644000175100017510000000144715200142331013457 0ustar00runnerrunner#include #include "CPy.h" #include "static_data.c" struct ExcDummyStruct _CPy_ExcDummyStruct = { PyObject_HEAD_INIT(NULL) }; PyObject *_CPy_ExcDummy = (PyObject *)&_CPy_ExcDummyStruct; // System-wide empty tuple constant PyObject * __mypyc_empty_tuple__ = NULL; // 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; // Initialize system-wide empty tuple constant if (__mypyc_empty_tuple__ == NULL) { __mypyc_empty_tuple__ = PyTuple_New(0); if (!__mypyc_empty_tuple__) { CPyError_OutOfMemory(); } } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/int_ops.c0000644000175100017510000005236015200142331014167 0ustar00runnerrunner// Int primitive operations (tagged arbitrary-precision integers) // // These are registered in mypyc.primitives.int_ops. #include #include "CPy.h" #ifdef _MSC_VER #include #endif #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 #if defined(__GNUC__) || defined(__clang__) # if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || (defined(__SIZEOF_POINTER__) && __SIZEOF_POINTER__ == 8) # define CPY_CLZ(x) __builtin_clzll((unsigned long long)(x)) # define CPY_BITS 64 # else # define CPY_CLZ(x) __builtin_clz((unsigned int)(x)) # define CPY_BITS 32 # endif #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_FromVoidPtr(void *ptr) { if ((uintptr_t)ptr > PY_SSIZE_T_MAX) { PyObject *object = PyLong_FromVoidPtr(ptr); return ((CPyTagged)object) | CPY_INT_TAG; } else { return CPyTagged_FromSsize_t((Py_ssize_t)ptr); } } CPyTagged CPyTagged_FromInt64(int64_t value) { if (unlikely(CPyTagged_TooBigInt64(value))) { PyObject *object = PyLong_FromLongLong(value); 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)); } } // Tagged int negation slow path, where the result may be a long integer CPyTagged CPyTagged_Negate_(CPyTagged 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); } // Tagged int addition slow path, where the result may be a long integer CPyTagged CPyTagged_Add_(CPyTagged left, CPyTagged right) { 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); } // Tagged int subtraction slow path, where the result may be a long integer CPyTagged CPyTagged_Subtract_(CPyTagged left, CPyTagged right) { 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); } // Tagged int multiplication slow path, where the result may be a long integer CPyTagged CPyTagged_Multiply_(CPyTagged left, CPyTagged 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); } // Tagged int // slow path, where the result may be a long integer (or raise) CPyTagged CPyTagged_FloorDivide_(CPyTagged left, CPyTagged right) { 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); } } // Tagged int % slow path, where the result may be a long integer (or raise) CPyTagged CPyTagged_Remainder_(CPyTagged left, CPyTagged right) { 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 { PyObject *left_obj = CPyTagged_AsObject(left); PyObject *right_obj = CPyTagged_AsObject(right); int result = PyObject_RichCompareBool(left_obj, right_obj, Py_EQ); Py_DECREF(left_obj); Py_DECREF(right_obj); 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); } CPyTagged CPyTagged_FromFloat(double f) { if (f < ((double)CPY_TAGGED_MAX + 1.0) && f > (CPY_TAGGED_MIN - 1.0)) { return (Py_ssize_t)f << 1; } PyObject *o = PyLong_FromDouble(f); if (o == NULL) return CPY_INT_TAG; return CPyTagged_StealFromObject(o); } PyObject *CPyBool_Str(bool b) { return PyObject_Str(b ? Py_True : Py_False); } // 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 > (Py_ssize_t)PyLong_MASK) { val >>= PyLong_SHIFT; buf[1] = val & PyLong_MASK; if (val > (Py_ssize_t)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 = CPY_LONG_SIZE_SIGNED(obj); return &CPY_LONG_DIGIT(obj, 0); } } // Shared implementation of bitwise '&', '|' and '^' (specified by op) for at least // one long operand. This is somewhat optimized for performance. CPyTagged 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); 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; } void *digits = NULL; PyLongWriter *writer = PyLongWriter_Create(0, op == '&' ? asize : bsize, &digits); if (unlikely(writer == NULL)) { CPyError_OutOfMemory(); } Py_ssize_t i; if (op == '&') { for (i = 0; i < asize; i++) { ((digit *)digits)[i] = adigits[i] & bdigits[i]; } } else { if (op == '|') { for (i = 0; i < asize; i++) { ((digit *)digits)[i] = adigits[i] | bdigits[i]; } } else { for (i = 0; i < asize; i++) { ((digit *)digits)[i] = adigits[i] ^ bdigits[i]; } } for (; i < bsize; i++) { ((digit *)digits)[i] = bdigits[i]; } } return CPyTagged_StealFromObject(PyLongWriter_Finish(writer)); } // Bitwise '~' slow path CPyTagged CPyTagged_Invert_(CPyTagged num) { PyObject *obj = CPyTagged_AsObject(num); PyObject *result = PyNumber_Invert(obj); if (unlikely(result == NULL)) { CPyError_OutOfMemory(); } Py_DECREF(obj); return CPyTagged_StealFromObject(result); } // Bitwise '>>' slow path CPyTagged CPyTagged_Rshift_(CPyTagged left, CPyTagged right) { // 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); } // Bitwise '<<' slow path CPyTagged CPyTagged_Lshift_(CPyTagged left, CPyTagged right) { // 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); } // i64 unboxing slow path int64_t CPyLong_AsInt64_(PyObject *o) { int overflow; int64_t result = PyLong_AsLongLongAndOverflow(o, &overflow); if (result == -1) { if (PyErr_Occurred()) { return CPY_LL_INT_ERROR; } else if (overflow) { PyErr_SetString(PyExc_ValueError, "int too large to convert to i64"); return CPY_LL_INT_ERROR; } } return result; } int64_t CPyInt64_Divide(int64_t x, int64_t y) { if (y == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); return CPY_LL_INT_ERROR; } if (y == -1 && x == INT64_MIN) { PyErr_SetString(PyExc_OverflowError, "integer division overflow"); return CPY_LL_INT_ERROR; } int64_t d = x / y; // Adjust for Python semantics if (((x < 0) != (y < 0)) && d * y != x) { d--; } return d; } int64_t CPyInt64_Remainder(int64_t x, int64_t y) { if (y == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); return CPY_LL_INT_ERROR; } // Edge case: avoid core dump if (y == -1 && x == INT64_MIN) { return 0; } int64_t d = x % y; // Adjust for Python semantics if (((x < 0) != (y < 0)) && d != 0) { d += y; } return d; } // i32 unboxing slow path int32_t CPyLong_AsInt32_(PyObject *o) { int overflow; long result = PyLong_AsLongAndOverflow(o, &overflow); if (result > 0x7fffffffLL || result < -0x80000000LL) { overflow = 1; result = -1; } if (result == -1) { if (PyErr_Occurred()) { return CPY_LL_INT_ERROR; } else if (overflow) { PyErr_SetString(PyExc_ValueError, "int too large to convert to i32"); return CPY_LL_INT_ERROR; } } return result; } int32_t CPyInt32_Divide(int32_t x, int32_t y) { if (y == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); return CPY_LL_INT_ERROR; } if (y == -1 && x == INT32_MIN) { PyErr_SetString(PyExc_OverflowError, "integer division overflow"); return CPY_LL_INT_ERROR; } int32_t d = x / y; // Adjust for Python semantics if (((x < 0) != (y < 0)) && d * y != x) { d--; } return d; } int32_t CPyInt32_Remainder(int32_t x, int32_t y) { if (y == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); return CPY_LL_INT_ERROR; } // Edge case: avoid core dump if (y == -1 && x == INT32_MIN) { return 0; } int32_t d = x % y; // Adjust for Python semantics if (((x < 0) != (y < 0)) && d != 0) { d += y; } return d; } void CPyInt32_Overflow() { PyErr_SetString(PyExc_ValueError, "int too large to convert to i32"); } // i16 unboxing slow path int16_t CPyLong_AsInt16_(PyObject *o) { int overflow; long result = PyLong_AsLongAndOverflow(o, &overflow); if (result > 0x7fff || result < -0x8000) { overflow = 1; result = -1; } if (result == -1) { if (PyErr_Occurred()) { return CPY_LL_INT_ERROR; } else if (overflow) { PyErr_SetString(PyExc_ValueError, "int too large to convert to i16"); return CPY_LL_INT_ERROR; } } return result; } int16_t CPyInt16_Divide(int16_t x, int16_t y) { if (y == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); return CPY_LL_INT_ERROR; } if (y == -1 && x == INT16_MIN) { PyErr_SetString(PyExc_OverflowError, "integer division overflow"); return CPY_LL_INT_ERROR; } int16_t d = x / y; // Adjust for Python semantics if (((x < 0) != (y < 0)) && d * y != x) { d--; } return d; } int16_t CPyInt16_Remainder(int16_t x, int16_t y) { if (y == 0) { PyErr_SetString(PyExc_ZeroDivisionError, "integer division or modulo by zero"); return CPY_LL_INT_ERROR; } // Edge case: avoid core dump if (y == -1 && x == INT16_MIN) { return 0; } int16_t d = x % y; // Adjust for Python semantics if (((x < 0) != (y < 0)) && d != 0) { d += y; } return d; } void CPyInt16_Overflow() { PyErr_SetString(PyExc_ValueError, "int too large to convert to i16"); } // u8 unboxing slow path uint8_t CPyLong_AsUInt8_(PyObject *o) { int overflow; long result = PyLong_AsLongAndOverflow(o, &overflow); if (result < 0 || result >= 256) { overflow = 1; result = -1; } if (result == -1) { if (PyErr_Occurred()) { return CPY_LL_UINT_ERROR; } else if (overflow) { PyErr_SetString(PyExc_ValueError, "int too large or small to convert to u8"); return CPY_LL_UINT_ERROR; } } return result; } void CPyUInt8_Overflow() { PyErr_SetString(PyExc_ValueError, "int too large or small to convert to u8"); } double CPyTagged_TrueDivide(CPyTagged x, CPyTagged y) { if (unlikely(y == 0)) { PyErr_SetString(PyExc_ZeroDivisionError, "division by zero"); return CPY_FLOAT_ERROR; } if (likely(!CPyTagged_CheckLong(x) && !CPyTagged_CheckLong(y))) { return (double)((Py_ssize_t)x >> 1) / (double)((Py_ssize_t)y >> 1); } else { PyObject *xo = CPyTagged_AsObject(x); PyObject *yo = CPyTagged_AsObject(y); PyObject *result = PyNumber_TrueDivide(xo, yo); if (result == NULL) { Py_DECREF(xo); Py_DECREF(yo); return CPY_FLOAT_ERROR; } double value = PyFloat_AsDouble(result); Py_DECREF(xo); Py_DECREF(yo); Py_DECREF(result); return value; } return 1.0; } static PyObject *CPyLong_ToBytes(PyObject *v, Py_ssize_t length, int little_endian, int signed_flag) { // This is a wrapper for PyLong_AsByteArray and PyBytes_FromStringAndSize PyObject *result = PyBytes_FromStringAndSize(NULL, length); if (!result) { return NULL; } unsigned char *bytes = (unsigned char *)PyBytes_AS_STRING(result); #if PY_VERSION_HEX >= 0x030D0000 // 3.13.0 int res = _PyLong_AsByteArray((PyLongObject *)v, bytes, length, little_endian, signed_flag, 1); #else int res = _PyLong_AsByteArray((PyLongObject *)v, bytes, length, little_endian, signed_flag); #endif if (res < 0) { Py_DECREF(result); return NULL; } return result; } // int.to_bytes(length, byteorder, signed=False) PyObject *CPyTagged_ToBytes(CPyTagged self, Py_ssize_t length, PyObject *byteorder, int signed_flag) { PyObject *pyint = CPyTagged_AsObject(self); if (!PyUnicode_Check(byteorder)) { Py_DECREF(pyint); PyErr_SetString(PyExc_TypeError, "byteorder must be str"); return NULL; } const char *order = PyUnicode_AsUTF8(byteorder); if (!order) { Py_DECREF(pyint); return NULL; } int little_endian; if (strcmp(order, "big") == 0) { little_endian = 0; } else if (strcmp(order, "little") == 0) { little_endian = 1; } else { PyErr_SetString(PyExc_ValueError, "byteorder must be either 'little' or 'big'"); return NULL; } PyObject *result = CPyLong_ToBytes(pyint, length, little_endian, signed_flag); Py_DECREF(pyint); return result; } // int.to_bytes(length, byteorder="little", signed=False) PyObject *CPyTagged_ToLittleEndianBytes(CPyTagged self, Py_ssize_t length, int signed_flag) { PyObject *pyint = CPyTagged_AsObject(self); PyObject *result = CPyLong_ToBytes(pyint, length, 1, signed_flag); Py_DECREF(pyint); return result; } // int.to_bytes(length, "big", signed=False) PyObject *CPyTagged_ToBigEndianBytes(CPyTagged self, Py_ssize_t length, int signed_flag) { PyObject *pyint = CPyTagged_AsObject(self); PyObject *result = CPyLong_ToBytes(pyint, length, 0, signed_flag); Py_DECREF(pyint); return result; } // int.bit_length() CPyTagged CPyTagged_BitLength(CPyTagged self) { // Handle zero if (self == 0) { return 0; } // Fast path for small (tagged) ints if (CPyTagged_CheckShort(self)) { Py_ssize_t val = CPyTagged_ShortAsSsize_t(self); Py_ssize_t absval = val < 0 ? -val : val; int bits = 0; if (absval) { #if defined(_MSC_VER) #if defined(_WIN64) unsigned long idx; if (_BitScanReverse64(&idx, (unsigned __int64)absval)) { bits = (int)(idx + 1); } #else unsigned long idx; if (_BitScanReverse(&idx, (unsigned long)absval)) { bits = (int)(idx + 1); } #endif #elif defined(__GNUC__) || defined(__clang__) bits = (int)(CPY_BITS - CPY_CLZ(absval)); #else // Fallback to loop if no builtin while (absval) { absval >>= 1; bits++; } #endif } return bits << 1; } // Slow path for big ints PyObject *pyint = CPyTagged_AsObject(self); int bits = _PyLong_NumBits(pyint); Py_DECREF(pyint); if (bits < 0) { // _PyLong_NumBits sets an error on failure return CPY_INT_TAG; } return bits << 1; } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8552866 librt-0.11.0/internal/0000755000175100017510000000000015200142335014162 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/internal/librt_internal.c0000644000175100017510000011462515200142331017343 0ustar00runnerrunner#include "pythoncapi_compat.h" #define PY_SSIZE_T_CLEAN #include #include #include #include "CPy.h" #define LIBRT_INTERNAL_MODULE #include "librt_internal.h" #define START_SIZE 512 // See comment in read_int_internal() on motivation for these values. #define MIN_ONE_BYTE_INT -10 #define MAX_ONE_BYTE_INT 117 // 2 ** 7 - 1 - 10 #define MIN_TWO_BYTES_INT -100 #define MAX_TWO_BYTES_INT 16283 // 2 ** (8 + 6) - 1 - 100 #define MIN_FOUR_BYTES_INT -10000 #define MAX_FOUR_BYTES_INT 536860911 // 2 ** (3 * 8 + 5) - 1 - 10000 #define TWO_BYTES_INT_BIT 1 #define FOUR_BYTES_INT_BIT 2 #define LONG_INT_BIT 4 #define FOUR_BYTES_INT_TRAILER 3 // We add one reserved bit here so that we can potentially support // 8 bytes format in the future. #define LONG_INT_TRAILER 15 #define CPY_BOOL_ERROR 2 #define _CHECK_READ_BUFFER(data, err) if (unlikely(_check_read_buffer(data) == CPY_NONE_ERROR)) \ return err; #define _CHECK_WRITE_BUFFER(data, err) if (unlikely(_check_write_buffer(data) == CPY_NONE_ERROR)) \ return err; #define _CHECK_WRITE(data, need) if (unlikely(_check_size((WriteBufferObject *)data, need) == CPY_NONE_ERROR)) \ return CPY_NONE_ERROR; #define _CHECK_READ(data, size, err) if (unlikely(_check_read((ReadBufferObject *)data, size) == CPY_NONE_ERROR)) \ return err; #define _READ(result, data, type) \ do { \ memcpy((void *) result, ((ReadBufferObject *)data)->ptr, sizeof(type)); \ ((ReadBufferObject *)data)->ptr += sizeof(type); \ } while (0) #define _WRITE(data, type, v) \ do { \ type temp = v; \ memcpy(((WriteBufferObject *)data)->ptr, (const void *) &temp, sizeof(type)); \ ((WriteBufferObject *)data)->ptr += sizeof(type); \ } while (0) // // ReadBuffer // #if PY_BIG_ENDIAN uint16_t reverse_16(uint16_t number) { return (number << 8) | (number >> 8); } uint32_t reverse_32(uint32_t number) { return ((number & 0xFF) << 24) | ((number & 0xFF00) << 8) | ((number & 0xFF0000) >> 8) | (number >> 24); } #endif typedef struct { PyObject_HEAD char *ptr; // Current read location in the buffer char *end; // End of the buffer PyObject *source; // The object that contains the buffer } ReadBufferObject; static PyTypeObject ReadBufferType; static PyObject* ReadBuffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { if (type != &ReadBufferType) { PyErr_SetString(PyExc_TypeError, "ReadBuffer should not be subclassed"); return NULL; } ReadBufferObject *self = (ReadBufferObject *)type->tp_alloc(type, 0); if (self != NULL) { self->source = NULL; self->ptr = NULL; self->end = NULL; } return (PyObject *) self; } static int ReadBuffer_init_internal(ReadBufferObject *self, PyObject *source) { if (!PyBytes_CheckExact(source)) { PyErr_SetString(PyExc_TypeError, "source must be a bytes object"); return -1; } self->source = Py_NewRef(source); self->ptr = PyBytes_AS_STRING(source); self->end = self->ptr + PyBytes_GET_SIZE(source); return 0; } static PyObject* ReadBuffer_internal(PyObject *source) { ReadBufferObject *self = (ReadBufferObject *)ReadBufferType.tp_alloc(&ReadBufferType, 0); if (self == NULL) return NULL; self->ptr = NULL; self->end = NULL; self->source = NULL; if (ReadBuffer_init_internal(self, source) == -1) { Py_DECREF(self); return NULL; } return (PyObject *)self; } static int ReadBuffer_init(ReadBufferObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"source", NULL}; PyObject *source = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &source)) return -1; return ReadBuffer_init_internal(self, source); } static void ReadBuffer_dealloc(ReadBufferObject *self) { Py_CLEAR(self->source); Py_TYPE(self)->tp_free((PyObject *)self); } static PyMethodDef ReadBuffer_methods[] = { {NULL} /* Sentinel */ }; static PyTypeObject ReadBufferType = { .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "ReadBuffer", .tp_doc = PyDoc_STR("Mypy cache buffer objects"), .tp_basicsize = sizeof(ReadBufferObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = ReadBuffer_new, .tp_init = (initproc) ReadBuffer_init, .tp_dealloc = (destructor) ReadBuffer_dealloc, .tp_methods = ReadBuffer_methods, }; // // WriteBuffer // typedef struct { PyObject_HEAD char *buf; // Beginning of the buffer char *ptr; // Current write location in the buffer char *end; // End of the buffer } WriteBufferObject; static PyTypeObject WriteBufferType; static PyObject* WriteBuffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { if (type != &WriteBufferType) { PyErr_SetString(PyExc_TypeError, "WriteBuffer cannot be subclassed"); return NULL; } WriteBufferObject *self = (WriteBufferObject *)type->tp_alloc(type, 0); if (self != NULL) { self->buf = NULL; self->ptr = NULL; self->end = NULL; } return (PyObject *)self; } static int WriteBuffer_init_internal(WriteBufferObject *self) { Py_ssize_t size = START_SIZE; self->buf = PyMem_Malloc(size + 1); if (self->buf == NULL) { PyErr_NoMemory(); return -1; } self->ptr = self->buf; self->end = self->buf + size; return 0; } static PyObject* WriteBuffer_internal(void) { WriteBufferObject *self = (WriteBufferObject *)WriteBufferType.tp_alloc(&WriteBufferType, 0); if (self == NULL) return NULL; self->buf = NULL; self->ptr = NULL; self->end = NULL; if (WriteBuffer_init_internal(self) == -1) { Py_DECREF(self); return NULL; } return (PyObject *)self; } static int WriteBuffer_init(WriteBufferObject *self, PyObject *args, PyObject *kwds) { if (!PyArg_ParseTuple(args, "")) { return -1; } if (kwds != NULL && PyDict_Size(kwds) > 0) { PyErr_SetString(PyExc_TypeError, "WriteBuffer() takes no keyword arguments"); return -1; } return WriteBuffer_init_internal(self); } static void WriteBuffer_dealloc(WriteBufferObject *self) { PyMem_Free(self->buf); self->buf = NULL; Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject* WriteBuffer_getvalue_internal(PyObject *self) { WriteBufferObject *obj = (WriteBufferObject *)self; return PyBytes_FromStringAndSize(obj->buf, obj->ptr - obj->buf); } static PyObject* WriteBuffer_getvalue(WriteBufferObject *self, PyObject *Py_UNUSED(ignored)) { return PyBytes_FromStringAndSize(self->buf, self->ptr - self->buf); } static PyMethodDef WriteBuffer_methods[] = { {"getvalue", (PyCFunction) WriteBuffer_getvalue, METH_NOARGS, "Return the buffer content as bytes object" }, {NULL} /* Sentinel */ }; static PyTypeObject WriteBufferType = { .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "WriteBuffer", .tp_doc = PyDoc_STR("Mypy cache buffer objects"), .tp_basicsize = sizeof(WriteBufferObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = WriteBuffer_new, .tp_init = (initproc) WriteBuffer_init, .tp_dealloc = (destructor) WriteBuffer_dealloc, .tp_methods = WriteBuffer_methods, }; // ---------- static inline char _check_read_buffer(PyObject *data) { if (unlikely(Py_TYPE(data) != &ReadBufferType)) { PyErr_Format( PyExc_TypeError, "data must be a ReadBuffer object, got %s", Py_TYPE(data)->tp_name ); return CPY_NONE_ERROR; } return CPY_NONE; } static inline char _check_write_buffer(PyObject *data) { if (unlikely(Py_TYPE(data) != &WriteBufferType)) { PyErr_Format( PyExc_TypeError, "data must be a WriteBuffer object, got %s", Py_TYPE(data)->tp_name ); return CPY_NONE_ERROR; } return CPY_NONE; } static inline char _check_size(WriteBufferObject *data, Py_ssize_t need) { if (data->end - data->ptr >= need) return CPY_NONE; Py_ssize_t index = data->ptr - data->buf; Py_ssize_t target = index + need; Py_ssize_t size = data->end - data->buf; do { size *= 2; } while (target >= size); data->buf = PyMem_Realloc(data->buf, size); if (unlikely(data->buf == NULL)) { PyErr_NoMemory(); return CPY_NONE_ERROR; } data->ptr = data->buf + index; data->end = data->buf + size; return CPY_NONE; } static inline char _check_read(ReadBufferObject *data, Py_ssize_t need) { if (unlikely((data->end - data->ptr) < need)) { PyErr_SetString(PyExc_ValueError, "reading past the buffer end"); return CPY_NONE_ERROR; } return CPY_NONE; } /* bool format: single byte \x00 - False \x01 - True */ static char read_bool_internal(PyObject *data) { _CHECK_READ(data, 1, CPY_BOOL_ERROR) char res; _READ(&res, data, char); if (unlikely((res != 0) & (res != 1))) { PyErr_SetString(PyExc_ValueError, "invalid bool value"); return CPY_BOOL_ERROR; } return res; } static PyObject* read_bool(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "read_bool() takes exactly 1 argument (%zu given)", nargs); return NULL; } PyObject *data = args[0]; _CHECK_READ_BUFFER(data, NULL) char res = read_bool_internal(data); if (unlikely(res == CPY_BOOL_ERROR)) return NULL; PyObject *retval = res ? Py_True : Py_False; Py_INCREF(retval); return retval; } static char write_bool_internal(PyObject *data, char value) { _CHECK_WRITE(data, 1) _WRITE(data, char, value); return CPY_NONE; } static PyObject* write_bool(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "write_bool() takes exactly 2 arguments (%zu given)", nargs); return NULL; } PyObject *data = args[0]; PyObject *value = args[1]; _CHECK_WRITE_BUFFER(data, NULL) if (unlikely(!PyBool_Check(value))) { PyErr_SetString(PyExc_TypeError, "value must be a bool"); return NULL; } if (unlikely(write_bool_internal(data, Py_IsTrue(value)) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } /* str format: size as int (see below) followed by UTF-8 bytes */ static inline CPyTagged _read_short_int(PyObject *data, uint8_t first) { uint8_t second; uint16_t two_more; if ((first & TWO_BYTES_INT_BIT) == 0) { // Note we use tagged ints since this function can return an error. return ((Py_ssize_t)(first >> 1) + MIN_ONE_BYTE_INT) << 1; } if ((first & FOUR_BYTES_INT_BIT) == 0) { _CHECK_READ(data, 1, CPY_INT_TAG) _READ(&second, data, uint8_t); return ((((Py_ssize_t)second) << 6) + (Py_ssize_t)(first >> 2) + MIN_TWO_BYTES_INT) << 1; } // The caller is responsible to verify this is called only for short ints. _CHECK_READ(data, 3, CPY_INT_TAG) // TODO: check if compilers emit optimal code for these two reads, and tweak if needed. _READ(&second, data, uint8_t); _READ(&two_more, data, uint16_t); #if PY_BIG_ENDIAN two_more = reverse_16(two_more); #endif Py_ssize_t higher = (((Py_ssize_t)two_more) << 13) + (((Py_ssize_t)second) << 5); return (higher + (Py_ssize_t)(first >> 3) + MIN_FOUR_BYTES_INT) << 1; } static PyObject* read_str_internal(PyObject *data) { // Read string length. _CHECK_READ(data, 1, NULL) uint8_t first; _READ(&first, data, uint8_t); if (unlikely(first == LONG_INT_TRAILER)) { // Fail fast for invalid/tampered data. PyErr_SetString(PyExc_ValueError, "invalid str size"); return NULL; } CPyTagged tagged_size = _read_short_int(data, first); if (tagged_size == CPY_INT_TAG) return NULL; if ((Py_ssize_t)tagged_size < 0) { // Fail fast for invalid/tampered data. PyErr_SetString(PyExc_ValueError, "invalid str size"); return NULL; } Py_ssize_t size = tagged_size >> 1; // Read string content. char *ptr = ((ReadBufferObject *)data)->ptr; _CHECK_READ(data, size, NULL) PyObject *res = PyUnicode_FromStringAndSize(ptr, (Py_ssize_t)size); if (unlikely(res == NULL)) return NULL; ((ReadBufferObject *)data)->ptr += size; return res; } static PyObject* read_str(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "read_str() takes exactly 1 argument (%zu given)", nargs); return NULL; } PyObject *data = args[0]; _CHECK_READ_BUFFER(data, NULL) return read_str_internal(data); } // The caller *must* check that real_value is within allowed range (29 bits). static inline char _write_short_int(PyObject *data, Py_ssize_t real_value) { if (real_value >= MIN_ONE_BYTE_INT && real_value <= MAX_ONE_BYTE_INT) { _CHECK_WRITE(data, 1) _WRITE(data, uint8_t, (uint8_t)(real_value - MIN_ONE_BYTE_INT) << 1); } else if (real_value >= MIN_TWO_BYTES_INT && real_value <= MAX_TWO_BYTES_INT) { _CHECK_WRITE(data, 2) #if PY_BIG_ENDIAN uint16_t to_write = ((uint16_t)(real_value - MIN_TWO_BYTES_INT) << 2) | TWO_BYTES_INT_BIT; _WRITE(data, uint16_t, reverse_16(to_write)); #else _WRITE(data, uint16_t, ((uint16_t)(real_value - MIN_TWO_BYTES_INT) << 2) | TWO_BYTES_INT_BIT); #endif } else { _CHECK_WRITE(data, 4) #if PY_BIG_ENDIAN uint32_t to_write = ((uint32_t)(real_value - MIN_FOUR_BYTES_INT) << 3) | FOUR_BYTES_INT_TRAILER; _WRITE(data, uint32_t, reverse_32(to_write)); #else _WRITE(data, uint32_t, ((uint32_t)(real_value - MIN_FOUR_BYTES_INT) << 3) | FOUR_BYTES_INT_TRAILER); #endif } return CPY_NONE; } static char write_str_internal(PyObject *data, PyObject *value) { Py_ssize_t size; const char *chunk = PyUnicode_AsUTF8AndSize(value, &size); if (unlikely(chunk == NULL)) return CPY_NONE_ERROR; // Write string length. if (likely(size >= MIN_FOUR_BYTES_INT && size <= MAX_FOUR_BYTES_INT)) { if (_write_short_int(data, size) == CPY_NONE_ERROR) return CPY_NONE_ERROR; } else { PyErr_SetString(PyExc_ValueError, "str too long to serialize"); return CPY_NONE_ERROR; } // Write string content. _CHECK_WRITE(data, size) char *ptr = ((WriteBufferObject *)data)->ptr; memcpy(ptr, chunk, size); ((WriteBufferObject *)data)->ptr += size; return CPY_NONE; } static PyObject* write_str(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "write_str() takes exactly 2 arguments (%zu given)", nargs); return NULL; } PyObject *data = args[0]; PyObject *value = args[1]; _CHECK_WRITE_BUFFER(data, NULL) if (unlikely(!PyUnicode_Check(value))) { PyErr_SetString(PyExc_TypeError, "value must be a str"); return NULL; } if (unlikely(write_str_internal(data, value) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } /* bytes format: size as int (see below) followed by bytes */ static PyObject* read_bytes_internal(PyObject *data) { // Read length. _CHECK_READ(data, 1, NULL) uint8_t first; _READ(&first, data, uint8_t); if (unlikely(first == LONG_INT_TRAILER)) { // Fail fast for invalid/tampered data. PyErr_SetString(PyExc_ValueError, "invalid bytes size"); return NULL; } CPyTagged tagged_size = _read_short_int(data, first); if (tagged_size == CPY_INT_TAG) return NULL; if ((Py_ssize_t)tagged_size < 0) { // Fail fast for invalid/tampered data. PyErr_SetString(PyExc_ValueError, "invalid bytes size"); return NULL; } Py_ssize_t size = tagged_size >> 1; // Read bytes content. char *ptr = ((ReadBufferObject *)data)->ptr; _CHECK_READ(data, size, NULL) PyObject *res = PyBytes_FromStringAndSize(ptr, (Py_ssize_t)size); if (unlikely(res == NULL)) return NULL; ((ReadBufferObject *)data)->ptr += size; return res; } static PyObject* read_bytes(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "read_bytes() takes exactly 1 argument (%zu given)", nargs); return NULL; } PyObject *data = args[0]; _CHECK_READ_BUFFER(data, NULL) return read_bytes_internal(data); } static char write_bytes_internal(PyObject *data, PyObject *value) { const char *chunk = PyBytes_AsString(value); if (unlikely(chunk == NULL)) return CPY_NONE_ERROR; Py_ssize_t size = PyBytes_GET_SIZE(value); // Write length. if (likely(size >= MIN_FOUR_BYTES_INT && size <= MAX_FOUR_BYTES_INT)) { if (_write_short_int(data, size) == CPY_NONE_ERROR) return CPY_NONE_ERROR; } else { PyErr_SetString(PyExc_ValueError, "bytes too long to serialize"); return CPY_NONE_ERROR; } // Write bytes content. _CHECK_WRITE(data, size) char *ptr = ((WriteBufferObject *)data)->ptr; memcpy(ptr, chunk, size); ((WriteBufferObject *)data)->ptr += size; return CPY_NONE; } static PyObject* write_bytes(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "write_bytes() takes exactly 2 arguments (%zu given)", nargs); return NULL; } PyObject *data = args[0]; PyObject *value = args[1]; _CHECK_WRITE_BUFFER(data, NULL) if (unlikely(!PyBytes_Check(value))) { PyErr_SetString(PyExc_TypeError, "value must be a bytes object"); return NULL; } if (unlikely(write_bytes_internal(data, value) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } /* float format: stored using PyFloat helpers in little-endian format. */ static double read_float_internal(PyObject *data) { _CHECK_READ(data, 8, CPY_FLOAT_ERROR) char *ptr = ((ReadBufferObject *)data)->ptr; double res = PyFloat_Unpack8(ptr, 1); if (unlikely((res == -1.0) && PyErr_Occurred())) return CPY_FLOAT_ERROR; ((ReadBufferObject *)data)->ptr += 8; return res; } static PyObject* read_float(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "read_float() takes exactly 1 argument (%zu given)", nargs); return NULL; } PyObject *data = args[0]; _CHECK_READ_BUFFER(data, NULL) double retval = read_float_internal(data); if (unlikely(retval == CPY_FLOAT_ERROR && PyErr_Occurred())) { return NULL; } return PyFloat_FromDouble(retval); } static char write_float_internal(PyObject *data, double value) { _CHECK_WRITE(data, 8) char *ptr = ((WriteBufferObject *)data)->ptr; int res = PyFloat_Pack8(value, ptr, 1); if (unlikely(res == -1)) return CPY_NONE_ERROR; ((WriteBufferObject *)data)->ptr += 8; return CPY_NONE; } static PyObject* write_float(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "write_float() takes exactly 2 arguments (%zu given)", nargs); return NULL; } PyObject *data = args[0]; PyObject *value = args[1]; _CHECK_WRITE_BUFFER(data, NULL) if (unlikely(!PyFloat_Check(value))) { PyErr_SetString(PyExc_TypeError, "value must be a float"); return NULL; } if (unlikely(write_float_internal(data, PyFloat_AsDouble(value)) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } /* int format: one byte: last bit 0, 7 bits used two bytes: last two bits 01, 14 bits used four bytes: last three bits 011, 29 bits used everything else: 00001111 followed by serialized string representation Note: for fixed size formats we skew ranges towards more positive values, since negative integers are much more rare. */ static CPyTagged read_int_internal(PyObject *data) { _CHECK_READ(data, 1, CPY_INT_TAG) uint8_t first; _READ(&first, data, uint8_t); if (likely(first != LONG_INT_TRAILER)) { return _read_short_int(data, first); } // Long integer encoding -- byte length and sign, followed by a byte array. // Read byte length and sign. _CHECK_READ(data, 1, CPY_INT_TAG) _READ(&first, data, uint8_t); Py_ssize_t size_and_sign = _read_short_int(data, first); if (size_and_sign == CPY_INT_TAG) return CPY_INT_TAG; if ((Py_ssize_t)size_and_sign < 0) { PyErr_SetString(PyExc_ValueError, "invalid int data"); return CPY_INT_TAG; } bool sign = (size_and_sign >> 1) & 1; Py_ssize_t size = size_and_sign >> 2; // Construct an int object from the byte array. _CHECK_READ(data, size, CPY_INT_TAG) char *ptr = ((ReadBufferObject *)data)->ptr; PyObject *num = _PyLong_FromByteArray((unsigned char *)ptr, size, 1, 0); if (num == NULL) return CPY_INT_TAG; ((ReadBufferObject *)data)->ptr += size; if (sign) { PyObject *old = num; num = PyNumber_Negative(old); Py_DECREF(old); if (num == NULL) { return CPY_INT_TAG; } } return CPyTagged_StealFromObject(num); } static PyObject* read_int(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "read_int() takes exactly 1 argument (%zu given)", nargs); return NULL; } PyObject *data = args[0]; _CHECK_READ_BUFFER(data, NULL) CPyTagged retval = read_int_internal(data); if (unlikely(retval == CPY_INT_TAG)) { return NULL; } return CPyTagged_StealAsObject(retval); } static inline int hex_to_int(char c) { if (c >= '0' && c <= '9') return c - '0'; else if (c >= 'a' && c <= 'f') return c - 'a' + 10; else return c - 'A' + 10; // Assume valid hex digit } static inline char _write_long_int(PyObject *data, CPyTagged value) { _CHECK_WRITE(data, 1) _WRITE(data, uint8_t, LONG_INT_TRAILER); PyObject *hex_str = NULL; PyObject* int_value = CPyTagged_AsObject(value); if (unlikely(int_value == NULL)) goto error; hex_str = PyNumber_ToBase(int_value, 16); if (hex_str == NULL) goto error; Py_DECREF(int_value); int_value = NULL; const char *str = PyUnicode_AsUTF8(hex_str); if (str == NULL) goto error; Py_ssize_t len = strlen(str); bool neg; if (str[0] == '-') { str++; len--; neg = true; } else { neg = false; } // Skip the 0x hex prefix. str += 2; len -= 2; // Write bytes encoded length and sign. Py_ssize_t size = (len + 1) / 2; Py_ssize_t encoded_size = (size << 1) | neg; if (encoded_size <= MAX_FOUR_BYTES_INT) { if (_write_short_int(data, encoded_size) == CPY_NONE_ERROR) goto error; } else { PyErr_SetString(PyExc_ValueError, "int too long to serialize"); goto error; } // Write absolute integer value as byte array in a variable-length little endian format. Py_ssize_t i; for (i = len; i > 1; i -= 2) { if (write_tag_internal( data, hex_to_int(str[i - 1]) | (hex_to_int(str[i - 2]) << 4)) == CPY_NONE_ERROR) goto error; } // The final byte may correspond to only one hex digit. if (i == 1) { if (write_tag_internal(data, hex_to_int(str[i - 1])) == CPY_NONE_ERROR) goto error; } Py_DECREF(hex_str); return CPY_NONE; error: Py_XDECREF(int_value); Py_XDECREF(hex_str); return CPY_NONE_ERROR; } static char write_int_internal(PyObject *data, CPyTagged value) { if (likely((value & CPY_INT_TAG) == 0)) { Py_ssize_t real_value = CPyTagged_ShortAsSsize_t(value); if (likely(real_value >= MIN_FOUR_BYTES_INT && real_value <= MAX_FOUR_BYTES_INT)) { return _write_short_int(data, real_value); } else { return _write_long_int(data, value); } } else { return _write_long_int(data, value); } } static PyObject* write_int(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "write_int() takes exactly 2 arguments (%zu given)", nargs); return NULL; } PyObject *data = args[0]; PyObject *value = args[1]; _CHECK_WRITE_BUFFER(data, NULL) if (unlikely(!PyLong_Check(value))) { PyErr_SetString(PyExc_TypeError, "value must be an int"); return NULL; } CPyTagged tagged_value = CPyTagged_BorrowFromObject(value); if (unlikely(write_int_internal(data, tagged_value) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } /* integer tag format (0 <= t <= 255): stored as a uint8_t */ static uint8_t read_tag_internal(PyObject *data) { _CHECK_READ(data, 1, CPY_LL_UINT_ERROR) uint8_t ret; _READ(&ret, data, uint8_t); return ret; } static PyObject* read_tag(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "read_tag() takes exactly 1 argument (%zu given)", nargs); return NULL; } PyObject *data = args[0]; _CHECK_READ_BUFFER(data, NULL) uint8_t retval = read_tag_internal(data); if (unlikely(retval == CPY_LL_UINT_ERROR && PyErr_Occurred())) { return NULL; } return PyLong_FromLong(retval); } static char write_tag_internal(PyObject *data, uint8_t value) { _CHECK_WRITE(data, 1) _WRITE(data, uint8_t, value); return CPY_NONE; } static PyObject* write_tag(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "write_tag() takes exactly 2 arguments (%zu given)", nargs); return NULL; } PyObject *data = args[0]; PyObject *value = args[1]; _CHECK_WRITE_BUFFER(data, NULL) uint8_t unboxed = CPyLong_AsUInt8(value); if (unlikely(unboxed == CPY_LL_UINT_ERROR && PyErr_Occurred())) { CPy_TypeError("u8", value); return NULL; } if (unlikely(write_tag_internal(data, unboxed) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } // All tags must be kept in sync with cache.py, nodes.py, and types.py. // Primitive types. #define LITERAL_FALSE 0 #define LITERAL_TRUE 1 #define LITERAL_NONE 2 #define LITERAL_INT 3 #define LITERAL_STR 4 #define LITERAL_BYTES 5 #define LITERAL_FLOAT 6 #define LITERAL_COMPLEX 7 // Supported builtin collections. #define LIST_GEN 20 #define LIST_INT 21 #define LIST_STR 22 #define LIST_BYTES 23 #define TUPLE_GEN 24 #define DICT_STR_GEN 30 // This is the smallest custom class tag. #define MYPY_FILE 50 // Instance class has special formats. #define INSTANCE 80 #define INSTANCE_SIMPLE 81 #define INSTANCE_GENERIC 82 #define INSTANCE_STR 83 #define INSTANCE_FUNCTION 84 #define INSTANCE_INT 85 #define INSTANCE_BOOL 86 #define INSTANCE_OBJECT 87 #define RESERVED 254 #define END_TAG 255 // Forward declaration. static char _skip_object(PyObject *data, uint8_t tag); static inline char _skip(PyObject *data, Py_ssize_t size) { // We are careful about error conditions, so all // _skip_xxx() functions can return an error value. _CHECK_READ(data, size, CPY_NONE_ERROR) ((ReadBufferObject *)data)->ptr += size; return CPY_NONE; } static inline char _skip_short_int(PyObject *data, uint8_t first) { if ((first & TWO_BYTES_INT_BIT) == 0) return CPY_NONE; if ((first & FOUR_BYTES_INT_BIT) == 0) return _skip(data, 1); return _skip(data, 3); } static inline char _skip_int(PyObject *data) { _CHECK_READ(data, 1, CPY_NONE_ERROR) uint8_t first; _READ(&first, data, uint8_t); if (likely(first != LONG_INT_TRAILER)) { return _skip_short_int(data, first); } _CHECK_READ(data, 1, CPY_NONE_ERROR) _READ(&first, data, uint8_t); Py_ssize_t size_and_sign = _read_short_int(data, first); if (size_and_sign == CPY_INT_TAG) return CPY_NONE_ERROR; if ((Py_ssize_t)size_and_sign < 0) { PyErr_SetString(PyExc_ValueError, "invalid int data"); return CPY_NONE_ERROR; } Py_ssize_t size = size_and_sign >> 2; return _skip(data, size); } // This is essentially a wrapper around _read_short_int() that makes // sure the result is valid. static inline Py_ssize_t _read_size(PyObject *data) { _CHECK_READ(data, 1, -1) uint8_t first; _READ(&first, data, uint8_t); // We actually allow serializing lists/dicts with over 4 billion items, // but we don't really need to, fail with ValueError just in case. if (unlikely(first == LONG_INT_TRAILER)) { PyErr_SetString(PyExc_ValueError, "unsupported size"); return -1; } CPyTagged tagged_size = _read_short_int(data, first); if (tagged_size == CPY_INT_TAG) return -1; if ((Py_ssize_t)tagged_size < 0) { PyErr_SetString(PyExc_ValueError, "invalid size"); return -1; } Py_ssize_t size = tagged_size >> 1; return size; } static inline char _skip_str_bytes(PyObject *data) { Py_ssize_t size = _read_size(data); if (size < 0) return CPY_NONE_ERROR; return _skip(data, size); } // List/dict logic should be kept in sync with mypy/cache.py static inline char _skip_list_gen(PyObject *data) { Py_ssize_t size = _read_size(data); if (size < 0) return CPY_NONE_ERROR; Py_ssize_t i; for (i = 0; i < size; i++) { uint8_t tag = read_tag_internal(data); if (unlikely(tag == CPY_LL_UINT_ERROR && PyErr_Occurred())) { return CPY_NONE_ERROR; } if (unlikely(_skip_object(data, tag) == CPY_NONE_ERROR)) return CPY_NONE_ERROR; } return CPY_NONE; } static inline char _skip_list_int(PyObject *data) { Py_ssize_t size = _read_size(data); if (size < 0) return CPY_NONE_ERROR; Py_ssize_t i; for (i = 0; i < size; i++) { if (unlikely(_skip_int(data) == CPY_NONE_ERROR)) return CPY_NONE_ERROR; } return CPY_NONE; } static inline char _skip_list_str_bytes(PyObject *data) { Py_ssize_t size = _read_size(data); if (size < 0) return CPY_NONE_ERROR; Py_ssize_t i; for (i = 0; i < size; i++) { if (unlikely(_skip_str_bytes(data) == CPY_NONE_ERROR)) return CPY_NONE_ERROR; } return CPY_NONE; } static inline char _skip_dict_str_gen(PyObject *data) { Py_ssize_t size = _read_size(data); if (size < 0) return CPY_NONE_ERROR; Py_ssize_t i; for (i = 0; i < size; i++) { // Bare key followed by tagged value. if (unlikely(_skip_str_bytes(data) == CPY_NONE_ERROR)) return CPY_NONE_ERROR; uint8_t tag = read_tag_internal(data); if (unlikely(tag == CPY_LL_UINT_ERROR && PyErr_Occurred())) { return CPY_NONE_ERROR; } if (unlikely(_skip_object(data, tag) == CPY_NONE_ERROR)) return CPY_NONE_ERROR; } return CPY_NONE; } // Similar to mypy/cache.py, the convention is that the caller reads // the opening tag for custom classes. static inline char _skip_class(PyObject *data) { while (1) { uint8_t tag = read_tag_internal(data); if (unlikely(tag == CPY_LL_UINT_ERROR && PyErr_Occurred())) { return CPY_NONE_ERROR; } if (tag == END_TAG) { return CPY_NONE; } if (unlikely(_skip_object(data, tag) == CPY_NONE_ERROR)) { return CPY_NONE_ERROR; } } } // Instance has special compact layout (as an important optimization). static inline char _skip_instance(PyObject *data) { uint8_t second_tag = read_tag_internal(data); if (unlikely(second_tag == CPY_LL_UINT_ERROR && PyErr_Occurred())) { return CPY_NONE_ERROR; } if (second_tag >= INSTANCE_STR && second_tag <= INSTANCE_OBJECT) { return CPY_NONE; } if (second_tag == INSTANCE_SIMPLE) { return _skip_str_bytes(data); } if (second_tag == INSTANCE_GENERIC) { return _skip_class(data); } PyErr_Format(PyExc_ValueError, "Unexpected instance tag: %d", second_tag); return CPY_NONE_ERROR; } // This is the main dispatch point. Branches are ordered manually // based roughly on frequency in self-check. static char _skip_object(PyObject *data, uint8_t tag) { if (tag == LITERAL_STR || tag == LITERAL_BYTES) return _skip_str_bytes(data); if (tag == LITERAL_NONE || tag == LITERAL_FALSE || tag == LITERAL_TRUE) return CPY_NONE; if (tag == LIST_GEN || tag == TUPLE_GEN) return _skip_list_gen(data); if (tag == LITERAL_INT) return _skip_int(data); if (tag == INSTANCE) return _skip_instance(data); // We intentionally exclude MypyFile as a sanity check. Module symbols should // be always handled via cross_ref, and never appear in a symbol table as is. if (tag > MYPY_FILE && tag < RESERVED) return _skip_class(data); if (tag == LIST_INT) return _skip_list_int(data); if (tag == LIST_STR || tag == LIST_BYTES) return _skip_list_str_bytes(data); if (tag == DICT_STR_GEN) return _skip_dict_str_gen(data); if (tag == LITERAL_FLOAT) return _skip(data, 8); if (tag == LITERAL_COMPLEX) return _skip(data, 16); PyErr_Format(PyExc_ValueError, "Unsupported tag: %d", tag); return CPY_NONE_ERROR; } static PyObject* extract_symbol_internal(PyObject *data) { char *ptr = ((ReadBufferObject *)data)->ptr; if (unlikely(_skip_class(data) == CPY_NONE_ERROR)) return NULL; Py_ssize_t size = ((ReadBufferObject *)data)->ptr - ptr; PyObject *res = PyBytes_FromStringAndSize(ptr, size); if (unlikely(res == NULL)) return NULL; return res; } static PyObject* extract_symbol(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "extract_symbol() takes exactly 1 argument (%zu given)", nargs); return NULL; } PyObject *data = args[0]; _CHECK_READ_BUFFER(data, NULL) return extract_symbol_internal(data); } static uint8_t cache_version_internal(void) { return 0; } static PyObject* cache_version(PyObject *self, PyObject *Py_UNUSED(ignored)) { return PyLong_FromLong(cache_version_internal()); } static PyTypeObject * ReadBuffer_type_internal(void) { return &ReadBufferType; // Return borrowed reference } static PyTypeObject * WriteBuffer_type_internal(void) { return &WriteBufferType; // Return borrowed reference }; static PyMethodDef librt_internal_module_methods[] = { {"write_bool", (PyCFunction)write_bool, METH_FASTCALL, PyDoc_STR("write a bool")}, {"read_bool", (PyCFunction)read_bool, METH_FASTCALL, PyDoc_STR("read a bool")}, {"write_str", (PyCFunction)write_str, METH_FASTCALL, PyDoc_STR("write a string")}, {"read_str", (PyCFunction)read_str, METH_FASTCALL, PyDoc_STR("read a string")}, {"write_bytes", (PyCFunction)write_bytes, METH_FASTCALL, PyDoc_STR("write bytes")}, {"read_bytes", (PyCFunction)read_bytes, METH_FASTCALL, PyDoc_STR("read bytes")}, {"write_float", (PyCFunction)write_float, METH_FASTCALL, PyDoc_STR("write a float")}, {"read_float", (PyCFunction)read_float, METH_FASTCALL, PyDoc_STR("read a float")}, {"write_int", (PyCFunction)write_int, METH_FASTCALL, PyDoc_STR("write an int")}, {"read_int", (PyCFunction)read_int, METH_FASTCALL, PyDoc_STR("read an int")}, {"write_tag", (PyCFunction)write_tag, METH_FASTCALL, PyDoc_STR("write a short int")}, {"read_tag", (PyCFunction)read_tag, METH_FASTCALL, PyDoc_STR("read a short int")}, {"cache_version", (PyCFunction)cache_version, METH_NOARGS, PyDoc_STR("cache format version")}, {"extract_symbol", (PyCFunction)extract_symbol, METH_FASTCALL, PyDoc_STR("extract bytes for a mypy symbol")}, {NULL, NULL, 0, NULL} }; static int NativeInternal_ABI_Version(void) { return LIBRT_INTERNAL_ABI_VERSION; } static int NativeInternal_API_Version(void) { return LIBRT_INTERNAL_API_VERSION; } static int librt_internal_module_exec(PyObject *m) { if (PyType_Ready(&ReadBufferType) < 0) { return -1; } if (PyType_Ready(&WriteBufferType) < 0) { return -1; } if (PyModule_AddObjectRef(m, "ReadBuffer", (PyObject *) &ReadBufferType) < 0) { return -1; } if (PyModule_AddObjectRef(m, "WriteBuffer", (PyObject *) &WriteBufferType) < 0) { return -1; } // Export mypy internal C API, be careful with the order! static void *NativeInternal_API[LIBRT_INTERNAL_API_LEN] = { (void *)ReadBuffer_internal, (void *)WriteBuffer_internal, (void *)WriteBuffer_getvalue_internal, (void *)write_bool_internal, (void *)read_bool_internal, (void *)write_str_internal, (void *)read_str_internal, (void *)write_float_internal, (void *)read_float_internal, (void *)write_int_internal, (void *)read_int_internal, (void *)write_tag_internal, (void *)read_tag_internal, (void *)NativeInternal_ABI_Version, (void *)write_bytes_internal, (void *)read_bytes_internal, (void *)cache_version_internal, (void *)ReadBuffer_type_internal, (void *)WriteBuffer_type_internal, (void *)NativeInternal_API_Version, (void *)extract_symbol_internal }; PyObject *c_api_object = PyCapsule_New((void *)NativeInternal_API, "librt.internal._C_API", NULL); if (PyModule_Add(m, "_C_API", c_api_object) < 0) { return -1; } return 0; } static PyModuleDef_Slot librt_internal_module_slots[] = { {Py_mod_exec, librt_internal_module_exec}, #ifdef Py_MOD_GIL_NOT_USED {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} }; static PyModuleDef librt_internal_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "internal", .m_doc = "Mypy cache serialization utils", .m_size = 0, .m_methods = librt_internal_module_methods, .m_slots = librt_internal_module_slots, }; PyMODINIT_FUNC PyInit_internal(void) { return PyModuleDef_Init(&librt_internal_module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/internal/librt_internal.h0000644000175100017510000000377115200142331017347 0ustar00runnerrunner#ifndef LIBRT_INTERNAL_H #define LIBRT_INTERNAL_H #include #include // ABI version -- only an exact match is compatible. This will only be changed in // very exceptional cases (likely never) due to strict backward compatibility // requirements. #define LIBRT_INTERNAL_ABI_VERSION 2 // API version -- more recent versions must maintain backward compatibility, i.e. // we can add new features but not remove or change existing features (unless // ABI version is changed, but see the comment above). #define LIBRT_INTERNAL_API_VERSION 1 // Number of functions in the capsule API. If you add a new function, also increase // LIBRT_INTERNAL_API_VERSION. #define LIBRT_INTERNAL_API_LEN 21 #ifdef LIBRT_INTERNAL_MODULE static PyObject *ReadBuffer_internal(PyObject *source); static PyObject *WriteBuffer_internal(void); static PyObject *WriteBuffer_getvalue_internal(PyObject *self); static PyObject *ReadBuffer_internal(PyObject *source); static PyObject *ReadBuffer_internal_empty(void); static char write_bool_internal(PyObject *data, char value); static char read_bool_internal(PyObject *data); static char write_str_internal(PyObject *data, PyObject *value); static PyObject *read_str_internal(PyObject *data); static char write_float_internal(PyObject *data, double value); static double read_float_internal(PyObject *data); static char write_int_internal(PyObject *data, CPyTagged value); static CPyTagged read_int_internal(PyObject *data); static char write_tag_internal(PyObject *data, uint8_t value); static uint8_t read_tag_internal(PyObject *data); static int NativeInternal_ABI_Version(void); static char write_bytes_internal(PyObject *data, PyObject *value); static PyObject *read_bytes_internal(PyObject *data); static uint8_t cache_version_internal(void); static PyTypeObject *ReadBuffer_type_internal(void); static PyTypeObject *WriteBuffer_type_internal(void); static int NativeInternal_API_Version(void); static PyObject *extract_symbol_internal(PyObject *data); #endif #endif // LIBRT_INTERNAL_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/internal/librt_internal_api.c0000644000175100017510000000312715200142331020166 0ustar00runnerrunner#include "librt_internal_api.h" void *NativeInternal_API[LIBRT_INTERNAL_API_LEN] = {0}; int import_librt_internal(void) { PyObject *mod = PyImport_ImportModule("librt.internal"); if (mod == NULL) return -1; Py_DECREF(mod); // we import just for the side effect of making the below work. void **capsule = (void **)PyCapsule_Import("librt.internal._C_API", 0); if (capsule == NULL) return -1; // Each librt capsule gives at least 20 entries. Validate version before copying the table. int (*abi_version)(void) = (int (*)(void))capsule[13]; if (abi_version() != LIBRT_INTERNAL_ABI_VERSION) { char err[128]; snprintf(err, sizeof(err), "ABI version conflict for librt.internal, expected %d, found %d", LIBRT_INTERNAL_ABI_VERSION, abi_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } int (*api_version)(void) = (int (*)(void))capsule[19]; if (api_version() < LIBRT_INTERNAL_API_VERSION) { char err[128]; snprintf(err, sizeof(err), "API version conflict for librt.internal, expected %d or newer, found %d (hint: upgrade librt)", LIBRT_INTERNAL_API_VERSION, api_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } // Provider API version is >= our expected version, which (by the API // compatibility contract) means it has at least LIBRT_INTERNAL_API_LEN // entries, so this copy is safe. memcpy(NativeInternal_API, capsule, sizeof(NativeInternal_API)); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/internal/librt_internal_api.h0000644000175100017510000000436215200142331020175 0ustar00runnerrunner#ifndef LIBRT_INTERNAL_API_H #define LIBRT_INTERNAL_API_H #include "librt_internal.h" extern void *NativeInternal_API[LIBRT_INTERNAL_API_LEN]; #define ReadBuffer_internal (*(PyObject* (*)(PyObject *source)) NativeInternal_API[0]) #define WriteBuffer_internal (*(PyObject* (*)(void)) NativeInternal_API[1]) #define WriteBuffer_getvalue_internal (*(PyObject* (*)(PyObject *source)) NativeInternal_API[2]) #define write_bool_internal (*(char (*)(PyObject *source, char value)) NativeInternal_API[3]) #define read_bool_internal (*(char (*)(PyObject *source)) NativeInternal_API[4]) #define write_str_internal (*(char (*)(PyObject *source, PyObject *value)) NativeInternal_API[5]) #define read_str_internal (*(PyObject* (*)(PyObject *source)) NativeInternal_API[6]) #define write_float_internal (*(char (*)(PyObject *source, double value)) NativeInternal_API[7]) #define read_float_internal (*(double (*)(PyObject *source)) NativeInternal_API[8]) #define write_int_internal (*(char (*)(PyObject *source, CPyTagged value)) NativeInternal_API[9]) #define read_int_internal (*(CPyTagged (*)(PyObject *source)) NativeInternal_API[10]) #define write_tag_internal (*(char (*)(PyObject *source, uint8_t value)) NativeInternal_API[11]) #define read_tag_internal (*(uint8_t (*)(PyObject *source)) NativeInternal_API[12]) #define NativeInternal_ABI_Version (*(int (*)(void)) NativeInternal_API[13]) #define write_bytes_internal (*(char (*)(PyObject *source, PyObject *value)) NativeInternal_API[14]) #define read_bytes_internal (*(PyObject* (*)(PyObject *source)) NativeInternal_API[15]) #define cache_version_internal (*(uint8_t (*)(void)) NativeInternal_API[16]) #define ReadBuffer_type_internal (*(PyTypeObject* (*)(void)) NativeInternal_API[17]) #define WriteBuffer_type_internal (*(PyTypeObject* (*)(void)) NativeInternal_API[18]) #define NativeInternal_API_Version (*(int (*)(void)) NativeInternal_API[19]) #define extract_symbol_internal (*(PyObject* (*)(PyObject *source)) NativeInternal_API[20]) int import_librt_internal(void); static inline bool CPyReadBuffer_Check(PyObject *obj) { return Py_TYPE(obj) == ReadBuffer_type_internal(); } static inline bool CPyWriteBuffer_Check(PyObject *obj) { return Py_TYPE(obj) == WriteBuffer_type_internal(); } #endif // LIBRT_INTERNAL_API_H ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8565025 librt-0.11.0/librt/0000755000175100017510000000000015200142335013462 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/__init__.pyi0000644000175100017510000000000015200142320015724 0ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/base64.pyi0000644000175100017510000000026415200142320015265 0ustar00runnerrunnerdef b64encode(s: bytes) -> bytes: ... def b64decode(s: bytes | str) -> bytes: ... def urlsafe_b64encode(s: bytes) -> bytes: ... def urlsafe_b64decode(s: bytes | str) -> bytes: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/internal.pyi0000644000175100017510000000161015200142320016011 0ustar00runnerrunnerfrom mypy_extensions import u8 class ReadBuffer: def __init__(self, source: bytes) -> None: ... class WriteBuffer: def getvalue(self) -> bytes: ... def write_bool(data: WriteBuffer, value: bool, /) -> None: ... def read_bool(data: ReadBuffer, /) -> bool: ... def write_str(data: WriteBuffer, value: str, /) -> None: ... def read_str(data: ReadBuffer, /) -> str: ... def write_bytes(data: WriteBuffer, value: bytes, /) -> None: ... def read_bytes(data: ReadBuffer, /) -> bytes: ... def write_float(data: WriteBuffer, value: float, /) -> None: ... def read_float(data: ReadBuffer, /) -> float: ... def write_int(data: WriteBuffer, value: int, /) -> None: ... def read_int(data: ReadBuffer, /) -> int: ... def write_tag(data: WriteBuffer, value: u8, /) -> None: ... def read_tag(data: ReadBuffer, /) -> u8: ... def cache_version() -> u8: ... def extract_symbol(data: ReadBuffer, /) -> bytes: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/py.typed0000644000175100017510000000000015200142320015141 0ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/random.pyi0000644000175100017510000000117015200142320015456 0ustar00runnerrunnerfrom typing import final, overload from mypy_extensions import i64 def random() -> float: ... def randint(a: i64, b: i64) -> i64: ... @overload def randrange(stop: i64, /) -> i64: ... @overload def randrange(start: i64, stop: i64, /) -> i64: ... def seed(n: i64, /) -> None: ... @final class Random: def __init__(self, seed: i64 | None = None) -> None: ... def randint(self, a: i64, b: i64) -> i64: ... @overload def randrange(self, stop: i64, /) -> i64: ... @overload def randrange(self, start: i64, stop: i64, /) -> i64: ... def random(self) -> float: ... def seed(self, n: i64, /) -> None: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/strings.pyi0000644000175100017510000000336415200142320015676 0ustar00runnerrunnerfrom typing import final from mypy_extensions import i64, i32, i16, u8 @final class BytesWriter: def append(self, x: int, /) -> None: ... def write(self, b: bytes | bytearray, /) -> None: ... def getvalue(self) -> bytes: ... def truncate(self, size: i64, /) -> None: ... def __len__(self) -> i64: ... def __getitem__(self, i: i64, /) -> u8: ... def __setitem__(self, i: i64, x: u8, /) -> None: ... @final class StringWriter: def append(self, x: int, /) -> None: ... def write(self, s: str, /) -> None: ... def getvalue(self) -> str: ... def __len__(self) -> i64: ... def __getitem__(self, i: i64, /) -> i32: ... def write_i16_le(b: BytesWriter, n: i16, /) -> None: ... def write_i16_be(b: BytesWriter, n: i16, /) -> None: ... def read_i16_le(b: bytes, index: i64, /) -> i16: ... def read_i16_be(b: bytes, index: i64, /) -> i16: ... def write_i32_le(b: BytesWriter, n: i32, /) -> None: ... def write_i32_be(b: BytesWriter, n: i32, /) -> None: ... def read_i32_le(b: bytes, index: i64, /) -> i32: ... def read_i32_be(b: bytes, index: i64, /) -> i32: ... def write_i64_le(b: BytesWriter, n: i64, /) -> None: ... def write_i64_be(b: BytesWriter, n: i64, /) -> None: ... def read_i64_le(b: bytes, index: i64, /) -> i64: ... def read_i64_be(b: bytes, index: i64, /) -> i64: ... def write_f32_le(b: BytesWriter, n: float, /) -> None: ... def write_f32_be(b: BytesWriter, n: float, /) -> None: ... def read_f32_le(b: bytes, index: i64, /) -> float: ... def read_f32_be(b: bytes, index: i64, /) -> float: ... def write_f64_le(b: BytesWriter, n: float, /) -> None: ... def write_f64_be(b: BytesWriter, n: float, /) -> None: ... def read_f64_le(b: bytes, index: i64, /) -> float: ... def read_f64_be(b: bytes, index: i64, /) -> float: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/time.pyi0000644000175100017510000000003115200142320015127 0ustar00runnerrunnerdef time() -> float: ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/librt/vecs.pyi0000644000175100017510000000157715200142320015151 0ustar00runnerrunnerfrom typing import TypeVar, Generic, Iterable, Iterator, overload from mypy_extensions import i64 T = TypeVar("T") class vec(Generic[T]): @overload def __init__(self, *, capacity: i64 = ...) -> None: ... @overload def __init__(self, items: Iterable[T], /, *, capacity: i64 = ...) -> None: ... def __len__(self) -> i64: ... @overload def __getitem__(self, i: i64, /) -> T: ... @overload def __getitem__(self, i: slice, /) -> vec[T]: ... def __setitem__(self, i: i64, o: T, /) -> None: ... def __contains__(self, o: object, /) -> bool: ... def __iter__(self) -> Iterator[T]: ... def __buffer__(self, flags: int, /) -> memoryview: ... def append(v: vec[T], o: T, /) -> vec[T]: ... def remove(v: vec[T], o: T, /) -> vec[T]: ... def pop(v: vec[T], i: i64 = -1, /) -> tuple[vec[T], T]: ... def extend(v: vec[T], o: Iterable[T], /) -> vec[T]: ... ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8622737 librt-0.11.0/librt.egg-info/0000755000175100017510000000000015200142335015154 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435292.0 librt-0.11.0/librt.egg-info/PKG-INFO0000644000175100017510000000242215200142334016250 0ustar00runnerrunnerMetadata-Version: 2.4 Name: librt Version: 0.11.0 Summary: Mypyc runtime library Author-email: Jukka Lehtosalo , Ivan Levkivskyi License-Expression: MIT Project-URL: Homepage, https://github.com/mypyc/librt Project-URL: Issues, https://github.com/mypyc/mypyc/issues Classifier: Development Status :: 3 - Alpha Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 Classifier: Programming Language :: Python :: 3.11 Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: 3.13 Classifier: Programming Language :: Python :: 3.14 Classifier: Topic :: Software Development Classifier: Typing :: Typed Requires-Python: >=3.9 Description-Content-Type: text/x-rst License-File: LICENSE Dynamic: license-file Mypyc runtime library ===================== This library contains efficient C implementations of various Python standard library classes and functions. Mypyc can use these fast implementations when compiling Python code to native extension modules. Mypyc compiler is a part of `mypy distribution `__. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435292.0 librt-0.11.0/librt.egg-info/SOURCES.txt0000644000175100017510000001356215200142334017046 0ustar00runnerrunnerCPy.h LICENSE MANIFEST.in README.md build_setup.py bytearray_extra_ops.c bytearray_extra_ops.h bytes_extra_ops.c bytes_extra_ops.h bytes_ops.c byteswriter_extra_ops.c byteswriter_extra_ops.h dict_ops.c exc_ops.c float_ops.c function_wrapper.c generic_ops.c getargs.c getargsfast.c init.c int_ops.c list_ops.c misc_ops.c mypyc_util.h pyproject.toml pythoncapi_compat.h pythonsupport.c pythonsupport.h set_ops.c setup.py smoke_tests.py static_data.c static_data.h str_extra_ops.c str_extra_ops.h str_ops.c stringwriter_extra_ops.c stringwriter_extra_ops.h tuple_ops.c vecs_extra_ops.c vecs_extra_ops.h ./CPy.h ./bytearray_extra_ops.c ./bytearray_extra_ops.h ./bytes_extra_ops.c ./bytes_extra_ops.h ./bytes_ops.c ./byteswriter_extra_ops.c ./byteswriter_extra_ops.h ./dict_ops.c ./exc_ops.c ./float_ops.c ./function_wrapper.c ./generic_ops.c ./getargs.c ./getargsfast.c ./init.c ./int_ops.c ./list_ops.c ./misc_ops.c ./mypyc_util.h ./pythoncapi_compat.h ./pythonsupport.c ./pythonsupport.h ./set_ops.c ./static_data.c ./static_data.h ./str_extra_ops.c ./str_extra_ops.h ./str_ops.c ./stringwriter_extra_ops.c ./stringwriter_extra_ops.h ./tuple_ops.c ./vecs_extra_ops.c ./vecs_extra_ops.h ./base64/codec_choose.c ./base64/codecs.h ./base64/config.h ./base64/env.h ./base64/lib.c ./base64/lib_openmp.c ./base64/libbase64.h ./base64/librt_base64.c ./base64/librt_base64.h ./base64/librt_base64_api.c ./base64/librt_base64_api.h ./base64/arch/avx/codec.c ./base64/arch/avx/enc_loop_asm.c ./base64/arch/avx2/codec.c ./base64/arch/avx2/dec_loop.c ./base64/arch/avx2/dec_reshuffle.c ./base64/arch/avx2/enc_loop.c ./base64/arch/avx2/enc_loop_asm.c ./base64/arch/avx2/enc_reshuffle.c ./base64/arch/avx2/enc_translate.c ./base64/arch/avx512/codec.c ./base64/arch/avx512/enc_loop.c ./base64/arch/avx512/enc_reshuffle_translate.c ./base64/arch/generic/codec.c ./base64/arch/generic/dec_head.c ./base64/arch/generic/dec_tail.c ./base64/arch/generic/enc_head.c ./base64/arch/generic/enc_tail.c ./base64/arch/generic/32/dec_loop.c ./base64/arch/generic/32/enc_loop.c ./base64/arch/generic/64/enc_loop.c ./base64/arch/neon32/codec.c ./base64/arch/neon32/dec_loop.c ./base64/arch/neon32/enc_loop.c ./base64/arch/neon32/enc_reshuffle.c ./base64/arch/neon32/enc_translate.c ./base64/arch/neon64/codec.c ./base64/arch/neon64/dec_loop.c ./base64/arch/neon64/enc_loop.c ./base64/arch/neon64/enc_loop_asm.c ./base64/arch/neon64/enc_reshuffle.c ./base64/arch/sse41/codec.c ./base64/arch/sse42/codec.c ./base64/arch/ssse3/codec.c ./base64/arch/ssse3/dec_loop.c ./base64/arch/ssse3/dec_reshuffle.c ./base64/arch/ssse3/enc_loop.c ./base64/arch/ssse3/enc_loop_asm.c ./base64/arch/ssse3/enc_reshuffle.c ./base64/arch/ssse3/enc_translate.c ./base64/tables/table_dec_32bit.h ./base64/tables/table_enc_12bit.h ./base64/tables/tables.c ./base64/tables/tables.h ./internal/librt_internal.c ./internal/librt_internal.h ./internal/librt_internal_api.c ./internal/librt_internal_api.h ./random/librt_random.c ./random/librt_random.h ./random/librt_random_api.c ./random/librt_random_api.h ./strings/librt_strings.c ./strings/librt_strings.h ./strings/librt_strings_api.c ./strings/librt_strings_api.h ./strings/librt_strings_common.h ./time/librt_time.c ./time/librt_time.h ./time/librt_time_api.c ./time/librt_time_api.h ./vecs/librt_vecs.c ./vecs/librt_vecs.h ./vecs/librt_vecs_api.c ./vecs/librt_vecs_api.h ./vecs/vec_bool.c ./vecs/vec_float.c ./vecs/vec_i16.c ./vecs/vec_i32.c ./vecs/vec_i64.c ./vecs/vec_nested.c ./vecs/vec_t.c ./vecs/vec_template.c ./vecs/vec_u8.c ./vecs/vecs_internal.h base64/codec_choose.c base64/codecs.h base64/config.h base64/env.h base64/lib.c base64/lib_openmp.c base64/libbase64.h base64/librt_base64.c base64/librt_base64.h base64/librt_base64_api.c base64/librt_base64_api.h base64/arch/avx/codec.c base64/arch/avx/enc_loop_asm.c base64/arch/avx2/codec.c base64/arch/avx2/dec_loop.c base64/arch/avx2/dec_reshuffle.c base64/arch/avx2/enc_loop.c base64/arch/avx2/enc_loop_asm.c base64/arch/avx2/enc_reshuffle.c base64/arch/avx2/enc_translate.c base64/arch/avx512/codec.c base64/arch/avx512/enc_loop.c base64/arch/avx512/enc_reshuffle_translate.c base64/arch/generic/codec.c base64/arch/generic/dec_head.c base64/arch/generic/dec_tail.c base64/arch/generic/enc_head.c base64/arch/generic/enc_tail.c base64/arch/generic/32/dec_loop.c base64/arch/generic/32/enc_loop.c base64/arch/generic/64/enc_loop.c base64/arch/neon32/codec.c base64/arch/neon32/dec_loop.c base64/arch/neon32/enc_loop.c base64/arch/neon32/enc_reshuffle.c base64/arch/neon32/enc_translate.c base64/arch/neon64/codec.c base64/arch/neon64/dec_loop.c base64/arch/neon64/enc_loop.c base64/arch/neon64/enc_loop_asm.c base64/arch/neon64/enc_reshuffle.c base64/arch/sse41/codec.c base64/arch/sse42/codec.c base64/arch/ssse3/codec.c base64/arch/ssse3/dec_loop.c base64/arch/ssse3/dec_reshuffle.c base64/arch/ssse3/enc_loop.c base64/arch/ssse3/enc_loop_asm.c base64/arch/ssse3/enc_reshuffle.c base64/arch/ssse3/enc_translate.c base64/tables/table_dec_32bit.h base64/tables/table_enc_12bit.h base64/tables/tables.c base64/tables/tables.h internal/librt_internal.c internal/librt_internal.h internal/librt_internal_api.c internal/librt_internal_api.h librt/__init__.pyi librt/base64.pyi librt/internal.pyi librt/py.typed librt/random.pyi librt/strings.pyi librt/time.pyi librt/vecs.pyi librt.egg-info/PKG-INFO librt.egg-info/SOURCES.txt librt.egg-info/dependency_links.txt librt.egg-info/top_level.txt random/librt_random.c random/librt_random.h random/librt_random_api.c random/librt_random_api.h strings/librt_strings.c strings/librt_strings.h strings/librt_strings_api.c strings/librt_strings_api.h strings/librt_strings_common.h time/librt_time.c time/librt_time.h time/librt_time_api.c time/librt_time_api.h vecs/librt_vecs.c vecs/librt_vecs.h vecs/librt_vecs_api.c vecs/librt_vecs_api.h vecs/vec_bool.c vecs/vec_float.c vecs/vec_i16.c vecs/vec_i32.c vecs/vec_i64.c vecs/vec_nested.c vecs/vec_t.c vecs/vec_template.c vecs/vec_u8.c vecs/vecs_internal.h././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435292.0 librt-0.11.0/librt.egg-info/dependency_links.txt0000644000175100017510000000000115200142334021221 0ustar00runnerrunner ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435292.0 librt-0.11.0/librt.egg-info/top_level.txt0000644000175100017510000000000615200142334017701 0ustar00runnerrunnerlibrt ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/list_ops.c0000644000175100017510000002660115200142331014347 0ustar00runnerrunner// List primitive operations // // These are registered in mypyc.primitives.list_ops. #include #include "CPy.h" #ifndef Py_TPFLAGS_SEQUENCE #define Py_TPFLAGS_SEQUENCE (1 << 5) #endif PyObject *CPyList_Build(Py_ssize_t len, ...) { Py_ssize_t i; PyObject *res = PyList_New(len); if (res == NULL) { return NULL; } va_list args; va_start(args, len); for (i = 0; i < len; i++) { // Steals the reference PyObject *value = va_arg(args, PyObject *); PyList_SET_ITEM(res, i, value); } va_end(args); return res; } char CPyList_Clear(PyObject *list) { if (PyList_CheckExact(list)) { PyList_Clear(list); } else { PyObject *res = PyObject_CallMethodNoArgs(list, mypyc_interned_str.clear); if (res == NULL) { return 0; } Py_DECREF(res); } return 1; } PyObject *CPyList_Copy(PyObject *list) { if(PyList_CheckExact(list)) { return PyList_GetSlice(list, 0, PyList_GET_SIZE(list)); } return PyObject_CallMethodNoArgs(list, mypyc_interned_str.copy); } PyObject *CPyList_GetItemShort(PyObject *list, CPyTagged index) { Py_ssize_t n = CPyTagged_ShortAsSsize_t(index); Py_ssize_t size = PyList_GET_SIZE(list); if (n >= 0) { if (n >= size) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } else { n += size; if (n < 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } PyObject *result = PyList_GET_ITEM(list, n); Py_INCREF(result); return result; } PyObject *CPyList_GetItemShortBorrow(PyObject *list, CPyTagged index) { Py_ssize_t n = CPyTagged_ShortAsSsize_t(index); Py_ssize_t size = PyList_GET_SIZE(list); if (n >= 0) { if (n >= size) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } else { n += size; if (n < 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } return PyList_GET_ITEM(list, n); } PyObject *CPyList_GetItem(PyObject *list, CPyTagged index) { if (CPyTagged_CheckShort(index)) { Py_ssize_t n = CPyTagged_ShortAsSsize_t(index); Py_ssize_t size = PyList_GET_SIZE(list); if (n >= 0) { if (n >= size) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } else { n += size; if (n < 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } PyObject *result = PyList_GET_ITEM(list, n); Py_INCREF(result); return result; } else { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return NULL; } } PyObject *CPyList_GetItemBorrow(PyObject *list, CPyTagged index) { if (CPyTagged_CheckShort(index)) { Py_ssize_t n = CPyTagged_ShortAsSsize_t(index); Py_ssize_t size = PyList_GET_SIZE(list); if (n >= 0) { if (n >= size) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } else { n += size; if (n < 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } } return PyList_GET_ITEM(list, n); } else { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return NULL; } } PyObject *CPyList_GetItemInt64(PyObject *list, int64_t index) { size_t size = PyList_GET_SIZE(list); if (likely((uint64_t)index < size)) { PyObject *result = PyList_GET_ITEM(list, index); Py_INCREF(result); return result; } if (index >= 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } index += size; if (index < 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } PyObject *result = PyList_GET_ITEM(list, index); Py_INCREF(result); return result; } PyObject *CPyList_GetItemInt64Borrow(PyObject *list, int64_t index) { size_t size = PyList_GET_SIZE(list); if (likely((uint64_t)index < size)) { return PyList_GET_ITEM(list, index); } if (index >= 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } index += size; if (index < 0) { PyErr_SetString(PyExc_IndexError, "list index out of range"); return NULL; } return PyList_GET_ITEM(list, index); } bool CPyList_SetItem(PyObject *list, CPyTagged index, PyObject *value) { if (CPyTagged_CheckShort(index)) { Py_ssize_t n = CPyTagged_ShortAsSsize_t(index); Py_ssize_t size = PyList_GET_SIZE(list); if (n >= 0) { if (n >= size) { PyErr_SetString(PyExc_IndexError, "list assignment index out of range"); return false; } } else { n += size; if (n < 0) { PyErr_SetString(PyExc_IndexError, "list assignment index out of range"); return false; } } // PyList_SET_ITEM doesn't decref the old element, so we do Py_DECREF(PyList_GET_ITEM(list, n)); // N.B: Steals reference PyList_SET_ITEM(list, n, value); return true; } else { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return false; } } bool CPyList_SetItemInt64(PyObject *list, int64_t index, PyObject *value) { size_t size = PyList_GET_SIZE(list); if (unlikely((uint64_t)index >= size)) { if (index > 0) { PyErr_SetString(PyExc_IndexError, "list assignment index out of range"); return false; } index += size; if (index < 0) { PyErr_SetString(PyExc_IndexError, "list assignment index out of range"); return false; } } // PyList_SET_ITEM doesn't decref the old element, so we do Py_DECREF(PyList_GET_ITEM(list, index)); // N.B: Steals reference PyList_SET_ITEM(list, index, value); return true; } // This function should only be used to fill in brand new lists. void CPyList_SetItemUnsafe(PyObject *list, Py_ssize_t index, PyObject *value) { PyList_SET_ITEM(list, index, value); } #ifdef Py_GIL_DISABLED // The original optimized list.pop implementation doesn't work on free-threaded // builds, so provide an alternative that is a bit slower but works. // // Note that this implementation isn't intended to be atomic. static inline PyObject *list_pop_index(PyObject *list, Py_ssize_t index) { PyObject *item = PyList_GetItemRef(list, index); if (item == NULL) { return NULL; } if (PySequence_DelItem(list, index) < 0) { Py_DECREF(item); return NULL; } return item; } #endif PyObject *CPyList_PopLast(PyObject *list) { #ifdef Py_GIL_DISABLED // The other implementation causes segfaults on a free-threaded Python 3.14b4 build. Py_ssize_t index = PyList_GET_SIZE(list) - 1; return list_pop_index(list, index); #else // 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 *)list, -1); #endif } PyObject *CPyList_Pop(PyObject *obj, CPyTagged index) { if (CPyTagged_CheckShort(index)) { Py_ssize_t n = CPyTagged_ShortAsSsize_t(index); #ifdef Py_GIL_DISABLED // We must use a slower implementation on free-threaded builds. if (n < 0) { n += PyList_GET_SIZE(obj); } return list_pop_index(obj, n); #else return list_pop_impl((PyListObject *)obj, n); #endif } 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) { if (PyList_Extend(o1, o2) < 0) { return NULL; } Py_RETURN_NONE; } // 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_Sort(PyObject *seq) { PyObject *newlist = PySequence_List(seq); if (newlist == NULL) return NULL; int res = PyList_Sort(newlist); if (res < 0) { Py_DECREF(newlist); return NULL; } return newlist; } 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 *CPySequence_InPlaceMultiply(PyObject *seq, CPyTagged t_size) { Py_ssize_t size = CPyTagged_AsSsize_t(t_size); if (size == -1 && PyErr_Occurred()) { return NULL; } return PySequence_InPlaceRepeat(seq, size); } PyObject *CPyList_GetSlice(PyObject *obj, CPyTagged start, CPyTagged end) { if (likely(PyList_CheckExact(obj) && CPyTagged_CheckShort(start) && CPyTagged_CheckShort(end))) { Py_ssize_t startn = CPyTagged_ShortAsSsize_t(start); Py_ssize_t endn = CPyTagged_ShortAsSsize_t(end); if (startn < 0) { startn += PyList_GET_SIZE(obj); } if (endn < 0) { endn += PyList_GET_SIZE(obj); } return PyList_GetSlice(obj, startn, endn); } return CPyObject_GetSlice(obj, start, end); } int CPySequence_Check(PyObject *obj) { return Py_TYPE(obj)->tp_flags & Py_TPFLAGS_SEQUENCE; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/misc_ops.c0000644000175100017510000015154715200142331014337 0ustar00runnerrunner#include "pythoncapi_compat.h" // Misc primitive operations + C helpers // // These are registered in mypyc.primitives.misc_ops. #include #include #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.) if (Py_IsNone(val)) { return CPyIter_Next(iter); } else { return PyObject_CallMethodOneArg(iter, mypyc_interned_str.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) { PyObject *exc_type = (PyObject *)Py_TYPE(CPy_ExcState()->exc_value); PyObject *type, *value, *traceback; PyObject *_m; PyObject *res; *outp = NULL; if (PyErr_GivenExceptionMatches(exc_type, PyExc_GeneratorExit)) { _m = PyObject_GetAttr(iter, mypyc_interned_str.close_); if (_m) { res = PyObject_CallNoArgs(_m); Py_DECREF(_m); if (!res) return 2; Py_DECREF(res); } else if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); } else { return 2; } } else { _m = PyObject_GetAttr(iter, mypyc_interned_str.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 { return 2; } } } 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_GetAttr((PyObject *)metaclass, mypyc_interned_str.__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; } #if CPY_3_13_FEATURES // Adapted from CPython 3.13.0b3 /* Determine the most derived metatype. */ PyObject *CPy_CalculateMetaclass(PyObject *metatype, PyObject *bases) { Py_ssize_t i, nbases; PyTypeObject *winner; PyObject *tmp; PyTypeObject *tmptype; /* Determine the proper metatype to deal with this, and check for metatype conflicts while we're at it. Note that if some other metatype wins to contract, it's possible that its instances are not types. */ nbases = PyTuple_GET_SIZE(bases); winner = (PyTypeObject *)metatype; for (i = 0; i < nbases; i++) { tmp = PyTuple_GET_ITEM(bases, i); tmptype = Py_TYPE(tmp); if (PyType_IsSubtype(winner, tmptype)) continue; if (PyType_IsSubtype(tmptype, winner)) { winner = tmptype; continue; } /* else: */ PyErr_SetString(PyExc_TypeError, "metaclass conflict: " "the metaclass of a derived class " "must be a (non-strict) subclass " "of the metaclasses of all its bases"); return NULL; } return (PyObject *)winner; } #else PyObject *CPy_CalculateMetaclass(PyObject *metatype, PyObject *bases) { return (PyObject *)_PyType_CalculateMetaclass((PyTypeObject *)metatype, bases); } #endif // 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 = (PyTypeObject *)CPy_CalculateMetaclass((PyObject *)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 (template_->tp_doc) { // cpython expects tp_doc to be heap-allocated so convert it here to // avoid segfaults on deallocation. Py_ssize_t size = strlen(template_->tp_doc) + 1; char *doc = (char *)PyMem_Malloc(size); if (!doc) goto error; memcpy(doc, template_->tp_doc, size); template_->tp_doc = doc; } // 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_SetAttr((PyObject *)t, mypyc_interned_str.__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_GetAttr((PyObject *)t, mypyc_interned_str.__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_SetAttr((PyObject *)t, mypyc_interned_str.__module__, modname) < 0) goto error; Py_XDECREF(dummy_class); // Unlike the tp_doc slots of most other object, a heap type's tp_doc // must be heap allocated. if (template_->tp_doc) { // Silently truncate the docstring if it contains a null byte Py_ssize_t size = strlen(template_->tp_doc) + 1; char *tp_doc = (char *)PyMem_Malloc(size); if (tp_doc == NULL) { PyErr_NoMemory(); goto error; } memcpy(tp_doc, template_->tp_doc, size); t->ht_type.tp_doc = tp_doc; } #if PY_MINOR_VERSION == 11 // This is a hack. Python 3.11 doesn't include good public APIs to work with managed // dicts, which are the default for heap types. So we try to opt-out until Python 3.12. t->ht_type.tp_flags &= ~Py_TPFLAGS_MANAGED_DICT; #endif return (PyObject *)t; error: Py_XDECREF(t); Py_XDECREF(bases); Py_XDECREF(dummy_class); Py_XDECREF(name); return NULL; } // Call __init_subclass__ on the appropriate base class of type. // This is separated from CPyType_FromTemplate so that class attributes // can be set before __init_subclass__ is called. bool CPy_InitSubclass(PyObject *type) { if (init_subclass((PyTypeObject *)type, NULL)) { return false; } return true; } 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 * dataclass_type: A str object with the return value of util.py:dataclass_type() */ int CPyDataclass_SleightOfHand(PyObject *dataclass_dec, PyObject *tp, PyObject *dict, PyObject *annotations, PyObject *dataclass_type) { PyTypeObject *ttp = (PyTypeObject *)tp; Py_ssize_t pos; PyObject *res = NULL; /* 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)) { // Check and delete key. Key may be absent from tp for InitVar variables. if (PyObject_HasAttr(tp, key) == 1 && 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_CallOneArg(dataclass_dec, tp); if (!res) { goto fail; } const char *dataclass_type_ptr = PyUnicode_AsUTF8(dataclass_type); if (dataclass_type_ptr == NULL) { goto fail; } if (strcmp(dataclass_type_ptr, "attr") == 0 || strcmp(dataclass_type_ptr, "attr-auto") == 0) { // These attributes are added or modified by @attr.s(slots=True). const char * const keys[] = {"__attrs_attrs__", "__attrs_own_setattr__", "__init__", ""}; for (const char * const *key_iter = keys; **key_iter != '\0'; key_iter++) { PyObject *value = NULL; int rv = PyObject_GetOptionalAttrString(res, *key_iter, &value); if (rv == 1) { PyObject_SetAttrString(tp, *key_iter, value); Py_DECREF(value); } else if (rv == -1) { goto fail; } } } /* Copy back the original contents of the dict */ if (_CPy_UpdateObjFromDict(tp, orig_dict) != 0) { goto fail; } Py_DECREF(res); Py_DECREF(orig_dict); return 1; fail: Py_XDECREF(res); 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_GetAttr((PyObject *)Py_TYPE(obj), mypyc_interned_str.__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_FromVoidPtr(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)); } } static PyObject *CPyTagged_ShortToAsciiBytes(Py_ssize_t n) { PyObject *obj = PyBytes_FromStringAndSize(NULL, MAX_INT_CHARS); if (!obj) return NULL; int len = fmt_ssize_t(PyBytes_AsString(obj), n); Py_SET_SIZE(obj, len); return obj; } PyObject *CPyTagged_AsciiBytes(CPyTagged n) { if (CPyTagged_CheckShort(n)) { return CPyTagged_ShortToAsciiBytes(CPyTagged_ShortAsSsize_t(n)); } PyObject *str = PyObject_Str(CPyTagged_AsObject(n)); PyObject *bytes = PyUnicode_AsASCIIString(str); CPy_DECREF(str); return bytes; } void CPyDebug_Print(const char *msg) { printf("%s\n", msg); fflush(stdout); } void CPyDebug_PrintObject(PyObject *obj) { // Printing can cause errors. We don't want this to affect any existing // state so we'll save any existing error and restore it at the end. PyObject *exc_type, *exc_value, *exc_traceback; PyErr_Fetch(&exc_type, &exc_value, &exc_traceback); if (PyObject_Print(obj, stderr, 0) == -1) { PyErr_Print(); } else { fprintf(stderr, "\n"); } fflush(stderr); PyErr_Restore(exc_type, exc_value, exc_traceback); } 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, const int *frozensets) { 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_DecodeUTF8(data, len, "surrogatepass"); 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; } } if (frozensets) { int num = *frozensets++; while (num-- > 0) { int num_items = *frozensets++; PyObject *obj = PyFrozenSet_New(NULL); if (obj == NULL) { return -1; } for (int i = 0; i < num_items; i++) { PyObject *item = statics[*frozensets++]; Py_INCREF(item); if (PySet_Add(obj, item) == -1) { return -1; } } *result++ = obj; } } return 0; } // Call super(type(self), self) PyObject * CPy_Super(PyObject *builtins, PyObject *self) { PyObject *super_type = PyObject_GetAttr(builtins, mypyc_interned_str.super); if (!super_type) return NULL; PyObject *result = PyObject_CallFunctionObjArgs( super_type, (PyObject*)Py_TYPE(self), self, NULL); Py_DECREF(super_type); return result; } static bool import_single(PyObject *mod_id, PyObject **mod_static, PyObject *globals_id, PyObject *globals_name, PyObject *globals) { if (Py_IsNone(*mod_static)) { CPyModule *mod = PyImport_Import(mod_id); if (mod == NULL) { return false; } *mod_static = mod; } PyObject *mod_dict = PyImport_GetModuleDict(); CPyModule *globals_mod = CPyDict_GetItem(mod_dict, globals_id); if (globals_mod == NULL) { return false; } int ret = CPyDict_SetItem(globals, globals_name, globals_mod); Py_DECREF(globals_mod); if (ret < 0) { return false; } return true; } // Table-driven import helper. See transform_import() in irbuild for the details. bool CPyImport_ImportMany(PyObject *modules, CPyModule **statics[], PyObject *globals, PyObject *tb_path, PyObject *tb_function, Py_ssize_t *tb_lines) { for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(modules); i++) { PyObject *module = PyTuple_GET_ITEM(modules, i); PyObject *mod_id = PyTuple_GET_ITEM(module, 0); PyObject *globals_id = PyTuple_GET_ITEM(module, 1); PyObject *globals_name = PyTuple_GET_ITEM(module, 2); if (!import_single(mod_id, statics[i], globals_id, globals_name, globals)) { assert(PyErr_Occurred() && "error indicator should be set on bad import!"); PyObject *typ, *val, *tb; PyErr_Fetch(&typ, &val, &tb); const char *path = PyUnicode_AsUTF8(tb_path); if (path == NULL) { path = ""; } const char *function = PyUnicode_AsUTF8(tb_function); if (function == NULL) { function = ""; } PyErr_Restore(typ, val, tb); CPy_AddTraceback(path, function, tb_lines[i], globals); return false; } } return true; } // This helper function is a simplification of cpython/ceval.c/import_from() static 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) { // Attribute lookup failed. The name may still be a submodule that's // been imported already; look it up directly in sys.modules. PyObject *fullmodname = PyUnicode_FromFormat("%U.%U", package_name, import_name); if (fullmodname == NULL) { goto fail; } PyErr_Clear(); x = PyImport_GetModule(fullmodname); Py_DECREF(fullmodname); if (x == NULL) { goto fail; } } return x; fail: PyErr_Clear(); PyObject *package_path = PyModule_GetFilenameObject(module); PyObject *path_for_msg = package_path != NULL ? package_path : Py_None; PyObject *errmsg = PyUnicode_FromFormat("cannot import name %R from %R (%S)", import_name, package_name, path_for_msg); // NULL checks for errmsg and package_name done by PyErr_SetImportError. PyErr_SetImportError(errmsg, package_name, package_path); Py_XDECREF(package_path); Py_XDECREF(errmsg); return NULL; } PyObject *CPyImport_ImportFromMany(PyObject *mod_id, PyObject *names, PyObject *as_names, PyObject *globals) { PyObject *mod = PyImport_ImportModuleLevelObject(mod_id, globals, 0, names, 0); if (mod == NULL) { return NULL; } for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(names); i++) { PyObject *name = PyTuple_GET_ITEM(names, i); PyObject *as_name = PyTuple_GET_ITEM(as_names, i); PyObject *obj = CPyImport_ImportFrom(mod, mod_id, name, as_name); if (obj == NULL) { Py_DECREF(mod); return NULL; } int ret = CPyDict_SetItem(globals, as_name, obj); Py_DECREF(obj); if (ret < 0) { Py_DECREF(mod); return NULL; } } return mod; } // Import attributes from an already-imported native module and store them // in the globals dict. Returns the module on success, NULL on error. PyObject *CPyImport_GetNativeAttrs(PyObject *mod_id, PyObject *names, PyObject *as_names, PyObject *globals) { PyObject *mod = PyImport_GetModule(mod_id); if (mod == NULL) { if (!PyErr_Occurred()) { PyErr_Format(PyExc_ImportError, "module '%U' is not in sys.modules", mod_id); } return NULL; } for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(names); i++) { PyObject *name = PyTuple_GET_ITEM(names, i); PyObject *as_name = PyTuple_GET_ITEM(as_names, i); PyObject *obj = PyObject_GetAttr(mod, name); if (obj == NULL) { Py_DECREF(mod); return NULL; } int ret = CPyDict_SetItem(globals, as_name, obj); Py_DECREF(obj); if (ret < 0) { Py_DECREF(mod); return NULL; } } return mod; } // 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, PyObject *method) { // Look up reverse method PyObject *m = PyObject_GetAttr(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_GetAttr(singledispatch_func, mypyc_interned_str.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_GetAttr(singledispatch_func, mypyc_interned_str.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_GetAttr(typing, mypyc_interned_str.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_GetAttr(singledispatch_func, mypyc_interned_str.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; } // Adapted from ceval.c GET_AITER PyObject *CPy_GetAIter(PyObject *obj) { unaryfunc getter = NULL; PyTypeObject *type = Py_TYPE(obj); if (type->tp_as_async != NULL) { getter = type->tp_as_async->am_aiter; } if (getter == NULL) { PyErr_Format(PyExc_TypeError, "'async for' requires an object with " "__aiter__ method, got %.100s", type->tp_name); Py_DECREF(obj); return NULL; } PyObject *iter = (*getter)(obj); if (!iter) { return NULL; } if (Py_TYPE(iter)->tp_as_async == NULL || Py_TYPE(iter)->tp_as_async->am_anext == NULL) { PyErr_Format(PyExc_TypeError, "'async for' received an object from __aiter__ " "that does not implement __anext__: %.100s", Py_TYPE(iter)->tp_name); Py_DECREF(iter); return NULL; } return iter; } // Adapted from ceval.c GET_ANEXT PyObject *CPy_GetANext(PyObject *aiter) { unaryfunc getter = NULL; PyObject *next_iter = NULL; PyObject *awaitable = NULL; PyTypeObject *type = Py_TYPE(aiter); if (PyAsyncGen_CheckExact(aiter)) { awaitable = type->tp_as_async->am_anext(aiter); if (awaitable == NULL) { goto error; } } else { if (type->tp_as_async != NULL){ getter = type->tp_as_async->am_anext; } if (getter != NULL) { next_iter = (*getter)(aiter); if (next_iter == NULL) { goto error; } } else { PyErr_Format(PyExc_TypeError, "'async for' requires an iterator with " "__anext__ method, got %.100s", type->tp_name); goto error; } awaitable = CPyCoro_GetAwaitableIter(next_iter); if (awaitable == NULL) { _PyErr_FormatFromCause( PyExc_TypeError, "'async for' received an invalid object " "from __anext__: %.100s", Py_TYPE(next_iter)->tp_name); Py_DECREF(next_iter); goto error; } else { Py_DECREF(next_iter); } } return awaitable; error: return NULL; } #if CPY_3_11_FEATURES // Return obj.__name__ (specialized to type objects, which are the most common target). PyObject *CPy_GetName(PyObject *obj) { if (PyType_Check(obj)) { return PyType_GetName((PyTypeObject *)obj); } return PyObject_GetAttr(obj, mypyc_interned_str.__name__); } #endif #ifdef MYPYC_LOG_TRACE // This is only compiled in if trace logging is enabled by user static int TraceCounter = 0; static const int TRACE_EVERY_NTH = 1009; // Should be a prime number #define TRACE_LOG_FILE_NAME "mypyc_trace.txt" static FILE *TraceLogFile = NULL; // Log a tracing event on every Nth call void CPyTrace_LogEvent(const char *location, const char *line, const char *op, const char *details) { if (TraceLogFile == NULL) { if ((TraceLogFile = fopen(TRACE_LOG_FILE_NAME, "w")) == NULL) { fprintf(stderr, "error: Could not open trace file %s\n", TRACE_LOG_FILE_NAME); abort(); } } if (TraceCounter == 0) { fprintf(TraceLogFile, "%s:%s:%s:%s\n", location, line, op, details); } TraceCounter++; if (TraceCounter == TRACE_EVERY_NTH) { TraceCounter = 0; } } #endif #if CPY_3_12_FEATURES // Copied from Python 3.12.3, since this struct is internal to CPython. It defines // the structure of typing.TypeAliasType objects. We need it since compute_value is // not part of the public API, and we need to set it to match Python runtime semantics. // // IMPORTANT: This needs to be kept in sync with CPython! typedef struct { PyObject_HEAD PyObject *name; #if CPY_3_15_FEATURES PyObject *qualname; #endif PyObject *type_params; PyObject *compute_value; PyObject *value; PyObject *module; } typealiasobject; void CPy_SetTypeAliasTypeComputeFunction(PyObject *alias, PyObject *compute_value) { typealiasobject *obj = (typealiasobject *)alias; if (obj->value != NULL) { Py_DECREF(obj->value); } obj->value = NULL; Py_INCREF(compute_value); if (obj->compute_value != NULL) { Py_DECREF(obj->compute_value); } obj->compute_value = compute_value; } #endif #ifdef _WIN32 #define SEP "\\" #else #define SEP "/" #endif // Cached class references for __spec__ / __loader__ construction. static PyObject *CPyImport_ModuleSpecClass = NULL; static PyObject *CPyImport_ExtFileLoaderClass = NULL; static PyObject *CPyImport_SpecKwnames = NULL; // ("origin", "is_package") // Initialize cached references for ModuleSpec and ExtensionFileLoader. // Returns 0 on success, -1 on error. static int CPyImport_InitSpecClasses(void) { if (CPyImport_ModuleSpecClass != NULL) { return 0; } PyObject *machinery = PyImport_ImportModule("importlib.machinery"); if (machinery == NULL) { return -1; } CPyImport_ModuleSpecClass = PyObject_GetAttrString(machinery, "ModuleSpec"); CPyImport_ExtFileLoaderClass = PyObject_GetAttrString(machinery, "ExtensionFileLoader"); Py_DECREF(machinery); if (CPyImport_ModuleSpecClass == NULL || CPyImport_ExtFileLoaderClass == NULL) { Py_CLEAR(CPyImport_ModuleSpecClass); Py_CLEAR(CPyImport_ExtFileLoaderClass); return -1; } PyObject *origin_str = PyUnicode_InternFromString("origin"); PyObject *is_package_str = PyUnicode_InternFromString("is_package"); if (origin_str == NULL || is_package_str == NULL) { CPyError_OutOfMemory(); } CPyImport_SpecKwnames = PyTuple_Pack(2, origin_str, is_package_str); Py_DECREF(origin_str); Py_DECREF(is_package_str); if (CPyImport_SpecKwnames == NULL) { CPyError_OutOfMemory(); } return 0; } // Set __package__ before executing the module body so it is available // during module initialization. For a package, __package__ is the module // name itself. For a non-package submodule "a.b.c", it is "a.b". For a // top-level non-package module, it is "". static int CPyImport_SetModulePackage(PyObject *modobj, PyObject *module_name, Py_ssize_t is_package) { PyObject *pkg = NULL; int rc = PyObject_GetOptionalAttrString(modobj, "__package__", &pkg); if (rc < 0) { return -1; } if (pkg != NULL && pkg != Py_None) { Py_DECREF(pkg); return 0; } Py_XDECREF(pkg); PyObject *package_name = NULL; if (is_package) { package_name = module_name; Py_INCREF(package_name); } else { Py_ssize_t name_len = PyUnicode_GetLength(module_name); if (name_len < 0) { return -1; } Py_ssize_t dot = PyUnicode_FindChar(module_name, '.', 0, name_len, -1); if (dot >= 0) { package_name = PyUnicode_Substring(module_name, 0, dot); } else { package_name = PyUnicode_FromString(""); } } if (package_name == NULL) { return -1; } rc = PyObject_SetAttrString(modobj, "__package__", package_name); Py_DECREF(package_name); return rc; } // Derive and set __file__ on modobj from the shared library path, module name, // and extension suffix. Returns 0 on success, -1 on error. static int CPyImport_SetModuleFile(PyObject *modobj, PyObject *module_name, PyObject *shared_lib_file, PyObject *ext_suffix, Py_ssize_t is_package) { PyObject *file = NULL; int rc = PyObject_GetOptionalAttrString(modobj, "__file__", &file); if (rc < 0) { return -1; } if (file != NULL) { // __file__ already set, nothing to do. Py_DECREF(file); return 0; } // Derive __file__ from the shared lib's directory, the module // name, and the extension suffix. Two layouts: // // Monolithic: one shared lib above the package tree holds many // modules, so append the full dotted module path. // separate=True: each module has its own "__mypyc.so" // next to the module, so dirname(shared_lib) is already inside // the parent package. Append only the last segment. // // Detect the separate=True case by matching the shared lib's // basename against "__mypyc". PyObject *derived_file = NULL; if (shared_lib_file != NULL && shared_lib_file != Py_None && PyUnicode_Check(shared_lib_file)) { Py_ssize_t sf_len = PyUnicode_GetLength(shared_lib_file); // Find the last path separator, checking both '/' and '\\' // for cross-platform support. Py_ssize_t sep = PyUnicode_FindChar(shared_lib_file, '/', 0, sf_len, -1); Py_ssize_t bsep = PyUnicode_FindChar(shared_lib_file, '\\', 0, sf_len, -1); if (bsep > sep) { sep = bsep; } // Use the same separator character found in the path, or // the platform default if no separator was found. Py_UCS4 sep_char = sep >= 0 ? PyUnicode_ReadChar(shared_lib_file, sep) : (Py_UCS4)SEP[0]; PyObject *dot_str = PyUnicode_FromString("."); PyObject *sep_str = PyUnicode_FromOrdinal(sep_char); if (dot_str == NULL || sep_str == NULL) { CPyError_OutOfMemory(); } PyObject *module_path = PyUnicode_Replace(module_name, dot_str, sep_str, -1); Py_DECREF(dot_str); Py_DECREF(sep_str); if (module_path == NULL) { return -1; } // Compute the module's last dotted segment for the separate=True check. Py_ssize_t name_len = PyUnicode_GetLength(module_name); Py_ssize_t last_dot = PyUnicode_FindChar(module_name, '.', 0, name_len, -1); PyObject *last_segment; if (last_dot >= 0) { last_segment = PyUnicode_Substring(module_name, last_dot + 1, name_len); } else { last_segment = module_name; Py_INCREF(last_segment); } if (last_segment == NULL) { Py_DECREF(module_path); return -1; } // Compare shared_lib_file basename against "__mypyc". PyObject *expected_basename = PyUnicode_FromFormat( "%U__mypyc%U", last_segment, ext_suffix); PyObject *actual_basename; if (sep >= 0) { actual_basename = PyUnicode_Substring(shared_lib_file, sep + 1, sf_len); } else { actual_basename = shared_lib_file; Py_INCREF(actual_basename); } int is_per_module_lib = 0; if (expected_basename != NULL && actual_basename != NULL) { is_per_module_lib = (PyUnicode_Compare(expected_basename, actual_basename) == 0); } Py_XDECREF(expected_basename); Py_XDECREF(actual_basename); // For packages, __file__ should point to __init__, // e.g. "a/b/__init__.cpython-312-x86_64-linux-gnu.so". PyObject *file_path = is_per_module_lib ? last_segment : module_path; if (sep >= 0) { PyObject *dir = PyUnicode_Substring(shared_lib_file, 0, sep); if (dir != NULL) { if (is_package) { derived_file = PyUnicode_FromFormat( "%U%c%U%c__init__%U", dir, (int)sep_char, file_path, (int)sep_char, ext_suffix); } else { derived_file = PyUnicode_FromFormat( "%U%c%U%U", dir, (int)sep_char, file_path, ext_suffix); } Py_DECREF(dir); } } else { if (is_package) { derived_file = PyUnicode_FromFormat( "%U%c__init__%U", file_path, (int)SEP[0], ext_suffix); } else { derived_file = PyUnicode_FromFormat("%U%U", file_path, ext_suffix); } } Py_DECREF(last_segment); Py_DECREF(module_path); } if (derived_file == NULL && !PyErr_Occurred()) { derived_file = module_name; Py_INCREF(derived_file); } if (derived_file == NULL || PyObject_SetAttrString(modobj, "__file__", derived_file) < 0) { Py_XDECREF(derived_file); return -1; } Py_DECREF(derived_file); return 0; } // Set __path__ to [dirname(__file__)] on a package module if not already set. // Returns 0 on success, -1 on error. static int CPyImport_SetModulePath(PyObject *modobj) { PyObject *existing_path = NULL; int rc = PyObject_GetOptionalAttrString(modobj, "__path__", &existing_path); if (rc < 0) { return -1; } if (existing_path != NULL) { Py_DECREF(existing_path); return 0; } PyObject *file = NULL; rc = PyObject_GetOptionalAttrString(modobj, "__file__", &file); if (rc <= 0) { return rc; } PyObject *os_path = PyImport_ImportModule("os.path"); if (os_path == NULL) { Py_DECREF(file); return -1; } PyObject *dir = PyObject_CallMethod(os_path, "dirname", "O", file); Py_DECREF(os_path); Py_DECREF(file); if (dir == NULL) { return -1; } PyObject *path_list = PyList_New(1); if (path_list == NULL) { CPyError_OutOfMemory(); } PyList_SET_ITEM(path_list, 0, dir); // steals ref to dir int ret = PyObject_SetAttrString(modobj, "__path__", path_list); Py_DECREF(path_list); return ret; } // Set __spec__ and __loader__ on modobj if not already set. // Returns 0 on success, -1 on error. static int CPyImport_SetModuleSpec(PyObject *modobj, PyObject *module_name, Py_ssize_t is_package) { PyObject *spec = NULL; int rc = PyObject_GetOptionalAttrString(modobj, "__spec__", &spec); if (rc < 0) { return -1; } if (spec != NULL && spec != Py_None) { // __spec__ already set. Py_DECREF(spec); return 0; } Py_XDECREF(spec); if (CPyImport_InitSpecClasses() < 0) { return -1; } PyObject *file = NULL; if (PyObject_GetOptionalAttrString(modobj, "__file__", &file) < 0) { return -1; } if (file == NULL) { file = Py_None; Py_INCREF(file); } // ExtensionFileLoader(name, path) PyObject *loader = PyObject_CallFunctionObjArgs( CPyImport_ExtFileLoaderClass, module_name, file, NULL); if (loader == NULL) { Py_DECREF(file); return -1; } // ModuleSpec(name, loader, *, origin=file, is_package=is_package) PyObject *is_pkg_obj = is_package ? Py_True : Py_False; PyObject *spec_args[] = {NULL, module_name, loader, file, is_pkg_obj}; spec = PyObject_Vectorcall( CPyImport_ModuleSpecClass, spec_args + 1, 2 | PY_VECTORCALL_ARGUMENTS_OFFSET, CPyImport_SpecKwnames); Py_DECREF(file); if (spec == NULL) { Py_DECREF(loader); return -1; } if (is_package) { // Set submodule_search_locations from __path__ PyObject *path = NULL; if (PyObject_GetOptionalAttrString(modobj, "__path__", &path) < 0) { Py_DECREF(spec); Py_DECREF(loader); return -1; } if (path != NULL) { if (PyObject_SetAttrString(spec, "submodule_search_locations", path) < 0) { Py_DECREF(path); Py_DECREF(spec); Py_DECREF(loader); return -1; } Py_DECREF(path); } } if (PyObject_SetAttrString(modobj, "__spec__", spec) < 0 || PyObject_SetAttrString(modobj, "__loader__", loader) < 0) { Py_DECREF(spec); Py_DECREF(loader); return -1; } Py_DECREF(spec); Py_DECREF(loader); return 0; } PyObject *CPyImport_ImportNative(PyObject *module_name, PyObject *(*init_only_fn)(void), int (*exec_fn)(PyObject *), CPyModule **module_static, PyObject *shared_lib_file, PyObject *ext_suffix, Py_ssize_t is_package) { PyObject *parent_module = NULL; PyObject *child_name = NULL; PyObject *exc_type, *exc_val, *exc_tb; Py_ssize_t name_len = PyUnicode_GetLength(module_name); if (name_len < 0) { return NULL; } Py_ssize_t dot = PyUnicode_FindChar(module_name, '.', 0, name_len, -1); if (dot >= 0) { // Import the parent package first to preserve import ordering semantics. PyObject *parent_name = PyUnicode_Substring(module_name, 0, dot); if (parent_name == NULL) { CPyError_OutOfMemory(); } child_name = PyUnicode_Substring(module_name, dot + 1, name_len); if (child_name == NULL) { CPyError_OutOfMemory(); } parent_module = PyImport_Import(parent_name); Py_DECREF(parent_name); if (parent_module == NULL) { Py_DECREF(child_name); return NULL; } } // Create the module object without executing the module body. // CPyInitOnly_* uses an internal static to cache the module object. // We then check sys.modules to determine whether the module body // has already been executed (or is being executed in a circular import). PyObject *module_dict = PyImport_GetModuleDict(); if (module_dict == NULL) { Py_XDECREF(parent_module); Py_XDECREF(child_name); return NULL; } PyObject *existing = PyDict_GetItemWithError(module_dict, module_name); if (existing != NULL) { if (*module_static != NULL) { if (existing == (PyObject *)*module_static) { Py_INCREF(existing); Py_XDECREF(parent_module); Py_XDECREF(child_name); return existing; } PyErr_Format(PyExc_ImportError, "native module '%U' in sys.modules was replaced after initialization", module_name); Py_XDECREF(parent_module); Py_XDECREF(child_name); return NULL; } } if (PyErr_Occurred()) { Py_XDECREF(parent_module); Py_XDECREF(child_name); return NULL; } PyObject *modobj = init_only_fn(); if (modobj == NULL) { Py_XDECREF(parent_module); Py_XDECREF(child_name); return NULL; } if (PyObject_SetItem(module_dict, module_name, modobj) < 0) { goto fail; } if (*module_static != (CPyModule *)modobj) { PyErr_Format(PyExc_ImportError, "native module '%U' was initialized inconsistently", module_name); goto fail; } if (CPyImport_SetDunderAttrs(modobj, module_name, shared_lib_file, ext_suffix, is_package) < 0) { goto fail; } // Now execute the module body, with __file__ and __package__ already set. if (exec_fn(modobj) != 0) { goto fail; } // Match CPython import semantics: publish parent.child only after the // child module finished executing successfully. if (parent_module != NULL && PyObject_SetAttr(parent_module, child_name, modobj) < 0) { goto fail; } Py_XDECREF(parent_module); Py_XDECREF(child_name); return modobj; fail: // Clean up on failure so that a subsequent import attempt will retry // initialization. PyErr_Fetch(&exc_type, &exc_val, &exc_tb); PyObject_DelItem(module_dict, module_name); PyErr_Clear(); PyErr_Restore(exc_type, exc_val, exc_tb); Py_XDECREF(parent_module); Py_XDECREF(child_name); Py_CLEAR(*module_static); return NULL; } int CPyImport_SetDunderAttrs(PyObject *module, PyObject *module_name, PyObject *shared_lib_file, PyObject *ext_suffix, Py_ssize_t is_package) { int res = CPyImport_SetModulePackage(module, module_name, is_package); if (res < 0) { return res; } res = CPyImport_SetModuleFile(module, module_name, shared_lib_file, ext_suffix, is_package); if (res < 0) { return res; } if (is_package) { res = CPyImport_SetModulePath(module); if (res < 0) { return res; } } return CPyImport_SetModuleSpec(module, module_name, is_package); } #if CPY_3_14_FEATURES #include "internal/pycore_object.h" void CPy_SetImmortal(PyObject *obj) { _Py_SetImmortal(obj); } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/mypyc_util.h0000644000175100017510000001372715200142331014723 0ustar00runnerrunner#ifndef MYPYC_UTIL_H #define MYPYC_UTIL_H #include #include #include #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 #ifndef Py_GIL_DISABLED // Everything is running in the same thread, so no need for thread locals #define CPyThreadLocal #else // 1. Use C11 standard thread_local storage, if available #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__) #define CPyThreadLocal _Thread_local // 2. Microsoft Visual Studio fallback #elif defined(_MSC_VER) #define CPyThreadLocal __declspec(thread) // 3. GNU thread local storage for GCC/Clang targets that still need it #elif defined(__GNUC__) || defined(__clang__) #define CPyThreadLocal __thread #else #error "Can't define CPyThreadLocal for this compiler/target (consider using a non-free-threaded Python build)" #endif #endif // Py_GIL_DISABLED // Helper macro for stringification in _Pragma #define CPY_STRINGIFY(x) #x #if defined(__clang__) #define CPY_UNROLL_LOOP_IMPL(x) _Pragma(CPY_STRINGIFY(x)) #define CPY_UNROLL_LOOP(n) CPY_UNROLL_LOOP_IMPL(unroll n) #elif defined(__GNUC__) && __GNUC__ >= 8 #define CPY_UNROLL_LOOP_IMPL(x) _Pragma(CPY_STRINGIFY(x)) #define CPY_UNROLL_LOOP(n) CPY_UNROLL_LOOP_IMPL(GCC unroll n) #else #define CPY_UNROLL_LOOP(n) #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) #ifndef Py_GIL_DISABLED // The *_NO_IMM operations below perform refcount manipulation for // non-immortal objects (Python 3.12 and later). // // Py_INCREF and other CPython operations check for immortality. This // can be expensive when we know that an object cannot be immortal. // // This optimization cannot be performed in free-threaded mode so we // fall back to just calling the normal incref/decref operations. static inline void CPy_INCREF_NO_IMM(PyObject *op) { op->ob_refcnt++; } static inline void CPy_DECREF_NO_IMM(PyObject *op) { if (--op->ob_refcnt == 0) { _Py_Dealloc(op); } } static inline void CPy_XDECREF_NO_IMM(PyObject *op) { if (op != NULL && --op->ob_refcnt == 0) { _Py_Dealloc(op); } } #define CPy_INCREF_NO_IMM(op) CPy_INCREF_NO_IMM((PyObject *)(op)) #define CPy_DECREF_NO_IMM(op) CPy_DECREF_NO_IMM((PyObject *)(op)) #define CPy_XDECREF_NO_IMM(op) CPy_XDECREF_NO_IMM((PyObject *)(op)) #else #define CPy_INCREF_NO_IMM(op) CPy_INCREF(op) #define CPy_DECREF_NO_IMM(op) CPy_DECREF(op) #define CPy_XDECREF_NO_IMM(op) CPy_XDECREF(op) #endif // 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 // Error value for signed fixed-width (low-level) integers #define CPY_LL_INT_ERROR -113 // Error value for unsigned fixed-width (low-level) integers #define CPY_LL_UINT_ERROR 239 // Error value for floats #define CPY_FLOAT_ERROR -113.0 // Value for 'None' primitive type #define CPY_NONE_ERROR 2 #define CPY_NONE 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; } // Are we targeting Python 3.X or newer? #define CPY_3_11_FEATURES (PY_VERSION_HEX >= 0x030b0000) #define CPY_3_12_FEATURES (PY_VERSION_HEX >= 0x030c0000) #define CPY_3_14_FEATURES (PY_VERSION_HEX >= 0x030e0000) #define CPY_3_15_FEATURES (PY_VERSION_HEX >= 0x030f0000) #if CPY_3_12_FEATURES // Same as macros in CPython internal/pycore_long.h, but with a CPY_ prefix #define CPY_NON_SIZE_BITS 3 #define CPY_SIGN_ZERO 1 #define CPY_SIGN_NEGATIVE 2 #define CPY_SIGN_MASK 3 #define CPY_LONG_DIGIT(o, n) ((o)->long_value.ob_digit[n]) // Only available on Python 3.12 and later #define CPY_LONG_TAG(o) ((o)->long_value.lv_tag) #define CPY_LONG_IS_NEGATIVE(o) (((o)->long_value.lv_tag & CPY_SIGN_MASK) == CPY_SIGN_NEGATIVE) // Only available on Python 3.12 and later #define CPY_LONG_SIZE(o) ((o)->long_value.lv_tag >> CPY_NON_SIZE_BITS) // Number of digits; negative for negative ints #define CPY_LONG_SIZE_SIGNED(o) (CPY_LONG_IS_NEGATIVE(o) ? -CPY_LONG_SIZE(o) : CPY_LONG_SIZE(o)) // Number of digits, assuming int is non-negative #define CPY_LONG_SIZE_UNSIGNED(o) CPY_LONG_SIZE(o) #else #define CPY_LONG_DIGIT(o, n) ((o)->ob_digit[n]) #define CPY_LONG_IS_NEGATIVE(o) (((o)->ob_base.ob_size < 0) #define CPY_LONG_SIZE_SIGNED(o) ((o)->ob_base.ob_size) #define CPY_LONG_SIZE_UNSIGNED(o) ((o)->ob_base.ob_size) #endif // Are we targeting Python 3.13 or newer? #define CPY_3_13_FEATURES (PY_VERSION_HEX >= 0x030d0000) // Are we targeting Python 3.14 or newer? #define CPY_3_14_FEATURES (PY_VERSION_HEX >= 0x030e0000) #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/pyproject.toml0000644000175100017510000000406315200142320015257 0ustar00runnerrunner[build-system] requires = ["setuptools >= 77.0.3"] build-backend = "setuptools.build_meta" [project] name = "librt" description = "Mypyc runtime library" readme = {text = """ Mypyc runtime library ===================== This library contains efficient C implementations of various Python standard library classes and functions. Mypyc can use these fast implementations when compiling Python code to native extension modules. Mypyc compiler is a part of `mypy distribution `__. """, content-type = "text/x-rst"} authors = [ {name = "Jukka Lehtosalo", email = "jukka.lehtosalo@iki.fi"}, {name = "Ivan Levkivskyi", email = "levkivskyi@gmail.com"}, ] version = "0.11.0" license = "MIT" classifiers = [ "Development Status :: 3 - Alpha", "Environment :: Console", "Intended Audience :: Developers", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", "Topic :: Software Development", "Typing :: Typed", ] requires-python = ">=3.9" [project.urls] Homepage = "https://github.com/mypyc/librt" Issues = "https://github.com/mypyc/mypyc/issues" [tool.setuptools.packages.find] include = ["librt"] [tool.setuptools.package-data] librt = ["py.typed", "**/*.pyi"] [tool.cibuildwheel] build-frontend = "build" linux.manylinux-x86_64-image = "manylinux_2_28" linux.manylinux-aarch64-image = "manylinux_2_28" linux.musllinux-x86_64-image = "musllinux_1_2" linux.musllinux-aarch64-image = "musllinux_1_2" build-verbosity = 1 linux.before-all = [ "yum install -y llvm-toolset || yum -v install -y llvm-toolset", ] before-test = [ "pip install pytest mypy_extensions", ] test-sources = [ "smoke_tests.py", ] test-command = "pytest smoke_tests.py" [tool.cibuildwheel.linux.environment] CC="clang" [[tool.cibuildwheel.overrides]] select = "*musllinux*" before-all = [ "apk add --no-cache clang", ] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/pythoncapi_compat.h0000644000175100017510000022027615200142331016245 0ustar00runnerrunner// 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/python/pythoncapi_compat // // Latest version: // https://raw.githubusercontent.com/python/pythoncapi-compat/main/pythoncapi_compat.h // // SPDX-License-Identifier: 0BSD #ifndef PYTHONCAPI_COMPAT #define PYTHONCAPI_COMPAT #ifdef __cplusplus extern "C" { #endif #include #include // offsetof() // Python 3.11.0b4 added PyFrame_Back() to Python.h #if PY_VERSION_HEX < 0x030b00B4 && !defined(PYPY_VERSION) # include "frameobject.h" // PyFrameObject, PyFrame_GetBack() #endif #ifndef _Py_CAST # define _Py_CAST(type, expr) ((type)(expr)) #endif // Static inline functions should use _Py_NULL rather than using directly NULL // to prevent C++ compiler warnings. On C23 and newer and on C++11 and newer, // _Py_NULL is defined as nullptr. #ifndef _Py_NULL # if (defined (__STDC_VERSION__) && __STDC_VERSION__ > 201710L) \ || (defined(__cplusplus) && __cplusplus >= 201103) # define _Py_NULL nullptr # else # define _Py_NULL NULL # endif #endif // Cast argument to PyObject* type. #ifndef _PyObject_CAST # define _PyObject_CAST(op) _Py_CAST(PyObject*, op) #endif #ifndef Py_BUILD_ASSERT # define Py_BUILD_ASSERT(cond) \ do { \ (void)sizeof(char [1 - 2 * !(cond)]); \ } while(0) #endif // bpo-42262 added Py_NewRef() to Python 3.10.0a3 #if PY_VERSION_HEX < 0x030A00A3 && !defined(Py_NewRef) 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) static inline PyObject* _Py_XNewRef(PyObject *obj) { Py_XINCREF(obj); return obj; } #define Py_XNewRef(obj) _Py_XNewRef(_PyObject_CAST(obj)) #endif // bpo-39573 added Py_SET_REFCNT() to Python 3.9.0a4 #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_REFCNT) 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(dst, src) \ do { \ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ PyObject *_tmp_dst = (*_tmp_dst_ptr); \ *_tmp_dst_ptr = _PyObject_CAST(src); \ Py_DECREF(_tmp_dst); \ } while (0) #define Py_XSETREF(dst, src) \ do { \ PyObject **_tmp_dst_ptr = _Py_CAST(PyObject**, &(dst)); \ PyObject *_tmp_dst = (*_tmp_dst_ptr); \ *_tmp_dst_ptr = _PyObject_CAST(src); \ Py_XDECREF(_tmp_dst); \ } 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(PYPY_VERSION)) && !defined(Py_IsTrue) # define Py_IsTrue(x) Py_Is(x, Py_True) #endif #if (PY_VERSION_HEX < 0x030A00B1 || defined(PYPY_VERSION)) && !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) 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) 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 || defined(PYPY_VERSION) static inline PyCodeObject* PyFrame_GetCode(PyFrameObject *frame) { assert(frame != _Py_NULL); assert(frame->f_code != _Py_NULL); return _Py_CAST(PyCodeObject*, Py_NewRef(frame->f_code)); } #endif static inline PyCodeObject* _PyFrame_GetCodeBorrow(PyFrameObject *frame) { PyCodeObject *code = PyFrame_GetCode(frame); Py_DECREF(code); return code; } // bpo-40421 added PyFrame_GetBack() to Python 3.9.0b1 #if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) static inline PyFrameObject* PyFrame_GetBack(PyFrameObject *frame) { assert(frame != _Py_NULL); return _Py_CAST(PyFrameObject*, Py_XNewRef(frame->f_back)); } #endif #if !defined(PYPY_VERSION) static inline PyFrameObject* _PyFrame_GetBackBorrow(PyFrameObject *frame) { PyFrameObject *back = PyFrame_GetBack(frame); Py_XDECREF(back); return back; } #endif // bpo-40421 added PyFrame_GetLocals() to Python 3.11.0a7 #if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) static inline PyObject* PyFrame_GetLocals(PyFrameObject *frame) { #if PY_VERSION_HEX >= 0x030400B1 if (PyFrame_FastToLocalsWithError(frame) < 0) { return NULL; } #else PyFrame_FastToLocals(frame); #endif return Py_NewRef(frame->f_locals); } #endif // bpo-40421 added PyFrame_GetGlobals() to Python 3.11.0a7 #if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) static inline PyObject* PyFrame_GetGlobals(PyFrameObject *frame) { return Py_NewRef(frame->f_globals); } #endif // bpo-40421 added PyFrame_GetBuiltins() to Python 3.11.0a7 #if PY_VERSION_HEX < 0x030B00A7 && !defined(PYPY_VERSION) static inline PyObject* PyFrame_GetBuiltins(PyFrameObject *frame) { return Py_NewRef(frame->f_builtins); } #endif // bpo-40421 added PyFrame_GetLasti() to Python 3.11.0b1 #if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION) static inline int PyFrame_GetLasti(PyFrameObject *frame) { #if PY_VERSION_HEX >= 0x030A00A7 // bpo-27129: Since Python 3.10.0a7, f_lasti is an instruction offset, // not a bytes offset anymore. Python uses 16-bit "wordcode" (2 bytes) // instructions. if (frame->f_lasti < 0) { return -1; } return frame->f_lasti * 2; #else return frame->f_lasti; #endif } #endif // gh-91248 added PyFrame_GetVar() to Python 3.12.0a2 #if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION) static inline PyObject* PyFrame_GetVar(PyFrameObject *frame, PyObject *name) { PyObject *locals, *value; locals = PyFrame_GetLocals(frame); if (locals == NULL) { return NULL; } #if PY_VERSION_HEX >= 0x03000000 value = PyDict_GetItemWithError(locals, name); #else value = _PyDict_GetItemWithError(locals, name); #endif Py_DECREF(locals); if (value == NULL) { if (PyErr_Occurred()) { return NULL; } #if PY_VERSION_HEX >= 0x03000000 PyErr_Format(PyExc_NameError, "variable %R does not exist", name); #else PyErr_SetString(PyExc_NameError, "variable does not exist"); #endif return NULL; } return Py_NewRef(value); } #endif // gh-91248 added PyFrame_GetVarString() to Python 3.12.0a2 #if PY_VERSION_HEX < 0x030C00A2 && !defined(PYPY_VERSION) static inline PyObject* PyFrame_GetVarString(PyFrameObject *frame, const char *name) { PyObject *name_obj, *value; #if PY_VERSION_HEX >= 0x03000000 name_obj = PyUnicode_FromString(name); #else name_obj = PyString_FromString(name); #endif if (name_obj == NULL) { return NULL; } value = PyFrame_GetVar(frame, name_obj); Py_DECREF(name_obj); return value; } #endif // bpo-39947 added PyThreadState_GetInterpreter() to Python 3.9.0a5 #if PY_VERSION_HEX < 0x030900A5 || (defined(PYPY_VERSION) && PY_VERSION_HEX < 0x030B0000) static inline PyInterpreterState * PyThreadState_GetInterpreter(PyThreadState *tstate) { assert(tstate != _Py_NULL); return tstate->interp; } #endif // bpo-40429 added PyThreadState_GetFrame() to Python 3.9.0b1 #if PY_VERSION_HEX < 0x030900B1 && !defined(PYPY_VERSION) static inline PyFrameObject* PyThreadState_GetFrame(PyThreadState *tstate) { assert(tstate != _Py_NULL); return _Py_CAST(PyFrameObject *, Py_XNewRef(tstate->frame)); } #endif #if !defined(PYPY_VERSION) static inline PyFrameObject* _PyThreadState_GetFrameBorrow(PyThreadState *tstate) { PyFrameObject *frame = PyThreadState_GetFrame(tstate); Py_XDECREF(frame); return frame; } #endif // bpo-39947 added PyInterpreterState_Get() to Python 3.9.0a5 #if PY_VERSION_HEX < 0x030900A5 || defined(PYPY_VERSION) static inline PyInterpreterState* PyInterpreterState_Get(void) { PyThreadState *tstate; PyInterpreterState *interp; tstate = PyThreadState_GET(); if (tstate == _Py_NULL) { Py_FatalError("GIL released (tstate is NULL)"); } interp = tstate->interp; if (interp == _Py_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) static inline uint64_t PyThreadState_GetID(PyThreadState *tstate) { assert(tstate != _Py_NULL); return tstate->id; } #endif // bpo-43760 added PyThreadState_EnterTracing() to Python 3.11.0a2 #if PY_VERSION_HEX < 0x030B00A2 && !defined(PYPY_VERSION) 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) static inline void PyThreadState_LeaveTracing(PyThreadState *tstate) { int use_tracing = (tstate->c_tracefunc != _Py_NULL || tstate->c_profilefunc != _Py_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 // PyObject_CallNoArgs() added to PyPy 3.9.16-v7.3.11 #if !defined(PyObject_CallNoArgs) && PY_VERSION_HEX < 0x030900A1 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 // PyObject_CallOneArg() added to PyPy 3.9.16-v7.3.11 #if !defined(PyObject_CallOneArg) && PY_VERSION_HEX < 0x030900A4 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 static inline int PyModule_AddObjectRef(PyObject *module, const char *name, PyObject *value) { int res; if (!value && !PyErr_Occurred()) { // PyModule_AddObject() raises TypeError in this case PyErr_SetString(PyExc_SystemError, "PyModule_AddObjectRef() must be called " "with an exception raised if value is NULL"); return -1; } Py_XINCREF(value); res = PyModule_AddObject(module, 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 static inline int PyModule_AddType(PyObject *module, PyTypeObject *type) { const char *name, *dot; if (PyType_Ready(type) < 0) { return -1; } // inline _PyType_Name() name = type->tp_name; assert(name != _Py_NULL); dot = strrchr(name, '.'); if (dot != _Py_NULL) { name = dot + 1; } return PyModule_AddObjectRef(module, 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) 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) static inline int PyObject_GC_IsFinalized(PyObject *obj) { PyGC_Head *gc = _Py_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) static inline int _Py_IS_TYPE(PyObject *ob, PyTypeObject *type) { return Py_TYPE(ob) == type; } #define Py_IS_TYPE(ob, type) _Py_IS_TYPE(_PyObject_CAST(ob), type) #endif // bpo-46906 added PyFloat_Pack2() and PyFloat_Unpack2() to Python 3.11a7. // bpo-11734 added _PyFloat_Pack2() and _PyFloat_Unpack2() to Python 3.6.0b1. // Python 3.11a2 moved _PyFloat_Pack2() and _PyFloat_Unpack2() to the internal // C API: Python 3.11a2-3.11a6 versions are not supported. #if 0x030600B1 <= PY_VERSION_HEX && PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) static inline int PyFloat_Pack2(double x, char *p, int le) { return _PyFloat_Pack2(x, (unsigned char*)p, le); } static inline double PyFloat_Unpack2(const char *p, int le) { return _PyFloat_Unpack2((const unsigned char *)p, le); } #endif // bpo-46906 added PyFloat_Pack4(), PyFloat_Pack8(), PyFloat_Unpack4() and // PyFloat_Unpack8() to Python 3.11a7. // Python 3.11a2 moved _PyFloat_Pack4(), _PyFloat_Pack8(), _PyFloat_Unpack4() // and _PyFloat_Unpack8() to the internal C API: Python 3.11a2-3.11a6 versions // are not supported. #if PY_VERSION_HEX <= 0x030B00A1 && !defined(PYPY_VERSION) static inline int PyFloat_Pack4(double x, char *p, int le) { return _PyFloat_Pack4(x, (unsigned char*)p, le); } static inline int PyFloat_Pack8(double x, char *p, int le) { return _PyFloat_Pack8(x, (unsigned char*)p, le); } static inline double PyFloat_Unpack4(const char *p, int le) { return _PyFloat_Unpack4((const unsigned char *)p, le); } static inline double PyFloat_Unpack8(const char *p, int le) { return _PyFloat_Unpack8((const unsigned char *)p, le); } #endif // gh-92154 added PyCode_GetCode() to Python 3.11.0b1 #if PY_VERSION_HEX < 0x030B00B1 && !defined(PYPY_VERSION) static inline PyObject* PyCode_GetCode(PyCodeObject *code) { return Py_NewRef(code->co_code); } #endif // gh-95008 added PyCode_GetVarnames() to Python 3.11.0rc1 #if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION) static inline PyObject* PyCode_GetVarnames(PyCodeObject *code) { return Py_NewRef(code->co_varnames); } #endif // gh-95008 added PyCode_GetFreevars() to Python 3.11.0rc1 #if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION) static inline PyObject* PyCode_GetFreevars(PyCodeObject *code) { return Py_NewRef(code->co_freevars); } #endif // gh-95008 added PyCode_GetCellvars() to Python 3.11.0rc1 #if PY_VERSION_HEX < 0x030B00C1 && !defined(PYPY_VERSION) static inline PyObject* PyCode_GetCellvars(PyCodeObject *code) { return Py_NewRef(code->co_cellvars); } #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 // gh-105922 added PyImport_AddModuleRef() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A0 static inline PyObject* PyImport_AddModuleRef(const char *name) { return Py_XNewRef(PyImport_AddModule(name)); } #endif // gh-105927 added PyWeakref_GetRef() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D0000 static inline int PyWeakref_GetRef(PyObject *ref, PyObject **pobj) { PyObject *obj; if (ref != NULL && !PyWeakref_Check(ref)) { *pobj = NULL; PyErr_SetString(PyExc_TypeError, "expected a weakref"); return -1; } obj = PyWeakref_GetObject(ref); if (obj == NULL) { // SystemError if ref is NULL *pobj = NULL; return -1; } if (obj == Py_None) { *pobj = NULL; return 0; } *pobj = Py_NewRef(obj); return 1; } #endif // bpo-36974 added PY_VECTORCALL_ARGUMENTS_OFFSET to Python 3.8b1 #ifndef PY_VECTORCALL_ARGUMENTS_OFFSET # define PY_VECTORCALL_ARGUMENTS_OFFSET (_Py_CAST(size_t, 1) << (8 * sizeof(size_t) - 1)) #endif // bpo-36974 added PyVectorcall_NARGS() to Python 3.8b1 #if PY_VERSION_HEX < 0x030800B1 static inline Py_ssize_t PyVectorcall_NARGS(size_t n) { return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET; } #endif // gh-105922 added PyObject_Vectorcall() to Python 3.9.0a4 #if PY_VERSION_HEX < 0x030900A4 static inline PyObject* PyObject_Vectorcall(PyObject *callable, PyObject *const *args, size_t nargsf, PyObject *kwnames) { #if PY_VERSION_HEX >= 0x030800B1 && !defined(PYPY_VERSION) // bpo-36974 added _PyObject_Vectorcall() to Python 3.8.0b1 return _PyObject_Vectorcall(callable, args, nargsf, kwnames); #else PyObject *posargs = NULL, *kwargs = NULL; PyObject *res; Py_ssize_t nposargs, nkwargs, i; if (nargsf != 0 && args == NULL) { PyErr_BadInternalCall(); goto error; } if (kwnames != NULL && !PyTuple_Check(kwnames)) { PyErr_BadInternalCall(); goto error; } nposargs = (Py_ssize_t)PyVectorcall_NARGS(nargsf); if (kwnames) { nkwargs = PyTuple_GET_SIZE(kwnames); } else { nkwargs = 0; } posargs = PyTuple_New(nposargs); if (posargs == NULL) { goto error; } if (nposargs) { for (i=0; i < nposargs; i++) { PyTuple_SET_ITEM(posargs, i, Py_NewRef(*args)); args++; } } if (nkwargs) { kwargs = PyDict_New(); if (kwargs == NULL) { goto error; } for (i = 0; i < nkwargs; i++) { PyObject *key = PyTuple_GET_ITEM(kwnames, i); PyObject *value = *args; args++; if (PyDict_SetItem(kwargs, key, value) < 0) { goto error; } } } else { kwargs = NULL; } res = PyObject_Call(callable, posargs, kwargs); Py_DECREF(posargs); Py_XDECREF(kwargs); return res; error: Py_DECREF(posargs); Py_XDECREF(kwargs); return NULL; #endif } #endif // gh-106521 added PyObject_GetOptionalAttr() and // PyObject_GetOptionalAttrString() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyObject_GetOptionalAttr(PyObject *obj, PyObject *attr_name, PyObject **result) { // bpo-32571 added _PyObject_LookupAttr() to Python 3.7.0b1 #if PY_VERSION_HEX >= 0x030700B1 && !defined(PYPY_VERSION) return _PyObject_LookupAttr(obj, attr_name, result); #else *result = PyObject_GetAttr(obj, attr_name); if (*result != NULL) { return 1; } if (!PyErr_Occurred()) { return 0; } if (PyErr_ExceptionMatches(PyExc_AttributeError)) { PyErr_Clear(); return 0; } return -1; #endif } static inline int PyObject_GetOptionalAttrString(PyObject *obj, const char *attr_name, PyObject **result) { PyObject *name_obj; int rc; #if PY_VERSION_HEX >= 0x03000000 name_obj = PyUnicode_FromString(attr_name); #else name_obj = PyString_FromString(attr_name); #endif if (name_obj == NULL) { *result = NULL; return -1; } rc = PyObject_GetOptionalAttr(obj, name_obj, result); Py_DECREF(name_obj); return rc; } #endif // gh-106307 added PyObject_GetOptionalAttr() and // PyMapping_GetOptionalItemString() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result) { *result = PyObject_GetItem(obj, key); if (*result) { return 1; } if (!PyErr_ExceptionMatches(PyExc_KeyError)) { return -1; } PyErr_Clear(); return 0; } static inline int PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result) { PyObject *key_obj; int rc; #if PY_VERSION_HEX >= 0x03000000 key_obj = PyUnicode_FromString(key); #else key_obj = PyString_FromString(key); #endif if (key_obj == NULL) { *result = NULL; return -1; } rc = PyMapping_GetOptionalItem(obj, key_obj, result); Py_DECREF(key_obj); return rc; } #endif // gh-108511 added PyMapping_HasKeyWithError() and // PyMapping_HasKeyStringWithError() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyMapping_HasKeyWithError(PyObject *obj, PyObject *key) { PyObject *res; int rc = PyMapping_GetOptionalItem(obj, key, &res); Py_XDECREF(res); return rc; } static inline int PyMapping_HasKeyStringWithError(PyObject *obj, const char *key) { PyObject *res; int rc = PyMapping_GetOptionalItemString(obj, key, &res); Py_XDECREF(res); return rc; } #endif // gh-108511 added PyObject_HasAttrWithError() and // PyObject_HasAttrStringWithError() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyObject_HasAttrWithError(PyObject *obj, PyObject *attr) { PyObject *res; int rc = PyObject_GetOptionalAttr(obj, attr, &res); Py_XDECREF(res); return rc; } static inline int PyObject_HasAttrStringWithError(PyObject *obj, const char *attr) { PyObject *res; int rc = PyObject_GetOptionalAttrString(obj, attr, &res); Py_XDECREF(res); return rc; } #endif // gh-106004 added PyDict_GetItemRef() and PyDict_GetItemStringRef() // to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result) { #if PY_VERSION_HEX >= 0x03000000 PyObject *item = PyDict_GetItemWithError(mp, key); #else PyObject *item = _PyDict_GetItemWithError(mp, key); #endif if (item != NULL) { *result = Py_NewRef(item); return 1; // found } if (!PyErr_Occurred()) { *result = NULL; return 0; // not found } *result = NULL; return -1; } static inline int PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result) { int res; #if PY_VERSION_HEX >= 0x03000000 PyObject *key_obj = PyUnicode_FromString(key); #else PyObject *key_obj = PyString_FromString(key); #endif if (key_obj == NULL) { *result = NULL; return -1; } res = PyDict_GetItemRef(mp, key_obj, result); Py_DECREF(key_obj); return res; } #endif // gh-106307 added PyModule_Add() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyModule_Add(PyObject *mod, const char *name, PyObject *value) { int res = PyModule_AddObjectRef(mod, name, value); Py_XDECREF(value); return res; } #endif // gh-108014 added Py_IsFinalizing() to Python 3.13.0a1 // bpo-1856 added _Py_Finalizing to Python 3.2.1b1. // _Py_IsFinalizing() was added to PyPy 7.3.0. #if (0x030201B1 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030D00A1) \ && (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x7030000) static inline int Py_IsFinalizing(void) { #if PY_VERSION_HEX >= 0x030700A1 // _Py_IsFinalizing() was added to Python 3.7.0a1. return _Py_IsFinalizing(); #else return (_Py_Finalizing != NULL); #endif } #endif // gh-108323 added PyDict_ContainsString() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyDict_ContainsString(PyObject *op, const char *key) { PyObject *key_obj = PyUnicode_FromString(key); if (key_obj == NULL) { return -1; } int res = PyDict_Contains(op, key_obj); Py_DECREF(key_obj); return res; } #endif // gh-108445 added PyLong_AsInt() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyLong_AsInt(PyObject *obj) { #ifdef PYPY_VERSION long value = PyLong_AsLong(obj); if (value == -1 && PyErr_Occurred()) { return -1; } if (value < (long)INT_MIN || (long)INT_MAX < value) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C int"); return -1; } return (int)value; #else return _PyLong_AsInt(obj); #endif } #endif // gh-107073 added PyObject_VisitManagedDict() to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg) { PyObject **dict = _PyObject_GetDictPtr(obj); if (dict == NULL || *dict == NULL) { // Nothing to do. return 0; } Py_VISIT(*dict); return 0; } static inline void PyObject_ClearManagedDict(PyObject *obj) { PyObject **dict = _PyObject_GetDictPtr(obj); if (dict == NULL || *dict == NULL) { return; } Py_CLEAR(*dict); } #endif // gh-108867 added PyThreadState_GetUnchecked() to Python 3.13.0a1 // Python 3.5.2 added _PyThreadState_UncheckedGet(). #if PY_VERSION_HEX >= 0x03050200 && PY_VERSION_HEX < 0x030D00A1 static inline PyThreadState* PyThreadState_GetUnchecked(void) { return _PyThreadState_UncheckedGet(); } #endif // gh-110289 added PyUnicode_EqualToUTF8() and PyUnicode_EqualToUTF8AndSize() // to Python 3.13.0a1 #if PY_VERSION_HEX < 0x030D00A1 static inline int PyUnicode_EqualToUTF8AndSize(PyObject *unicode, const char *str, Py_ssize_t str_len) { Py_ssize_t len; const void *utf8; PyObject *exc_type, *exc_value, *exc_tb; int res; // API cannot report errors so save/restore the exception PyErr_Fetch(&exc_type, &exc_value, &exc_tb); // Python 3.3.0a1 added PyUnicode_AsUTF8AndSize() #if PY_VERSION_HEX >= 0x030300A1 if (PyUnicode_IS_ASCII(unicode)) { utf8 = PyUnicode_DATA(unicode); len = PyUnicode_GET_LENGTH(unicode); } else { utf8 = PyUnicode_AsUTF8AndSize(unicode, &len); if (utf8 == NULL) { // Memory allocation failure. The API cannot report error, // so ignore the exception and return 0. res = 0; goto done; } } if (len != str_len) { res = 0; goto done; } res = (memcmp(utf8, str, (size_t)len) == 0); #else PyObject *bytes = PyUnicode_AsUTF8String(unicode); if (bytes == NULL) { // Memory allocation failure. The API cannot report error, // so ignore the exception and return 0. res = 0; goto done; } #if PY_VERSION_HEX >= 0x03000000 len = PyBytes_GET_SIZE(bytes); utf8 = PyBytes_AS_STRING(bytes); #else len = PyString_GET_SIZE(bytes); utf8 = PyString_AS_STRING(bytes); #endif if (len != str_len) { Py_DECREF(bytes); res = 0; goto done; } res = (memcmp(utf8, str, (size_t)len) == 0); Py_DECREF(bytes); #endif done: PyErr_Restore(exc_type, exc_value, exc_tb); return res; } static inline int PyUnicode_EqualToUTF8(PyObject *unicode, const char *str) { return PyUnicode_EqualToUTF8AndSize(unicode, str, (Py_ssize_t)strlen(str)); } #endif // gh-111138 added PyList_Extend() and PyList_Clear() to Python 3.13.0a2 #if PY_VERSION_HEX < 0x030D00A2 static inline int PyList_Extend(PyObject *list, PyObject *iterable) { return PyList_SetSlice(list, PY_SSIZE_T_MAX, PY_SSIZE_T_MAX, iterable); } static inline int PyList_Clear(PyObject *list) { return PyList_SetSlice(list, 0, PY_SSIZE_T_MAX, NULL); } #endif // gh-111262 added PyDict_Pop() and PyDict_PopString() to Python 3.13.0a2 #if PY_VERSION_HEX < 0x030D00A2 static inline int PyDict_Pop(PyObject *dict, PyObject *key, PyObject **result) { PyObject *value; if (!PyDict_Check(dict)) { PyErr_BadInternalCall(); if (result) { *result = NULL; } return -1; } // bpo-16991 added _PyDict_Pop() to Python 3.5.0b2. // Python 3.6.0b3 changed _PyDict_Pop() first argument type to PyObject*. // Python 3.13.0a1 removed _PyDict_Pop(). #if defined(PYPY_VERSION) || PY_VERSION_HEX < 0x030500b2 || PY_VERSION_HEX >= 0x030D0000 value = PyObject_CallMethod(dict, "pop", "O", key); #elif PY_VERSION_HEX < 0x030600b3 value = _PyDict_Pop(_Py_CAST(PyDictObject*, dict), key, NULL); #else value = _PyDict_Pop(dict, key, NULL); #endif if (value == NULL) { if (result) { *result = NULL; } if (PyErr_Occurred() && !PyErr_ExceptionMatches(PyExc_KeyError)) { return -1; } PyErr_Clear(); return 0; } if (result) { *result = value; } else { Py_DECREF(value); } return 1; } static inline int PyDict_PopString(PyObject *dict, const char *key, PyObject **result) { PyObject *key_obj = PyUnicode_FromString(key); if (key_obj == NULL) { if (result != NULL) { *result = NULL; } return -1; } int res = PyDict_Pop(dict, key_obj, result); Py_DECREF(key_obj); return res; } #endif #if PY_VERSION_HEX < 0x030200A4 // Python 3.2.0a4 added Py_hash_t type typedef Py_ssize_t Py_hash_t; #endif // gh-111545 added Py_HashPointer() to Python 3.13.0a3 #if PY_VERSION_HEX < 0x030D00A3 static inline Py_hash_t Py_HashPointer(const void *ptr) { #if PY_VERSION_HEX >= 0x030900A4 && !defined(PYPY_VERSION) return _Py_HashPointer(ptr); #else return _Py_HashPointer(_Py_CAST(void*, ptr)); #endif } #endif // Python 3.13a4 added a PyTime API. // Use the private API added to Python 3.5. #if PY_VERSION_HEX < 0x030D00A4 && PY_VERSION_HEX >= 0x03050000 typedef _PyTime_t PyTime_t; #define PyTime_MIN _PyTime_MIN #define PyTime_MAX _PyTime_MAX static inline double PyTime_AsSecondsDouble(PyTime_t t) { return _PyTime_AsSecondsDouble(t); } static inline int PyTime_Monotonic(PyTime_t *result) { return _PyTime_GetMonotonicClockWithInfo(result, NULL); } static inline int PyTime_Time(PyTime_t *result) { return _PyTime_GetSystemClockWithInfo(result, NULL); } static inline int PyTime_PerfCounter(PyTime_t *result) { #if PY_VERSION_HEX >= 0x03070000 && !defined(PYPY_VERSION) return _PyTime_GetPerfCounterWithInfo(result, NULL); #elif PY_VERSION_HEX >= 0x03070000 // Call time.perf_counter_ns() and convert Python int object to PyTime_t. // Cache time.perf_counter_ns() function for best performance. static PyObject *func = NULL; if (func == NULL) { PyObject *mod = PyImport_ImportModule("time"); if (mod == NULL) { return -1; } func = PyObject_GetAttrString(mod, "perf_counter_ns"); Py_DECREF(mod); if (func == NULL) { return -1; } } PyObject *res = PyObject_CallNoArgs(func); if (res == NULL) { return -1; } long long value = PyLong_AsLongLong(res); Py_DECREF(res); if (value == -1 && PyErr_Occurred()) { return -1; } Py_BUILD_ASSERT(sizeof(value) >= sizeof(PyTime_t)); *result = (PyTime_t)value; return 0; #else // Call time.perf_counter() and convert C double to PyTime_t. // Cache time.perf_counter() function for best performance. static PyObject *func = NULL; if (func == NULL) { PyObject *mod = PyImport_ImportModule("time"); if (mod == NULL) { return -1; } func = PyObject_GetAttrString(mod, "perf_counter"); Py_DECREF(mod); if (func == NULL) { return -1; } } PyObject *res = PyObject_CallNoArgs(func); if (res == NULL) { return -1; } double d = PyFloat_AsDouble(res); Py_DECREF(res); if (d == -1.0 && PyErr_Occurred()) { return -1; } // Avoid floor() to avoid having to link to libm *result = (PyTime_t)(d * 1e9); return 0; #endif } #endif // gh-111389 added hash constants to Python 3.13.0a5. These constants were // added first as private macros to Python 3.4.0b1 and PyPy 7.3.8. #if (!defined(PyHASH_BITS) \ && ((!defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x030400B1) \ || (defined(PYPY_VERSION) && PY_VERSION_HEX >= 0x03070000 \ && PYPY_VERSION_NUM >= 0x07030800))) # define PyHASH_BITS _PyHASH_BITS # define PyHASH_MODULUS _PyHASH_MODULUS # define PyHASH_INF _PyHASH_INF # define PyHASH_IMAG _PyHASH_IMAG #endif // gh-111545 added Py_GetConstant() and Py_GetConstantBorrowed() // to Python 3.13.0a6 #if PY_VERSION_HEX < 0x030D00A6 && !defined(Py_CONSTANT_NONE) #define Py_CONSTANT_NONE 0 #define Py_CONSTANT_FALSE 1 #define Py_CONSTANT_TRUE 2 #define Py_CONSTANT_ELLIPSIS 3 #define Py_CONSTANT_NOT_IMPLEMENTED 4 #define Py_CONSTANT_ZERO 5 #define Py_CONSTANT_ONE 6 #define Py_CONSTANT_EMPTY_STR 7 #define Py_CONSTANT_EMPTY_BYTES 8 #define Py_CONSTANT_EMPTY_TUPLE 9 static inline PyObject* Py_GetConstant(unsigned int constant_id) { static PyObject* constants[Py_CONSTANT_EMPTY_TUPLE + 1] = {NULL}; if (constants[Py_CONSTANT_NONE] == NULL) { constants[Py_CONSTANT_NONE] = Py_None; constants[Py_CONSTANT_FALSE] = Py_False; constants[Py_CONSTANT_TRUE] = Py_True; constants[Py_CONSTANT_ELLIPSIS] = Py_Ellipsis; constants[Py_CONSTANT_NOT_IMPLEMENTED] = Py_NotImplemented; constants[Py_CONSTANT_ZERO] = PyLong_FromLong(0); if (constants[Py_CONSTANT_ZERO] == NULL) { goto fatal_error; } constants[Py_CONSTANT_ONE] = PyLong_FromLong(1); if (constants[Py_CONSTANT_ONE] == NULL) { goto fatal_error; } constants[Py_CONSTANT_EMPTY_STR] = PyUnicode_FromStringAndSize("", 0); if (constants[Py_CONSTANT_EMPTY_STR] == NULL) { goto fatal_error; } constants[Py_CONSTANT_EMPTY_BYTES] = PyBytes_FromStringAndSize("", 0); if (constants[Py_CONSTANT_EMPTY_BYTES] == NULL) { goto fatal_error; } constants[Py_CONSTANT_EMPTY_TUPLE] = PyTuple_New(0); if (constants[Py_CONSTANT_EMPTY_TUPLE] == NULL) { goto fatal_error; } // goto dance to avoid compiler warnings about Py_FatalError() goto init_done; fatal_error: // This case should never happen Py_FatalError("Py_GetConstant() failed to get constants"); } init_done: if (constant_id <= Py_CONSTANT_EMPTY_TUPLE) { return Py_NewRef(constants[constant_id]); } else { PyErr_BadInternalCall(); return NULL; } } static inline PyObject* Py_GetConstantBorrowed(unsigned int constant_id) { PyObject *obj = Py_GetConstant(constant_id); Py_XDECREF(obj); return obj; } #endif // gh-114329 added PyList_GetItemRef() to Python 3.13.0a4 #if PY_VERSION_HEX < 0x030D00A4 static inline PyObject * PyList_GetItemRef(PyObject *op, Py_ssize_t index) { PyObject *item = PyList_GetItem(op, index); Py_XINCREF(item); return item; } #endif // gh-114329 added PyList_GetItemRef() to Python 3.13.0a4 #if PY_VERSION_HEX < 0x030D00A4 static inline int PyDict_SetDefaultRef(PyObject *d, PyObject *key, PyObject *default_value, PyObject **result) { PyObject *value; if (PyDict_GetItemRef(d, key, &value) < 0) { // get error if (result) { *result = NULL; } return -1; } if (value != NULL) { // present if (result) { *result = value; } else { Py_DECREF(value); } return 1; } // missing: set the item if (PyDict_SetItem(d, key, default_value) < 0) { // set error if (result) { *result = NULL; } return -1; } if (result) { *result = Py_NewRef(default_value); } return 0; } #endif #if PY_VERSION_HEX < 0x030D00B3 # define Py_BEGIN_CRITICAL_SECTION(op) { # define Py_END_CRITICAL_SECTION() } # define Py_BEGIN_CRITICAL_SECTION2(a, b) { # define Py_END_CRITICAL_SECTION2() } #endif #if PY_VERSION_HEX < 0x030E0000 && PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) typedef struct PyUnicodeWriter PyUnicodeWriter; static inline void PyUnicodeWriter_Discard(PyUnicodeWriter *writer) { _PyUnicodeWriter_Dealloc((_PyUnicodeWriter*)writer); PyMem_Free(writer); } static inline PyUnicodeWriter* PyUnicodeWriter_Create(Py_ssize_t length) { if (length < 0) { PyErr_SetString(PyExc_ValueError, "length must be positive"); return NULL; } const size_t size = sizeof(_PyUnicodeWriter); PyUnicodeWriter *pub_writer = (PyUnicodeWriter *)PyMem_Malloc(size); if (pub_writer == _Py_NULL) { PyErr_NoMemory(); return _Py_NULL; } _PyUnicodeWriter *writer = (_PyUnicodeWriter *)pub_writer; _PyUnicodeWriter_Init(writer); if (_PyUnicodeWriter_Prepare(writer, length, 127) < 0) { PyUnicodeWriter_Discard(pub_writer); return NULL; } writer->overallocate = 1; return pub_writer; } static inline PyObject* PyUnicodeWriter_Finish(PyUnicodeWriter *writer) { PyObject *str = _PyUnicodeWriter_Finish((_PyUnicodeWriter*)writer); assert(((_PyUnicodeWriter*)writer)->buffer == NULL); PyMem_Free(writer); return str; } static inline int PyUnicodeWriter_WriteChar(PyUnicodeWriter *writer, Py_UCS4 ch) { if (ch > 0x10ffff) { PyErr_SetString(PyExc_ValueError, "character must be in range(0x110000)"); return -1; } return _PyUnicodeWriter_WriteChar((_PyUnicodeWriter*)writer, ch); } static inline int PyUnicodeWriter_WriteStr(PyUnicodeWriter *writer, PyObject *obj) { PyObject *str = PyObject_Str(obj); if (str == NULL) { return -1; } int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); Py_DECREF(str); return res; } static inline int PyUnicodeWriter_WriteRepr(PyUnicodeWriter *writer, PyObject *obj) { if (obj == NULL) { return _PyUnicodeWriter_WriteASCIIString((_PyUnicodeWriter*)writer, "", 6); } PyObject *str = PyObject_Repr(obj); if (str == NULL) { return -1; } int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); Py_DECREF(str); return res; } static inline int PyUnicodeWriter_WriteUTF8(PyUnicodeWriter *writer, const char *str, Py_ssize_t size) { if (size < 0) { size = (Py_ssize_t)strlen(str); } PyObject *str_obj = PyUnicode_FromStringAndSize(str, size); if (str_obj == _Py_NULL) { return -1; } int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj); Py_DECREF(str_obj); return res; } static inline int PyUnicodeWriter_WriteASCII(PyUnicodeWriter *writer, const char *str, Py_ssize_t size) { if (size < 0) { size = (Py_ssize_t)strlen(str); } return _PyUnicodeWriter_WriteASCIIString((_PyUnicodeWriter*)writer, str, size); } static inline int PyUnicodeWriter_WriteWideChar(PyUnicodeWriter *writer, const wchar_t *str, Py_ssize_t size) { if (size < 0) { size = (Py_ssize_t)wcslen(str); } PyObject *str_obj = PyUnicode_FromWideChar(str, size); if (str_obj == _Py_NULL) { return -1; } int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str_obj); Py_DECREF(str_obj); return res; } static inline int PyUnicodeWriter_WriteSubstring(PyUnicodeWriter *writer, PyObject *str, Py_ssize_t start, Py_ssize_t end) { if (!PyUnicode_Check(str)) { PyErr_Format(PyExc_TypeError, "expect str, not %s", Py_TYPE(str)->tp_name); return -1; } if (start < 0 || start > end) { PyErr_Format(PyExc_ValueError, "invalid start argument"); return -1; } if (end > PyUnicode_GET_LENGTH(str)) { PyErr_Format(PyExc_ValueError, "invalid end argument"); return -1; } return _PyUnicodeWriter_WriteSubstring((_PyUnicodeWriter*)writer, str, start, end); } static inline int PyUnicodeWriter_Format(PyUnicodeWriter *writer, const char *format, ...) { va_list vargs; va_start(vargs, format); PyObject *str = PyUnicode_FromFormatV(format, vargs); va_end(vargs); if (str == _Py_NULL) { return -1; } int res = _PyUnicodeWriter_WriteStr((_PyUnicodeWriter*)writer, str); Py_DECREF(str); return res; } #endif // PY_VERSION_HEX < 0x030E0000 // gh-116560 added PyLong_GetSign() to Python 3.14.0a0 #if PY_VERSION_HEX < 0x030E00A0 static inline int PyLong_GetSign(PyObject *obj, int *sign) { if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expect int, got %s", Py_TYPE(obj)->tp_name); return -1; } *sign = _PyLong_Sign(obj); return 0; } #endif // gh-126061 added PyLong_IsPositive/Negative/Zero() to Python in 3.14.0a2 #if PY_VERSION_HEX < 0x030E00A2 static inline int PyLong_IsPositive(PyObject *obj) { if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name); return -1; } return _PyLong_Sign(obj) == 1; } static inline int PyLong_IsNegative(PyObject *obj) { if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name); return -1; } return _PyLong_Sign(obj) == -1; } static inline int PyLong_IsZero(PyObject *obj) { if (!PyLong_Check(obj)) { PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name); return -1; } return _PyLong_Sign(obj) == 0; } #endif // gh-124502 added PyUnicode_Equal() to Python 3.14.0a0 #if PY_VERSION_HEX < 0x030E00A0 #if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION) PyAPI_FUNC(int) _PyUnicode_Equal(PyObject *str1, PyObject *str2); #endif static inline int PyUnicode_Equal(PyObject *str1, PyObject *str2) { if (!PyUnicode_Check(str1)) { PyErr_Format(PyExc_TypeError, "first argument must be str, not %s", Py_TYPE(str1)->tp_name); return -1; } if (!PyUnicode_Check(str2)) { PyErr_Format(PyExc_TypeError, "second argument must be str, not %s", Py_TYPE(str2)->tp_name); return -1; } #if PY_VERSION_HEX >= 0x030d0000 && !defined(PYPY_VERSION) return _PyUnicode_Equal(str1, str2); #elif PY_VERSION_HEX >= 0x03060000 && !defined(PYPY_VERSION) return _PyUnicode_EQ(str1, str2); #elif PY_VERSION_HEX >= 0x03090000 && defined(PYPY_VERSION) return _PyUnicode_EQ(str1, str2); #else return (PyUnicode_Compare(str1, str2) == 0); #endif } #endif // gh-121645 added PyBytes_Join() to Python 3.14.0a0 #if PY_VERSION_HEX < 0x030E00A0 static inline PyObject* PyBytes_Join(PyObject *sep, PyObject *iterable) { return _PyBytes_Join(sep, iterable); } #endif #if PY_VERSION_HEX < 0x030E00A0 #if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) PyAPI_FUNC(Py_hash_t) _Py_HashBytes(const void *src, Py_ssize_t len); #endif static inline Py_hash_t Py_HashBuffer(const void *ptr, Py_ssize_t len) { #if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) return _Py_HashBytes(ptr, len); #else Py_hash_t hash; PyObject *bytes = PyBytes_FromStringAndSize((const char*)ptr, len); if (bytes == NULL) { return -1; } hash = PyObject_Hash(bytes); Py_DECREF(bytes); return hash; #endif } #endif #if PY_VERSION_HEX < 0x030E00A0 static inline int PyIter_NextItem(PyObject *iter, PyObject **item) { iternextfunc tp_iternext; assert(iter != NULL); assert(item != NULL); tp_iternext = Py_TYPE(iter)->tp_iternext; if (tp_iternext == NULL) { *item = NULL; PyErr_Format(PyExc_TypeError, "expected an iterator, got '%s'", Py_TYPE(iter)->tp_name); return -1; } if ((*item = tp_iternext(iter))) { return 1; } if (!PyErr_Occurred()) { return 0; } if (PyErr_ExceptionMatches(PyExc_StopIteration)) { PyErr_Clear(); return 0; } return -1; } #endif #if PY_VERSION_HEX < 0x030E00A0 static inline PyObject* PyLong_FromInt32(int32_t value) { Py_BUILD_ASSERT(sizeof(long) >= 4); return PyLong_FromLong(value); } static inline PyObject* PyLong_FromInt64(int64_t value) { Py_BUILD_ASSERT(sizeof(long long) >= 8); return PyLong_FromLongLong(value); } static inline PyObject* PyLong_FromUInt32(uint32_t value) { Py_BUILD_ASSERT(sizeof(unsigned long) >= 4); return PyLong_FromUnsignedLong(value); } static inline PyObject* PyLong_FromUInt64(uint64_t value) { Py_BUILD_ASSERT(sizeof(unsigned long long) >= 8); return PyLong_FromUnsignedLongLong(value); } static inline int PyLong_AsInt32(PyObject *obj, int32_t *pvalue) { Py_BUILD_ASSERT(sizeof(int) == 4); int value = PyLong_AsInt(obj); if (value == -1 && PyErr_Occurred()) { return -1; } *pvalue = (int32_t)value; return 0; } static inline int PyLong_AsInt64(PyObject *obj, int64_t *pvalue) { Py_BUILD_ASSERT(sizeof(long long) == 8); long long value = PyLong_AsLongLong(obj); if (value == -1 && PyErr_Occurred()) { return -1; } *pvalue = (int64_t)value; return 0; } static inline int PyLong_AsUInt32(PyObject *obj, uint32_t *pvalue) { Py_BUILD_ASSERT(sizeof(long) >= 4); unsigned long value = PyLong_AsUnsignedLong(obj); if (value == (unsigned long)-1 && PyErr_Occurred()) { return -1; } #if SIZEOF_LONG > 4 if ((unsigned long)UINT32_MAX < value) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to C uint32_t"); return -1; } #endif *pvalue = (uint32_t)value; return 0; } static inline int PyLong_AsUInt64(PyObject *obj, uint64_t *pvalue) { Py_BUILD_ASSERT(sizeof(long long) == 8); unsigned long long value = PyLong_AsUnsignedLongLong(obj); if (value == (unsigned long long)-1 && PyErr_Occurred()) { return -1; } *pvalue = (uint64_t)value; return 0; } #endif // gh-102471 added import and export API for integers to 3.14.0a2. #if PY_VERSION_HEX < 0x030E00A2 && PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) // Helpers to access PyLongObject internals. static inline void _PyLong_SetSignAndDigitCount(PyLongObject *op, int sign, Py_ssize_t size) { #if PY_VERSION_HEX >= 0x030C0000 op->long_value.lv_tag = (uintptr_t)(1 - sign) | ((uintptr_t)(size) << 3); #elif PY_VERSION_HEX >= 0x030900A4 Py_SET_SIZE(op, sign * size); #else Py_SIZE(op) = sign * size; #endif } static inline Py_ssize_t _PyLong_DigitCount(const PyLongObject *op) { #if PY_VERSION_HEX >= 0x030C0000 return (Py_ssize_t)(op->long_value.lv_tag >> 3); #else return _PyLong_Sign((PyObject*)op) < 0 ? -Py_SIZE(op) : Py_SIZE(op); #endif } static inline digit* _PyLong_GetDigits(const PyLongObject *op) { #if PY_VERSION_HEX >= 0x030C0000 return (digit*)(op->long_value.ob_digit); #else return (digit*)(op->ob_digit); #endif } typedef struct PyLongLayout { uint8_t bits_per_digit; uint8_t digit_size; int8_t digits_order; int8_t digit_endianness; } PyLongLayout; typedef struct PyLongExport { int64_t value; uint8_t negative; Py_ssize_t ndigits; const void *digits; Py_uintptr_t _reserved; } PyLongExport; typedef struct PyLongWriter PyLongWriter; static inline const PyLongLayout* PyLong_GetNativeLayout(void) { static const PyLongLayout PyLong_LAYOUT = { PyLong_SHIFT, sizeof(digit), -1, // least significant first PY_LITTLE_ENDIAN ? -1 : 1, }; return &PyLong_LAYOUT; } static inline int PyLong_Export(PyObject *obj, PyLongExport *export_long) { if (!PyLong_Check(obj)) { memset(export_long, 0, sizeof(*export_long)); PyErr_Format(PyExc_TypeError, "expected int, got %s", Py_TYPE(obj)->tp_name); return -1; } // Fast-path: try to convert to a int64_t PyLongObject *self = (PyLongObject*)obj; int overflow; #if SIZEOF_LONG == 8 long value = PyLong_AsLongAndOverflow(obj, &overflow); #else // Windows has 32-bit long, so use 64-bit long long instead long long value = PyLong_AsLongLongAndOverflow(obj, &overflow); #endif Py_BUILD_ASSERT(sizeof(value) == sizeof(int64_t)); // the function cannot fail since obj is a PyLongObject assert(!(value == -1 && PyErr_Occurred())); if (!overflow) { export_long->value = value; export_long->negative = 0; export_long->ndigits = 0; export_long->digits = 0; export_long->_reserved = 0; } else { export_long->value = 0; export_long->negative = _PyLong_Sign(obj) < 0; export_long->ndigits = _PyLong_DigitCount(self); if (export_long->ndigits == 0) { export_long->ndigits = 1; } export_long->digits = _PyLong_GetDigits(self); export_long->_reserved = (Py_uintptr_t)Py_NewRef(obj); } return 0; } static inline void PyLong_FreeExport(PyLongExport *export_long) { PyObject *obj = (PyObject*)export_long->_reserved; if (obj) { export_long->_reserved = 0; Py_DECREF(obj); } } static inline PyLongWriter* PyLongWriter_Create(int negative, Py_ssize_t ndigits, void **digits) { if (ndigits <= 0) { PyErr_SetString(PyExc_ValueError, "ndigits must be positive"); return NULL; } assert(digits != NULL); PyLongObject *obj = _PyLong_New(ndigits); if (obj == NULL) { return NULL; } _PyLong_SetSignAndDigitCount(obj, negative?-1:1, ndigits); *digits = _PyLong_GetDigits(obj); return (PyLongWriter*)obj; } static inline void PyLongWriter_Discard(PyLongWriter *writer) { PyLongObject *obj = (PyLongObject *)writer; assert(Py_REFCNT(obj) == 1); Py_DECREF(obj); } static inline PyObject* PyLongWriter_Finish(PyLongWriter *writer) { PyObject *obj = (PyObject *)writer; PyLongObject *self = (PyLongObject*)obj; Py_ssize_t j = _PyLong_DigitCount(self); Py_ssize_t i = j; int sign = _PyLong_Sign(obj); assert(Py_REFCNT(obj) == 1); // Normalize and get singleton if possible while (i > 0 && _PyLong_GetDigits(self)[i-1] == 0) { --i; } if (i != j) { if (i == 0) { sign = 0; } _PyLong_SetSignAndDigitCount(self, sign, i); } if (i <= 1) { long val = sign * (long)(_PyLong_GetDigits(self)[0]); Py_DECREF(obj); return PyLong_FromLong(val); } return obj; } #endif #if PY_VERSION_HEX < 0x030C00A3 # define Py_T_SHORT 0 # define Py_T_INT 1 # define Py_T_LONG 2 # define Py_T_FLOAT 3 # define Py_T_DOUBLE 4 # define Py_T_STRING 5 # define _Py_T_OBJECT 6 # define Py_T_CHAR 7 # define Py_T_BYTE 8 # define Py_T_UBYTE 9 # define Py_T_USHORT 10 # define Py_T_UINT 11 # define Py_T_ULONG 12 # define Py_T_STRING_INPLACE 13 # define Py_T_BOOL 14 # define Py_T_OBJECT_EX 16 # define Py_T_LONGLONG 17 # define Py_T_ULONGLONG 18 # define Py_T_PYSSIZET 19 # if PY_VERSION_HEX >= 0x03000000 && !defined(PYPY_VERSION) # define _Py_T_NONE 20 # endif # define Py_READONLY 1 # define Py_AUDIT_READ 2 # define _Py_WRITE_RESTRICTED 4 #endif // gh-127350 added Py_fopen() and Py_fclose() to Python 3.14a4 #if PY_VERSION_HEX < 0x030E00A4 #if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION) PyAPI_FUNC(FILE*) _Py_fopen_obj(PyObject *path, const char *mode); #endif static inline FILE* Py_fopen(PyObject *path, const char *mode) { #if 0x030400A2 <= PY_VERSION_HEX && !defined(PYPY_VERSION) return _Py_fopen_obj(path, mode); #else FILE *f; PyObject *bytes; #if PY_VERSION_HEX >= 0x03000000 if (!PyUnicode_FSConverter(path, &bytes)) { return NULL; } #else if (!PyString_Check(path)) { PyErr_SetString(PyExc_TypeError, "except str"); return NULL; } bytes = Py_NewRef(path); #endif const char *path_bytes = PyBytes_AS_STRING(bytes); f = fopen(path_bytes, mode); Py_DECREF(bytes); if (f == NULL) { PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path); return NULL; } return f; #endif } static inline int Py_fclose(FILE *file) { return fclose(file); } #endif #if 0x03080000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030E0000 && !defined(PYPY_VERSION) PyAPI_FUNC(const PyConfig*) _Py_GetConfig(void); static inline PyObject* PyConfig_Get(const char *name) { typedef enum { _PyConfig_MEMBER_INT, _PyConfig_MEMBER_UINT, _PyConfig_MEMBER_ULONG, _PyConfig_MEMBER_BOOL, _PyConfig_MEMBER_WSTR, _PyConfig_MEMBER_WSTR_OPT, _PyConfig_MEMBER_WSTR_LIST, } PyConfigMemberType; typedef struct { const char *name; size_t offset; PyConfigMemberType type; const char *sys_attr; } PyConfigSpec; #define PYTHONCAPI_COMPAT_SPEC(MEMBER, TYPE, sys_attr) \ {#MEMBER, offsetof(PyConfig, MEMBER), \ _PyConfig_MEMBER_##TYPE, sys_attr} static const PyConfigSpec config_spec[] = { PYTHONCAPI_COMPAT_SPEC(argv, WSTR_LIST, "argv"), PYTHONCAPI_COMPAT_SPEC(base_exec_prefix, WSTR_OPT, "base_exec_prefix"), PYTHONCAPI_COMPAT_SPEC(base_executable, WSTR_OPT, "_base_executable"), PYTHONCAPI_COMPAT_SPEC(base_prefix, WSTR_OPT, "base_prefix"), PYTHONCAPI_COMPAT_SPEC(bytes_warning, UINT, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(exec_prefix, WSTR_OPT, "exec_prefix"), PYTHONCAPI_COMPAT_SPEC(executable, WSTR_OPT, "executable"), PYTHONCAPI_COMPAT_SPEC(inspect, BOOL, _Py_NULL), #if 0x030C0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(int_max_str_digits, UINT, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(interactive, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(module_search_paths, WSTR_LIST, "path"), PYTHONCAPI_COMPAT_SPEC(optimization_level, UINT, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(parser_debug, BOOL, _Py_NULL), #if 0x03090000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(platlibdir, WSTR, "platlibdir"), #endif PYTHONCAPI_COMPAT_SPEC(prefix, WSTR_OPT, "prefix"), PYTHONCAPI_COMPAT_SPEC(pycache_prefix, WSTR_OPT, "pycache_prefix"), PYTHONCAPI_COMPAT_SPEC(quiet, BOOL, _Py_NULL), #if 0x030B0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(stdlib_dir, WSTR_OPT, "_stdlib_dir"), #endif PYTHONCAPI_COMPAT_SPEC(use_environment, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(verbose, UINT, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(warnoptions, WSTR_LIST, "warnoptions"), PYTHONCAPI_COMPAT_SPEC(write_bytecode, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(xoptions, WSTR_LIST, "_xoptions"), PYTHONCAPI_COMPAT_SPEC(buffered_stdio, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(check_hash_pycs_mode, WSTR, _Py_NULL), #if 0x030B0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(code_debug_ranges, BOOL, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(configure_c_stdio, BOOL, _Py_NULL), #if 0x030D0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(cpu_count, INT, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(dev_mode, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(dump_refs, BOOL, _Py_NULL), #if 0x030B0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(dump_refs_file, WSTR_OPT, _Py_NULL), #endif #ifdef Py_GIL_DISABLED PYTHONCAPI_COMPAT_SPEC(enable_gil, INT, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(faulthandler, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(filesystem_encoding, WSTR, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(filesystem_errors, WSTR, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(hash_seed, ULONG, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(home, WSTR_OPT, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(import_time, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(install_signal_handlers, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(isolated, BOOL, _Py_NULL), #ifdef MS_WINDOWS PYTHONCAPI_COMPAT_SPEC(legacy_windows_stdio, BOOL, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(malloc_stats, BOOL, _Py_NULL), #if 0x030A0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(orig_argv, WSTR_LIST, "orig_argv"), #endif PYTHONCAPI_COMPAT_SPEC(parse_argv, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(pathconfig_warnings, BOOL, _Py_NULL), #if 0x030C0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(perf_profiling, UINT, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(program_name, WSTR, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(run_command, WSTR_OPT, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(run_filename, WSTR_OPT, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(run_module, WSTR_OPT, _Py_NULL), #if 0x030B0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(safe_path, BOOL, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(show_ref_count, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(site_import, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(skip_source_first_line, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(stdio_encoding, WSTR, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(stdio_errors, WSTR, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(tracemalloc, UINT, _Py_NULL), #if 0x030B0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(use_frozen_modules, BOOL, _Py_NULL), #endif PYTHONCAPI_COMPAT_SPEC(use_hash_seed, BOOL, _Py_NULL), PYTHONCAPI_COMPAT_SPEC(user_site_directory, BOOL, _Py_NULL), #if 0x030A0000 <= PY_VERSION_HEX PYTHONCAPI_COMPAT_SPEC(warn_default_encoding, BOOL, _Py_NULL), #endif }; #undef PYTHONCAPI_COMPAT_SPEC const PyConfigSpec *spec; int found = 0; for (size_t i=0; i < sizeof(config_spec) / sizeof(config_spec[0]); i++) { spec = &config_spec[i]; if (strcmp(spec->name, name) == 0) { found = 1; break; } } if (found) { if (spec->sys_attr != NULL) { PyObject *value = PySys_GetObject(spec->sys_attr); if (value == NULL) { PyErr_Format(PyExc_RuntimeError, "lost sys.%s", spec->sys_attr); return NULL; } return Py_NewRef(value); } const PyConfig *config = _Py_GetConfig(); void *member = (char *)config + spec->offset; switch (spec->type) { case _PyConfig_MEMBER_INT: case _PyConfig_MEMBER_UINT: { int value = *(int *)member; return PyLong_FromLong(value); } case _PyConfig_MEMBER_BOOL: { int value = *(int *)member; return PyBool_FromLong(value != 0); } case _PyConfig_MEMBER_ULONG: { unsigned long value = *(unsigned long *)member; return PyLong_FromUnsignedLong(value); } case _PyConfig_MEMBER_WSTR: case _PyConfig_MEMBER_WSTR_OPT: { wchar_t *wstr = *(wchar_t **)member; if (wstr != NULL) { return PyUnicode_FromWideChar(wstr, -1); } else { return Py_NewRef(Py_None); } } case _PyConfig_MEMBER_WSTR_LIST: { const PyWideStringList *list = (const PyWideStringList *)member; PyObject *tuple = PyTuple_New(list->length); if (tuple == NULL) { return NULL; } for (Py_ssize_t i = 0; i < list->length; i++) { PyObject *item = PyUnicode_FromWideChar(list->items[i], -1); if (item == NULL) { Py_DECREF(tuple); return NULL; } PyTuple_SET_ITEM(tuple, i, item); } return tuple; } default: Py_UNREACHABLE(); } } PyErr_Format(PyExc_ValueError, "unknown config option name: %s", name); return NULL; } static inline int PyConfig_GetInt(const char *name, int *value) { PyObject *obj = PyConfig_Get(name); if (obj == NULL) { return -1; } if (!PyLong_Check(obj)) { Py_DECREF(obj); PyErr_Format(PyExc_TypeError, "config option %s is not an int", name); return -1; } int as_int = PyLong_AsInt(obj); Py_DECREF(obj); if (as_int == -1 && PyErr_Occurred()) { PyErr_Format(PyExc_OverflowError, "config option %s value does not fit into a C int", name); return -1; } *value = as_int; return 0; } #endif // PY_VERSION_HEX > 0x03090000 && !defined(PYPY_VERSION) // gh-133144 added PyUnstable_Object_IsUniquelyReferenced() to Python 3.14.0b1. // Adapted from _PyObject_IsUniquelyReferenced() implementation. #if PY_VERSION_HEX < 0x030E00B0 static inline int PyUnstable_Object_IsUniquelyReferenced(PyObject *obj) { #if !defined(Py_GIL_DISABLED) return Py_REFCNT(obj) == 1; #else // NOTE: the entire ob_ref_shared field must be zero, including flags, to // ensure that other threads cannot concurrently create new references to // this object. return (_Py_IsOwnedByCurrentThread(obj) && _Py_atomic_load_uint32_relaxed(&obj->ob_ref_local) == 1 && _Py_atomic_load_ssize_relaxed(&obj->ob_ref_shared) == 0); #endif } #endif // gh-128926 added PyUnstable_TryIncRef() and PyUnstable_EnableTryIncRef() to // Python 3.14.0a5. Adapted from _Py_TryIncref() and _PyObject_SetMaybeWeakref(). #if PY_VERSION_HEX < 0x030E00A5 static inline int PyUnstable_TryIncRef(PyObject *op) { #ifndef Py_GIL_DISABLED if (Py_REFCNT(op) > 0) { Py_INCREF(op); return 1; } return 0; #else // _Py_TryIncrefFast() uint32_t local = _Py_atomic_load_uint32_relaxed(&op->ob_ref_local); local += 1; if (local == 0) { // immortal return 1; } if (_Py_IsOwnedByCurrentThread(op)) { _Py_INCREF_STAT_INC(); _Py_atomic_store_uint32_relaxed(&op->ob_ref_local, local); #ifdef Py_REF_DEBUG _Py_INCREF_IncRefTotal(); #endif return 1; } // _Py_TryIncRefShared() Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared); for (;;) { // If the shared refcount is zero and the object is either merged // or may not have weak references, then we cannot incref it. if (shared == 0 || shared == _Py_REF_MERGED) { return 0; } if (_Py_atomic_compare_exchange_ssize( &op->ob_ref_shared, &shared, shared + (1 << _Py_REF_SHARED_SHIFT))) { #ifdef Py_REF_DEBUG _Py_INCREF_IncRefTotal(); #endif _Py_INCREF_STAT_INC(); return 1; } } #endif } static inline void PyUnstable_EnableTryIncRef(PyObject *op) { #ifdef Py_GIL_DISABLED // _PyObject_SetMaybeWeakref() if (_Py_IsImmortal(op)) { return; } for (;;) { Py_ssize_t shared = _Py_atomic_load_ssize_relaxed(&op->ob_ref_shared); if ((shared & _Py_REF_SHARED_FLAG_MASK) != 0) { // Nothing to do if it's in WEAKREFS, QUEUED, or MERGED states. return; } if (_Py_atomic_compare_exchange_ssize( &op->ob_ref_shared, &shared, shared | _Py_REF_MAYBE_WEAKREF)) { return; } } #else (void)op; // unused argument #endif } #endif #if PY_VERSION_HEX < 0x030F0000 static inline PyObject* PySys_GetAttrString(const char *name) { #if PY_VERSION_HEX >= 0x03000000 PyObject *value = Py_XNewRef(PySys_GetObject(name)); #else PyObject *value = Py_XNewRef(PySys_GetObject((char*)name)); #endif if (value != NULL) { return value; } if (!PyErr_Occurred()) { PyErr_Format(PyExc_RuntimeError, "lost sys.%s", name); } return NULL; } static inline PyObject* PySys_GetAttr(PyObject *name) { #if PY_VERSION_HEX >= 0x03000000 const char *name_str = PyUnicode_AsUTF8(name); #else const char *name_str = PyString_AsString(name); #endif if (name_str == NULL) { return NULL; } return PySys_GetAttrString(name_str); } static inline int PySys_GetOptionalAttrString(const char *name, PyObject **value) { #if PY_VERSION_HEX >= 0x03000000 *value = Py_XNewRef(PySys_GetObject(name)); #else *value = Py_XNewRef(PySys_GetObject((char*)name)); #endif if (*value != NULL) { return 1; } return 0; } static inline int PySys_GetOptionalAttr(PyObject *name, PyObject **value) { #if PY_VERSION_HEX >= 0x03000000 const char *name_str = PyUnicode_AsUTF8(name); #else const char *name_str = PyString_AsString(name); #endif if (name_str == NULL) { *value = NULL; return -1; } return PySys_GetOptionalAttrString(name_str, value); } #endif // PY_VERSION_HEX < 0x030F00A1 #if PY_VERSION_HEX < 0x030F00A1 typedef struct PyBytesWriter { char small_buffer[256]; PyObject *obj; Py_ssize_t size; } PyBytesWriter; static inline Py_ssize_t _PyBytesWriter_GetAllocated(PyBytesWriter *writer) { if (writer->obj == NULL) { return sizeof(writer->small_buffer); } else { return PyBytes_GET_SIZE(writer->obj); } } static inline int _PyBytesWriter_Resize_impl(PyBytesWriter *writer, Py_ssize_t size, int resize) { int overallocate = resize; assert(size >= 0); if (size <= _PyBytesWriter_GetAllocated(writer)) { return 0; } if (overallocate) { #ifdef MS_WINDOWS /* On Windows, overallocate by 50% is the best factor */ if (size <= (PY_SSIZE_T_MAX - size / 2)) { size += size / 2; } #else /* On Linux, overallocate by 25% is the best factor */ if (size <= (PY_SSIZE_T_MAX - size / 4)) { size += size / 4; } #endif } if (writer->obj != NULL) { if (_PyBytes_Resize(&writer->obj, size)) { return -1; } assert(writer->obj != NULL); } else { writer->obj = PyBytes_FromStringAndSize(NULL, size); if (writer->obj == NULL) { return -1; } if (resize) { assert((size_t)size > sizeof(writer->small_buffer)); memcpy(PyBytes_AS_STRING(writer->obj), writer->small_buffer, sizeof(writer->small_buffer)); } } return 0; } static inline void* PyBytesWriter_GetData(PyBytesWriter *writer) { if (writer->obj == NULL) { return writer->small_buffer; } else { return PyBytes_AS_STRING(writer->obj); } } static inline Py_ssize_t PyBytesWriter_GetSize(PyBytesWriter *writer) { return writer->size; } static inline void PyBytesWriter_Discard(PyBytesWriter *writer) { if (writer == NULL) { return; } Py_XDECREF(writer->obj); PyMem_Free(writer); } static inline PyBytesWriter* PyBytesWriter_Create(Py_ssize_t size) { if (size < 0) { PyErr_SetString(PyExc_ValueError, "size must be >= 0"); return NULL; } PyBytesWriter *writer = (PyBytesWriter*)PyMem_Malloc(sizeof(PyBytesWriter)); if (writer == NULL) { PyErr_NoMemory(); return NULL; } writer->obj = NULL; writer->size = 0; if (size >= 1) { if (_PyBytesWriter_Resize_impl(writer, size, 0) < 0) { PyBytesWriter_Discard(writer); return NULL; } writer->size = size; } return writer; } static inline PyObject* PyBytesWriter_FinishWithSize(PyBytesWriter *writer, Py_ssize_t size) { PyObject *result; if (size == 0) { result = PyBytes_FromStringAndSize("", 0); } else if (writer->obj != NULL) { if (size != PyBytes_GET_SIZE(writer->obj)) { if (_PyBytes_Resize(&writer->obj, size)) { goto error; } } result = writer->obj; writer->obj = NULL; } else { result = PyBytes_FromStringAndSize(writer->small_buffer, size); } PyBytesWriter_Discard(writer); return result; error: PyBytesWriter_Discard(writer); return NULL; } static inline PyObject* PyBytesWriter_Finish(PyBytesWriter *writer) { return PyBytesWriter_FinishWithSize(writer, writer->size); } static inline PyObject* PyBytesWriter_FinishWithPointer(PyBytesWriter *writer, void *buf) { Py_ssize_t size = (char*)buf - (char*)PyBytesWriter_GetData(writer); if (size < 0 || size > _PyBytesWriter_GetAllocated(writer)) { PyBytesWriter_Discard(writer); PyErr_SetString(PyExc_ValueError, "invalid end pointer"); return NULL; } return PyBytesWriter_FinishWithSize(writer, size); } static inline int PyBytesWriter_Resize(PyBytesWriter *writer, Py_ssize_t size) { if (size < 0) { PyErr_SetString(PyExc_ValueError, "size must be >= 0"); return -1; } if (_PyBytesWriter_Resize_impl(writer, size, 1) < 0) { return -1; } writer->size = size; return 0; } static inline int PyBytesWriter_Grow(PyBytesWriter *writer, Py_ssize_t size) { if (size < 0 && writer->size + size < 0) { PyErr_SetString(PyExc_ValueError, "invalid size"); return -1; } if (size > PY_SSIZE_T_MAX - writer->size) { PyErr_NoMemory(); return -1; } size = writer->size + size; if (_PyBytesWriter_Resize_impl(writer, size, 1) < 0) { return -1; } writer->size = size; return 0; } static inline void* PyBytesWriter_GrowAndUpdatePointer(PyBytesWriter *writer, Py_ssize_t size, void *buf) { Py_ssize_t pos = (char*)buf - (char*)PyBytesWriter_GetData(writer); if (PyBytesWriter_Grow(writer, size) < 0) { return NULL; } return (char*)PyBytesWriter_GetData(writer) + pos; } static inline int PyBytesWriter_WriteBytes(PyBytesWriter *writer, const void *bytes, Py_ssize_t size) { if (size < 0) { size_t len = strlen((const char*)bytes); if (len > (size_t)PY_SSIZE_T_MAX) { PyErr_NoMemory(); return -1; } size = (Py_ssize_t)len; } Py_ssize_t pos = writer->size; if (PyBytesWriter_Grow(writer, size) < 0) { return -1; } char *buf = (char*)PyBytesWriter_GetData(writer); memcpy(buf + pos, bytes, (size_t)size); return 0; } static inline int PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) Py_GCC_ATTRIBUTE((format(printf, 2, 3))); static inline int PyBytesWriter_Format(PyBytesWriter *writer, const char *format, ...) { va_list vargs; va_start(vargs, format); PyObject *str = PyBytes_FromFormatV(format, vargs); va_end(vargs); if (str == NULL) { return -1; } int res = PyBytesWriter_WriteBytes(writer, PyBytes_AS_STRING(str), PyBytes_GET_SIZE(str)); Py_DECREF(str); return res; } #endif // PY_VERSION_HEX < 0x030F00A1 #if PY_VERSION_HEX < 0x030F00A1 static inline PyObject* PyTuple_FromArray(PyObject *const *array, Py_ssize_t size) { PyObject *tuple = PyTuple_New(size); if (tuple == NULL) { return NULL; } for (Py_ssize_t i=0; i < size; i++) { PyObject *item = array[i]; PyTuple_SET_ITEM(tuple, i, Py_NewRef(item)); } return tuple; } #endif #if PY_VERSION_HEX < 0x030F00A1 static inline Py_hash_t PyUnstable_Unicode_GET_CACHED_HASH(PyObject *op) { #ifdef PYPY_VERSION (void)op; // unused argument return -1; #elif PY_VERSION_HEX >= 0x03000000 return ((PyASCIIObject*)op)->hash; #else return ((PyUnicodeObject*)op)->hash; #endif } #endif #if 0x030D0000 <= PY_VERSION_HEX && PY_VERSION_HEX < 0x030F00A7 && !defined(PYPY_VERSION) // Immortal objects were implemented in Python 3.12, however there is no easy API // to make objects immortal until 3.14 which has _Py_SetImmortal(). Since // immortal objects are primarily needed for free-threading, this API is implemented // for 3.14 using _Py_SetImmortal() and uses private macros on 3.13. #if 0x030E0000 <= PY_VERSION_HEX PyAPI_FUNC(void) _Py_SetImmortal(PyObject *op); #endif static inline int PyUnstable_SetImmortal(PyObject *op) { assert(op != NULL); if (!PyUnstable_Object_IsUniquelyReferenced(op) || PyUnicode_Check(op)) { return 0; } #if 0x030E0000 <= PY_VERSION_HEX _Py_SetImmortal(op); #else // Python 3.13 doesn't export _Py_SetImmortal() function if (PyObject_GC_IsTracked(op)) { PyObject_GC_UnTrack(op); } #ifdef Py_GIL_DISABLED op->ob_tid = _Py_UNOWNED_TID; op->ob_ref_local = _Py_IMMORTAL_REFCNT_LOCAL; op->ob_ref_shared = 0; #else op->ob_refcnt = _Py_IMMORTAL_REFCNT; #endif #endif return 1; } #endif #ifdef __cplusplus } #endif #endif // PYTHONCAPI_COMPAT ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/pythonsupport.c0000644000175100017510000001220415200142331015463 0ustar00runnerrunner// 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 #include "pythonsupport.h" ///////////////////////////////////////// // Adapted from bltinmodule.c in Python 3.7.0 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_GetOptionalAttr(base, mypyc_interned_str.__mro_entries__, &meth) < 0) { goto error; } if (!meth) { if (new_bases) { if (PyList_Append(new_bases, base) < 0) { goto error; } } continue; } new_base = PyObject_Vectorcall(meth, stack, 1, NULL); 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; } // From Python 3.7's typeobject.c int init_subclass(PyTypeObject *type, PyObject *kwds) { PyObject *super, *func, *result; PyObject *args[2] = {(PyObject *)type, (PyObject *)type}; super = PyObject_Vectorcall((PyObject *)&PySuper_Type, args, 2, NULL); if (super == NULL) { return -1; } func = PyObject_GetAttr(super, mypyc_interned_str.__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; } #if CPY_3_12_FEATURES // Slow path of CPyLong_AsSsize_tAndOverflow (non-inlined) Py_ssize_t CPyLong_AsSsize_tAndOverflow_(PyObject *vv, int *overflow) { PyLongObject *v = (PyLongObject *)vv; size_t x, prev; Py_ssize_t res; Py_ssize_t i; int sign; *overflow = 0; res = -1; i = CPY_LONG_TAG(v); sign = 1; x = 0; if (i & CPY_SIGN_NEGATIVE) { sign = -1; } i >>= CPY_NON_SIZE_BITS; while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + CPY_LONG_DIGIT(v, i); if ((x >> PyLong_SHIFT) != prev) { *overflow = sign; goto exit; } } /* Haven't lost any bits, but casting to long requires extra * care. */ 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; } #else // Slow path of CPyLong_AsSsize_tAndOverflow (non-inlined, Python 3.11 and earlier) 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); sign = 1; x = 0; if (i < 0) { sign = -1; i = -(i); } while (--i >= 0) { prev = x; x = (x << PyLong_SHIFT) + CPY_LONG_DIGIT(v, i); if ((x >> PyLong_SHIFT) != prev) { *overflow = sign; goto exit; } } /* Haven't lost any bits, but casting to long requires extra * care. */ 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; } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/pythonsupport.h0000644000175100017510000002412015200142331015470 0ustar00runnerrunner// 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 #include #include "pythoncapi_compat.h" #include #include #include "static_data.h" #include "mypyc_util.h" #if CPY_3_13_FEATURES #ifndef Py_BUILD_CORE #define Py_BUILD_CORE #endif #include "internal/pycore_genobject.h" // _PyGen_FetchStopIterationValue #include "internal/pycore_pyerrors.h" // _PyErr_FormatFromCause, _PyErr_SetKeyError #include "internal/pycore_setobject.h" // _PySet_Update #endif #if CPY_3_12_FEATURES #include "internal/pycore_frame.h" #endif #ifdef __cplusplus extern "C" { #endif #if 0 } // why isn't emacs smart enough to not indent this #endif PyObject* update_bases(PyObject *bases); int init_subclass(PyTypeObject *type, PyObject *kwds); Py_ssize_t CPyLong_AsSsize_tAndOverflow_(PyObject *vv, int *overflow); #if CPY_3_12_FEATURES static inline Py_ssize_t CPyLong_AsSsize_tAndOverflow(PyObject *vv, int *overflow) { /* This version by Tim Peters */ PyLongObject *v = (PyLongObject *)vv; Py_ssize_t res; Py_ssize_t i; *overflow = 0; res = -1; i = CPY_LONG_TAG(v); // TODO: Combine zero and non-zero cases helow? if (likely(i == (1 << CPY_NON_SIZE_BITS))) { res = CPY_LONG_DIGIT(v, 0); } else if (likely(i == CPY_SIGN_ZERO)) { res = 0; } else if (i == ((1 << CPY_NON_SIZE_BITS) | CPY_SIGN_NEGATIVE)) { res = -(sdigit)CPY_LONG_DIGIT(v, 0); } else { // Slow path is moved to a non-inline helper function to // limit size of generated code int overflow_local; res = CPyLong_AsSsize_tAndOverflow_(vv, &overflow_local); *overflow = overflow_local; } return res; } #else // 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; Py_ssize_t res; Py_ssize_t i; *overflow = 0; res = -1; i = Py_SIZE(v); if (likely(i == 1)) { res = CPY_LONG_DIGIT(v, 0); } else if (likely(i == 0)) { res = 0; } else if (i == -1) { res = -(sdigit)CPY_LONG_DIGIT(v, 0); } else { // Slow path is moved to a non-inline helper function to // limit size of generated code int overflow_local; res = CPyLong_AsSsize_tAndOverflow_(vv, &overflow_local); *overflow = overflow_local; } return res; } #endif // 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); } // 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_CallOneArg 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_CallOneArg(PyExc_StopIteration, value); 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 CPY_3_12_FEATURES // These are copied from genobject.c in Python 3.12 static int gen_is_coroutine(PyObject *o) { if (PyGen_CheckExact(o)) { PyCodeObject *code = PyGen_GetCode((PyGenObject*)o); if (code->co_flags & CO_ITERABLE_COROUTINE) { return 1; } } return 0; } #else // Copied from genobject.c in Python 3.10 static int gen_is_coroutine(PyObject *o) { if (PyGen_CheckExact(o)) { PyCodeObject *code = (PyCodeObject *)((PyGenObject*)o)->gi_code; if (code->co_flags & CO_ITERABLE_COROUTINE) { return 1; } } return 0; } #endif /* * This helper function returns an awaitable for `o`: * - `o` if `o` is a coroutine-object; * - `type(o)->tp_as_async->am_await(o)` * * Raises a TypeError if it's not possible to return * an awaitable and returns NULL. */ static PyObject * CPyCoro_GetAwaitableIter(PyObject *o) { unaryfunc getter = NULL; PyTypeObject *ot; if (PyCoro_CheckExact(o) || gen_is_coroutine(o)) { /* 'o' is a coroutine. */ Py_INCREF(o); return o; } ot = Py_TYPE(o); if (ot->tp_as_async != NULL) { getter = ot->tp_as_async->am_await; } if (getter != NULL) { PyObject *res = (*getter)(o); if (res != NULL) { if (PyCoro_CheckExact(res) || gen_is_coroutine(res)) { /* __await__ must return an *iterator*, not a coroutine or another awaitable (see PEP 492) */ PyErr_SetString(PyExc_TypeError, "__await__() returned a coroutine"); Py_CLEAR(res); } else if (!PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, "__await__() returned non-iterator " "of type '%.100s'", Py_TYPE(res)->tp_name); Py_CLEAR(res); } } return res; } PyErr_Format(PyExc_TypeError, "object %.100s can't be used in 'await' expression", ot->tp_name); return NULL; } #endif ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8578358 librt-0.11.0/random/0000755000175100017510000000000015200142335013626 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/random/librt_random.c0000644000175100017510000005227715200142331016457 0ustar00runnerrunner#include "pythoncapi_compat.h" #define PY_SSIZE_T_CLEAN #include #include #include #ifdef _WIN32 #include #else #include #endif #include "mypyc_util.h" #include "CPy.h" #include "librt_random.h" // // ChaCha8 PRNG with forward secrecy // #define CHACHA8_RESEED_INTERVAL 16 typedef struct { uint32_t seed[8]; // 256-bit key uint32_t buf[16]; // output buffer: one ChaCha8 block uint32_t counter; // block counter uint8_t used; // index into buf uint8_t n; // usable values in buf (8 or 16) uint8_t blocks_left; // blocks until next reseed } chacha8_rng; static inline uint32_t rotl32(uint32_t x, int n) { return (x << n) | (x >> (32 - n)); } #define QUARTERROUND(a, b, c, d) \ do { \ a += b; d ^= a; d = rotl32(d, 16); \ c += d; b ^= c; b = rotl32(b, 12); \ a += b; d ^= a; d = rotl32(d, 8); \ c += d; b ^= c; b = rotl32(b, 7); \ } while (0) static void chacha8_block(const uint32_t seed[8], uint32_t counter, uint32_t out[16]) { // "expand 32-byte k" uint32_t s[16] = { 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574, seed[0], seed[1], seed[2], seed[3], seed[4], seed[5], seed[6], seed[7], counter, 0, 0, 0 // counter (low 32), counter (high 32), nonce }; memcpy(out, s, sizeof(uint32_t) * 16); // 4 double-rounds = 8 rounds for (int i = 0; i < 4; i++) { // Column rounds QUARTERROUND(out[0], out[4], out[ 8], out[12]); QUARTERROUND(out[1], out[5], out[ 9], out[13]); QUARTERROUND(out[2], out[6], out[10], out[14]); QUARTERROUND(out[3], out[7], out[11], out[15]); // Diagonal rounds QUARTERROUND(out[0], out[5], out[10], out[15]); QUARTERROUND(out[1], out[6], out[11], out[12]); QUARTERROUND(out[2], out[7], out[ 8], out[13]); QUARTERROUND(out[3], out[4], out[ 9], out[14]); } // Add original state back (standard ChaCha finalization) for (int i = 0; i < 16; i++) out[i] += s[i]; } // Fill entropy from OS via os.urandom(), which handles short reads, // EINTR, and platform differences internally. // Returns 0 on success, -1 on failure (with Python exception set). static int fill_os_entropy(void *buf, size_t len) { PyObject *os_mod = PyImport_ImportModule("os"); if (os_mod == NULL) return -1; PyObject *bytes = PyObject_CallMethod(os_mod, "urandom", "n", (Py_ssize_t)len); Py_DECREF(os_mod); if (bytes == NULL) return -1; memcpy(buf, PyBytes_AS_STRING(bytes), len); Py_DECREF(bytes); return 0; } static void chacha8_refill(chacha8_rng *rng) { chacha8_block(rng->seed, rng->counter, rng->buf); rng->counter++; rng->used = 0; rng->blocks_left--; if (unlikely(rng->blocks_left == 0)) { // Forward secrecy reseed: steal last 8 words as new key memcpy(rng->seed, rng->buf + 8, sizeof(uint32_t) * 8); rng->n = 8; // only 8 words usable this block rng->counter = 0; rng->blocks_left = CHACHA8_RESEED_INTERVAL; } else { rng->n = 16; } } static inline uint32_t chacha8_next(chacha8_rng *rng) { if (unlikely(rng->used >= rng->n)) chacha8_refill(rng); return rng->buf[rng->used++]; } // Return 64 bits of randomness (two consecutive 32-bit words, single bounds check). static inline uint64_t chacha8_next64(chacha8_rng *rng) { // Need 2 words available; if fewer than 2, refill first. if (unlikely(rng->used + 1 >= rng->n)) // Use two separate calls to handle block boundary correctly. return ((uint64_t)chacha8_next(rng) << 32) | chacha8_next(rng); uint32_t hi = rng->buf[rng->used++]; uint32_t lo = rng->buf[rng->used++]; return ((uint64_t)hi << 32) | lo; } // Return a uniformly distributed random value in [0, range). // Use Lemire's nearly divisionless method for small ranges, and a portable // rejection sampler for larger ranges to avoid non-standard 128-bit arithmetic. static inline uint64_t chacha8_next_ranged(chacha8_rng *rng, uint64_t range) { assert(range != 0); if (likely(range <= UINT32_MAX)) { // 32-bit Lemire: multiply r * range to get 64-bit product, // upper 32 bits are the result in [0, range). uint64_t m = (uint64_t)chacha8_next(rng) * range; uint32_t lo = (uint32_t)m; if (unlikely(lo < range)) { uint32_t thresh = (uint32_t)(-(uint32_t)range) % (uint32_t)range; while (lo < thresh) { m = (uint64_t)chacha8_next(rng) * range; lo = (uint32_t)m; } } return m >> 32; } // If range is a power of two, masking produces an unbiased result. if ((range & (range - 1)) == 0) { return chacha8_next64(rng) & (range - 1); } uint64_t r; // In unsigned arithmetic, -range is 2**64 - range, so this computes // 2**64 % range. Rejecting values below this threshold leaves exactly // floor(2**64 / range) full buckets of size range, avoiding modulo bias. uint64_t thresh = -range % range; do { r = chacha8_next64(rng); } while (unlikely(r < thresh)); return r % range; } // Return a random i64 starting at 'start', with 'range' possible values. // A zero range represents the full 2**64 i64 domain. static inline int64_t random_i64_from_range(chacha8_rng *rng, int64_t start, uint64_t range) { uint64_t offset = range == 0 ? chacha8_next64(rng) : chacha8_next_ranged(rng, range); return (int64_t)((uint64_t)start + offset); } static void chacha8_reset(chacha8_rng *rng) { rng->counter = 0; rng->used = 16; // force immediate refill on first call rng->n = 16; rng->blocks_left = CHACHA8_RESEED_INTERVAL; } static int chacha8_init(chacha8_rng *rng) { if (fill_os_entropy(rng->seed, sizeof(rng->seed)) < 0) return -1; chacha8_reset(rng); return 0; } // Seed from an integer by hashing it through ChaCha8 to fill the 256-bit key. static void chacha8_seed_int(chacha8_rng *rng, int64_t seed_val) { // Use the integer to construct a simple initial key, then run one // ChaCha8 block to diffuse it across all 256 bits. memset(rng->seed, 0, sizeof(rng->seed)); rng->seed[0] = (uint32_t)(seed_val & 0xFFFFFFFF); rng->seed[1] = (uint32_t)((uint64_t)seed_val >> 32); uint32_t out[16]; chacha8_block(rng->seed, 0, out); memcpy(rng->seed, out, sizeof(rng->seed)); chacha8_reset(rng); } // // Thread-local global RNG for module-level random()/randint() // // thread_local pointer for fast access (direct %fs/%gs-relative load), // platform TLS key with destructor for cleanup on thread exit. // #ifdef _WIN32 static __declspec(thread) chacha8_rng *tls_rng = NULL; #else static __thread chacha8_rng *tls_rng = NULL; #endif #ifdef _WIN32 static DWORD tls_key = FLS_OUT_OF_INDEXES; static void NTAPI tls_rng_destructor(void *ptr) { if (ptr != NULL) { memset(ptr, 0, sizeof(chacha8_rng)); PyMem_RawFree(ptr); } } #else static pthread_key_t tls_key; static void tls_rng_destructor(void *ptr) { if (ptr != NULL) { memset(ptr, 0, sizeof(chacha8_rng)); PyMem_RawFree(ptr); } } #endif static int tls_key_created = 0; static int ensure_tls_key(void) { if (likely(tls_key_created)) return 0; #ifdef _WIN32 tls_key = FlsAlloc(tls_rng_destructor); if (tls_key == FLS_OUT_OF_INDEXES) { PyErr_SetString(PyExc_OSError, "FlsAlloc failed"); return -1; } #else if (pthread_key_create(&tls_key, tls_rng_destructor) != 0) { PyErr_SetString(PyExc_OSError, "pthread_key_create failed"); return -1; } #endif tls_key_created = 1; return 0; } // Get the thread-local RNG, initializing on first use. // Returns NULL with Python exception set on failure. static inline chacha8_rng * get_thread_rng(void) { chacha8_rng *rng = tls_rng; if (likely(rng != NULL)) return rng; // First use on this thread — allocate and seed rng = PyMem_RawMalloc(sizeof(chacha8_rng)); if (rng == NULL) { PyErr_NoMemory(); return NULL; } if (chacha8_init(rng) < 0) { PyMem_RawFree(rng); return NULL; } // Register with platform TLS for destructor #ifdef _WIN32 FlsSetValue(tls_key, rng); #else pthread_setspecific(tls_key, rng); #endif tls_rng = rng; return rng; } // Return a random double in [0.0, 1.0) with 53 bits of mantissa precision. static inline double random_double_impl(chacha8_rng *rng) { uint64_t r = chacha8_next64(rng); return (double)(r >> 11) * (1.0 / 9007199254740992.0); // 1/2^53 } // // Module-level random() and randint() // static PyObject* module_random(PyObject *module, PyObject *Py_UNUSED(ignored)) { chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return NULL; return PyFloat_FromDouble(random_double_impl(rng)); } // Generate random integer in [a, b] using the given RNG. static inline PyObject* randint_impl(chacha8_rng *rng, int64_t a, int64_t b) { uint64_t range = (uint64_t)b - (uint64_t)a + 1; return PyLong_FromLongLong(random_i64_from_range(rng, a, range)); } static PyObject* module_randint(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 2) { PyErr_Format(PyExc_TypeError, "randint() takes exactly 2 arguments (%zd given)", nargs); return NULL; } int64_t a = CPyLong_AsInt64(args[0]); if (unlikely(a == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; int64_t b = CPyLong_AsInt64(args[1]); if (unlikely(b == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (a > b) { PyErr_SetString(PyExc_ValueError, "empty range for randint()"); return NULL; } chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return NULL; return randint_impl(rng, a, b); } // Parse 1 or 2 int args for randrange([start,] stop). // Sets *a to start (default 0), *b to stop-1. // Returns 0 on success, -1 on error (with exception set). static int parse_randrange_args(PyObject *const *args, Py_ssize_t nargs, int64_t *a, int64_t *b) { if (nargs == 1) { *a = 0; int64_t stop = CPyLong_AsInt64(args[0]); if (unlikely(stop == CPY_LL_INT_ERROR && PyErr_Occurred())) return -1; if (stop <= 0) { PyErr_SetString(PyExc_ValueError, "empty range for randrange()"); return -1; } *b = stop - 1; } else if (nargs == 2) { *a = CPyLong_AsInt64(args[0]); if (unlikely(*a == CPY_LL_INT_ERROR && PyErr_Occurred())) return -1; int64_t stop = CPyLong_AsInt64(args[1]); if (unlikely(stop == CPY_LL_INT_ERROR && PyErr_Occurred())) return -1; if (*a >= stop) { PyErr_SetString(PyExc_ValueError, "empty range for randrange()"); return -1; } *b = stop - 1; } else { PyErr_Format(PyExc_TypeError, "randrange() takes 1 or 2 arguments (%zd given)", nargs); return -1; } return 0; } static PyObject* module_randrange(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { int64_t a, b; if (parse_randrange_args(args, nargs, &a, &b) < 0) return NULL; chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return NULL; return randint_impl(rng, a, b); } static PyObject* module_seed(PyObject *module, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 1) { PyErr_Format(PyExc_TypeError, "seed() takes exactly 1 argument (%zd given)", nargs); return NULL; } int64_t seed_val = CPyLong_AsInt64(args[0]); if (unlikely(seed_val == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return NULL; chacha8_seed_int(rng, seed_val); Py_RETURN_NONE; } // // Random Python type // typedef struct { PyObject_HEAD chacha8_rng rng; } RandomObject; static PyTypeObject RandomType; static PyObject* Random_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { if (type != &RandomType) { PyErr_SetString(PyExc_TypeError, "Random cannot be subclassed"); return NULL; } RandomObject *self = (RandomObject *)type->tp_alloc(type, 0); // Seeding is done in tp_init return (PyObject *)self; } static int Random_init(RandomObject *self, PyObject *args, PyObject *kwds) { PyObject *seed_obj = NULL; if (!PyArg_ParseTuple(args, "|O", &seed_obj)) { return -1; } if (kwds != NULL && PyDict_Size(kwds) > 0) { PyErr_SetString(PyExc_TypeError, "Random() takes no keyword arguments"); return -1; } if (seed_obj == NULL || seed_obj == Py_None) { if (chacha8_init(&self->rng) < 0) return -1; } else { int64_t seed_val = CPyLong_AsInt64(seed_obj); if (unlikely(seed_val == CPY_LL_INT_ERROR && PyErr_Occurred())) return -1; chacha8_seed_int(&self->rng, seed_val); } return 0; } // Internal constructors for capsule API (bypass tp_new/tp_init) static PyObject * Random_internal(void) { RandomObject *self = (RandomObject *)RandomType.tp_alloc(&RandomType, 0); if (self == NULL) return NULL; if (chacha8_init(&self->rng) < 0) { Py_DECREF(self); return NULL; } return (PyObject *)self; } static PyObject * Random_from_seed_internal(int64_t seed_val) { RandomObject *self = (RandomObject *)RandomType.tp_alloc(&RandomType, 0); if (self == NULL) return NULL; chacha8_seed_int(&self->rng, seed_val); return (PyObject *)self; } static PyTypeObject * Random_type_internal(void) { return &RandomType; } static int64_t Random_randrange1_internal(PyObject *self, int64_t stop) { if (unlikely(stop <= 0)) { PyErr_SetString(PyExc_ValueError, "empty range for randrange()"); return CPY_LL_INT_ERROR; } return (int64_t)chacha8_next_ranged(&((RandomObject *)self)->rng, (uint64_t)stop); } static int64_t Random_randrange2_internal(PyObject *self, int64_t start, int64_t stop) { if (unlikely(start >= stop)) { PyErr_SetString(PyExc_ValueError, "empty range for randrange()"); return CPY_LL_INT_ERROR; } uint64_t range = (uint64_t)stop - (uint64_t)start; return random_i64_from_range(&((RandomObject *)self)->rng, start, range); } static int64_t Random_randint_internal(PyObject *self, int64_t a, int64_t b) { if (unlikely(a > b)) { PyErr_SetString(PyExc_ValueError, "empty range for randint()"); return CPY_LL_INT_ERROR; } uint64_t range = (uint64_t)b - (uint64_t)a + 1; return random_i64_from_range(&((RandomObject *)self)->rng, a, range); } static double Random_random_internal(PyObject *self) { return random_double_impl(&((RandomObject *)self)->rng); } static PyObject* Random_randint(RandomObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 2) { PyErr_Format(PyExc_TypeError, "randint() takes exactly 2 arguments (%zd given)", nargs); return NULL; } int64_t a = CPyLong_AsInt64(args[0]); if (unlikely(a == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; int64_t b = CPyLong_AsInt64(args[1]); if (unlikely(b == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (a > b) { PyErr_SetString(PyExc_ValueError, "empty range for randint()"); return NULL; } return randint_impl(&self->rng, a, b); } static PyObject* Random_randrange(RandomObject *self, PyObject *const *args, Py_ssize_t nargs) { int64_t a, b; if (parse_randrange_args(args, nargs, &a, &b) < 0) return NULL; return randint_impl(&self->rng, a, b); } static PyObject* Random_random(RandomObject *self, PyObject *Py_UNUSED(ignored)) { return PyFloat_FromDouble(random_double_impl(&self->rng)); } static PyObject* Random_seed(RandomObject *self, PyObject *const *args, Py_ssize_t nargs) { if (nargs != 1) { PyErr_Format(PyExc_TypeError, "seed() takes exactly 1 argument (%zd given)", nargs); return NULL; } int64_t seed_val = CPyLong_AsInt64(args[0]); if (unlikely(seed_val == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; chacha8_seed_int(&self->rng, seed_val); Py_RETURN_NONE; } static PyMethodDef Random_methods[] = { {"randint", (PyCFunction) Random_randint, METH_FASTCALL, PyDoc_STR("Return random integer in range [a, b], including both end points.") }, {"randrange", (PyCFunction) Random_randrange, METH_FASTCALL, PyDoc_STR("Return random integer in range [start, stop).") }, {"random", (PyCFunction) Random_random, METH_NOARGS, PyDoc_STR("Return random float in [0.0, 1.0).") }, {"seed", (PyCFunction) Random_seed, METH_FASTCALL, PyDoc_STR("Seed the random number generator with an integer.") }, {NULL} /* Sentinel */ }; static PyTypeObject RandomType = { .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "Random", .tp_doc = PyDoc_STR("Fast random number generator using ChaCha8"), .tp_basicsize = sizeof(RandomObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = Random_new, .tp_init = (initproc) Random_init, .tp_methods = Random_methods, }; // Module definition static PyMethodDef librt_random_module_methods[] = { {"random", (PyCFunction) module_random, METH_NOARGS, PyDoc_STR("Return random float in [0.0, 1.0) using thread-local RNG.") }, {"randint", (PyCFunction) module_randint, METH_FASTCALL, PyDoc_STR("Return random integer in range [a, b] using thread-local RNG.") }, {"randrange", (PyCFunction) module_randrange, METH_FASTCALL, PyDoc_STR("Return random integer in range [start, stop) using thread-local RNG.") }, {"seed", (PyCFunction) module_seed, METH_FASTCALL, PyDoc_STR("Seed the thread-local RNG with an integer.") }, {NULL, NULL, 0, NULL} }; // Module-level internal functions for mypyc primitives (use thread-local RNG) static double module_random_internal(void) { chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return CPY_FLOAT_ERROR; return random_double_impl(rng); } static int64_t module_randint_internal(int64_t a, int64_t b) { if (unlikely(a > b)) { PyErr_SetString(PyExc_ValueError, "empty range for randint()"); return CPY_LL_INT_ERROR; } chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return CPY_LL_INT_ERROR; uint64_t range = (uint64_t)b - (uint64_t)a + 1; return random_i64_from_range(rng, a, range); } static int64_t module_randrange1_internal(int64_t stop) { if (unlikely(stop <= 0)) { PyErr_SetString(PyExc_ValueError, "empty range for randrange()"); return CPY_LL_INT_ERROR; } chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return CPY_LL_INT_ERROR; return (int64_t)chacha8_next_ranged(rng, (uint64_t)stop); } static int64_t module_randrange2_internal(int64_t start, int64_t stop) { if (unlikely(start >= stop)) { PyErr_SetString(PyExc_ValueError, "empty range for randrange()"); return CPY_LL_INT_ERROR; } chacha8_rng *rng = get_thread_rng(); if (rng == NULL) return CPY_LL_INT_ERROR; uint64_t range = (uint64_t)stop - (uint64_t)start; return random_i64_from_range(rng, start, range); } static int random_abi_version(void) { return LIBRT_RANDOM_ABI_VERSION; } static int random_api_version(void) { return LIBRT_RANDOM_API_VERSION; } static int librt_random_module_exec(PyObject *m) { if (ensure_tls_key() < 0) { return -1; } if (PyType_Ready(&RandomType) < 0) { return -1; } if (PyModule_AddObjectRef(m, "Random", (PyObject *) &RandomType) < 0) { return -1; } // Export mypyc internal C API via capsule static void *librt_random_api[LIBRT_RANDOM_API_LEN] = { (void *)random_abi_version, (void *)random_api_version, (void *)Random_internal, (void *)Random_from_seed_internal, (void *)Random_type_internal, (void *)Random_random_internal, (void *)Random_randint_internal, (void *)Random_randrange1_internal, (void *)Random_randrange2_internal, (void *)module_random_internal, (void *)module_randint_internal, (void *)module_randrange1_internal, (void *)module_randrange2_internal, }; PyObject *c_api_object = PyCapsule_New((void *)librt_random_api, "librt.random._C_API", NULL); if (PyModule_Add(m, "_C_API", c_api_object) < 0) { return -1; } return 0; } static PyModuleDef_Slot librt_random_module_slots[] = { {Py_mod_exec, librt_random_module_exec}, #ifdef Py_MOD_GIL_NOT_USED {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} }; static PyModuleDef librt_random_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "random", .m_doc = "Fast random number generation using ChaCha8", .m_size = 0, .m_methods = librt_random_module_methods, .m_slots = librt_random_module_slots, }; PyMODINIT_FUNC PyInit_random(void) { return PyModuleDef_Init(&librt_random_module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/random/librt_random.h0000644000175100017510000000030515200142331016445 0ustar00runnerrunner#ifndef LIBRT_RANDOM_H #define LIBRT_RANDOM_H #include #define LIBRT_RANDOM_ABI_VERSION 1 #define LIBRT_RANDOM_API_VERSION 9 #define LIBRT_RANDOM_API_LEN 13 #endif // LIBRT_RANDOM_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/random/librt_random_api.c0000644000175100017510000000307215200142331017275 0ustar00runnerrunner#include #include "librt_random_api.h" void *LibRTRandom_API[LIBRT_RANDOM_API_LEN] = {0}; int import_librt_random(void) { PyObject *mod = PyImport_ImportModule("librt.random"); if (mod == NULL) return -1; Py_DECREF(mod); // we import just for the side effect of making the below work. void **capsule = (void **)PyCapsule_Import("librt.random._C_API", 0); if (capsule == NULL) return -1; // Only after version validation succeeds can we safely copy the full table. int (*abi_version)(void) = (int (*)(void))capsule[0]; int (*api_version)(void) = (int (*)(void))capsule[1]; if (abi_version() != LIBRT_RANDOM_ABI_VERSION) { char err[128]; snprintf(err, sizeof(err), "ABI version conflict for librt.random, expected %d, found %d", LIBRT_RANDOM_ABI_VERSION, abi_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } if (api_version() < LIBRT_RANDOM_API_VERSION) { char err[128]; snprintf(err, sizeof(err), "API version conflict for librt.random, expected %d or newer, found %d (hint: upgrade librt)", LIBRT_RANDOM_API_VERSION, api_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } // Provider API version is >= our expected version, which (by the API // compatibility contract) means it has at least LIBRT_RANDOM_API_LEN // entries, so this copy is safe. memcpy(LibRTRandom_API, capsule, sizeof(LibRTRandom_API)); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/random/librt_random_api.h0000644000175100017510000000304015200142331017275 0ustar00runnerrunner#ifndef LIBRT_RANDOM_API_H #define LIBRT_RANDOM_API_H #include #include #include #include "librt_random.h" int import_librt_random(void); extern void *LibRTRandom_API[LIBRT_RANDOM_API_LEN]; #define LibRTRandom_ABIVersion (*(int (*)(void)) LibRTRandom_API[0]) #define LibRTRandom_APIVersion (*(int (*)(void)) LibRTRandom_API[1]) #define LibRTRandom_Random_internal (*(PyObject* (*)(void)) LibRTRandom_API[2]) #define LibRTRandom_Random_from_seed_internal (*(PyObject* (*)(int64_t)) LibRTRandom_API[3]) #define LibRTRandom_Random_type_internal (*(PyTypeObject* (*)(void)) LibRTRandom_API[4]) #define LibRTRandom_Random_random_internal (*(double (*)(PyObject*)) LibRTRandom_API[5]) #define LibRTRandom_Random_randint_internal (*(int64_t (*)(PyObject*, int64_t, int64_t)) LibRTRandom_API[6]) #define LibRTRandom_Random_randrange1_internal (*(int64_t (*)(PyObject*, int64_t)) LibRTRandom_API[7]) #define LibRTRandom_Random_randrange2_internal (*(int64_t (*)(PyObject*, int64_t, int64_t)) LibRTRandom_API[8]) #define LibRTRandom_module_random_internal (*(double (*)(void)) LibRTRandom_API[9]) #define LibRTRandom_module_randint_internal (*(int64_t (*)(int64_t, int64_t)) LibRTRandom_API[10]) #define LibRTRandom_module_randrange1_internal (*(int64_t (*)(int64_t)) LibRTRandom_API[11]) #define LibRTRandom_module_randrange2_internal (*(int64_t (*)(int64_t, int64_t)) LibRTRandom_API[12]) static inline bool CPyRandom_Check(PyObject *obj) { return Py_TYPE(obj) == LibRTRandom_Random_type_internal(); } #endif // LIBRT_RANDOM_API_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/set_ops.c0000644000175100017510000000053715200142331014167 0ustar00runnerrunner// Set primitive operations // // These are registered in mypyc.primitives.set_ops. #include #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; } ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1778435292.863016 librt-0.11.0/setup.cfg0000644000175100017510000000004615200142335014167 0ustar00runnerrunner[egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/setup.py0000644000175100017510000001237115200142331014060 0ustar00runnerrunner"""Build script for mypyc C runtime library and C API unit tests. The tests are written in C++ and use the Google Test framework. """ from __future__ import annotations import os import subprocess import sys from distutils import ccompiler, sysconfig from typing import Any # we'll import stuff from the source tree, let's ensure is on the sys path sys.path.insert(0, os.path.dirname(os.path.realpath(__file__))) import build_setup # noqa: F401 from setuptools import Extension, setup from setuptools.command.build_ext import build_ext C_APIS_TO_TEST = [ "init.c", "int_ops.c", "float_ops.c", "list_ops.c", "exc_ops.c", "generic_ops.c", "pythonsupport.c", ] class BuildExtGtest(build_ext): def get_library_names(self) -> list[str]: return ["gtest"] def run(self) -> None: # Build Google Test, the C++ framework we use for testing C code. # The source code for Google Test is copied to this repository. gtest_dir = os.path.abspath( os.path.join(os.path.dirname(__file__), "..", "external", "googletest") ) os.makedirs(self.build_temp, exist_ok=True) subprocess.check_call( ["make", "-f", os.path.join(gtest_dir, "make", "Makefile"), f"GTEST_DIR={gtest_dir}"], cwd=self.build_temp, ) self.library_dirs = [self.build_temp] return build_ext.run(self) if "--run-capi-tests" in sys.argv: sys.argv.pop() kwargs: dict[str, Any] if sys.platform == "darwin": kwargs = {"language": "c++"} compile_args: list[str] = [] else: kwargs = {} compile_args = ["--std=c++11"] setup( name="test_capi", version="0.1", ext_modules=[ Extension( "test_capi", ["test_capi.cc"] + C_APIS_TO_TEST, depends=["CPy.h", "mypyc_util.h", "pythonsupport.h"], extra_compile_args=["-Wno-unused-function", "-Wno-sign-compare"] + compile_args, libraries=["gtest"], include_dirs=["../external/googletest", "../external/googletest/include"], **kwargs, ) ], cmdclass={"build_ext": BuildExtGtest}, ) else: compiler = ccompiler.new_compiler() sysconfig.customize_compiler(compiler) cflags: list[str] = [] if compiler.compiler_type == "unix": # type: ignore[attr-defined] cflags += ["-O3", "-Wno-unused-function"] elif compiler.compiler_type == "msvc": # type: ignore[attr-defined] cflags += ["/O2"] setup( ext_modules=[ Extension( "librt.internal", [ "internal/librt_internal.c", "init.c", "int_ops.c", "exc_ops.c", "pythonsupport.c", "getargsfast.c", ], include_dirs=[".", "internal"], extra_compile_args=cflags, ), Extension( "librt.strings", [ "strings/librt_strings.c", "init.c", "int_ops.c", "exc_ops.c", "pythonsupport.c", "getargsfast.c", ], include_dirs=[".", "strings"], extra_compile_args=cflags, ), Extension( "librt.base64", [ "base64/librt_base64.c", "base64/lib.c", "base64/codec_choose.c", "base64/tables/tables.c", "base64/arch/generic/codec.c", "base64/arch/ssse3/codec.c", "base64/arch/sse41/codec.c", "base64/arch/sse42/codec.c", "base64/arch/avx/codec.c", "base64/arch/avx2/codec.c", "base64/arch/avx512/codec.c", "base64/arch/neon32/codec.c", "base64/arch/neon64/codec.c", ], include_dirs=[".", "base64"], extra_compile_args=cflags, ), Extension( "librt.vecs", [ "vecs/librt_vecs.c", "vecs/vec_i64.c", "vecs/vec_i32.c", "vecs/vec_i16.c", "vecs/vec_u8.c", "vecs/vec_float.c", "vecs/vec_bool.c", "vecs/vec_t.c", "vecs/vec_nested.c", ], include_dirs=[".", "vecs"], extra_compile_args=cflags, ), Extension( "librt.time", ["time/librt_time.c"], include_dirs=["."], extra_compile_args=cflags ), Extension( "librt.random", [ "random/librt_random.c", "init.c", "int_ops.c", "exc_ops.c", "pythonsupport.c", "getargsfast.c", ], include_dirs=["."], extra_compile_args=cflags, ), ] ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435280.0 librt-0.11.0/smoke_tests.py0000644000175100017510000002150215200142320015252 0ustar00runnerrunnerfrom __future__ import annotations import base64 from time import time as stdlib_time from typing import Final import pytest from mypy_extensions import u8 from librt.base64 import ( b64encode, b64decode, urlsafe_b64encode, urlsafe_b64decode ) from librt.internal import ( ReadBuffer, WriteBuffer, write_bool, read_bool, write_str, read_str, write_float, read_float, write_int, read_int, write_tag, read_tag, write_bytes, read_bytes, cache_version, ) from librt.random import Random, random, randint from librt.strings import BytesWriter, StringWriter from librt.time import time Tag = u8 TAG_A: Final[Tag] = 33 TAG_B: Final[Tag] = 255 TAG_SPECIAL: Final[Tag] = 239 def test_cache_version() -> None: assert cache_version() == 0 def test_buffer_write_and_read_int() -> None: b = WriteBuffer() write_int(b, 42) rb = ReadBuffer(b.getvalue()) assert read_int(rb) == 42 def test_buffer_roundtrip() -> None: b: WriteBuffer | ReadBuffer b = WriteBuffer() write_str(b, "foo") write_bool(b, True) write_str(b, "bar" * 1000) write_bool(b, False) write_bytes(b, b"bar") write_bytes(b, b"bar" * 100) write_bytes(b, b"") write_bytes(b, b"a" * 117) write_bytes(b, b"a" * 118) write_float(b, 0.1) write_float(b, -1.0) write_float(b, -113.0) write_int(b, 0) write_int(b, 1) write_tag(b, TAG_A) write_tag(b, TAG_SPECIAL) write_tag(b, TAG_B) write_int(b, 2) write_int(b, 2 ** 85) write_int(b, 255) write_int(b, -1) write_int(b, -255) write_int(b, 536860911) write_int(b, 536860912) write_int(b, 1234567891) b = ReadBuffer(b.getvalue()) assert read_str(b) == "foo" assert read_bool(b) is True assert read_str(b) == "bar" * 1000 assert read_bool(b) is False assert read_bytes(b) == b"bar" assert read_bytes(b) == b"bar" * 100 assert read_bytes(b) == b"" assert read_bytes(b) == b"a" * 117 assert read_bytes(b) == b"a" * 118 assert read_float(b) == 0.1 assert read_float(b) == -1.0 assert read_float(b) == -113.0 assert read_int(b) == 0 assert read_int(b) == 1 assert read_tag(b) == TAG_A assert read_tag(b) == TAG_SPECIAL assert read_tag(b) == TAG_B assert read_int(b) == 2 assert read_int(b) == 2 ** 85 assert read_int(b) == 255 assert read_int(b) == -1 assert read_int(b) == -255 assert read_int(b) == 536860911 assert read_int(b) == 536860912 assert read_int(b) == 1234567891 def test_buffer_int_size() -> None: b: WriteBuffer | ReadBuffer for i in (-10, -9, 0, 116, 117): b = WriteBuffer() write_int(b, i) assert len(b.getvalue()) == 1 b = ReadBuffer(b.getvalue()) assert read_int(b) == i for i in (-100, -11, 118, 12344, 16283): b = WriteBuffer() write_int(b, i) assert len(b.getvalue()) == 2 b = ReadBuffer(b.getvalue()) assert read_int(b) == i for i in (-10000, 16284, 123456789): b = WriteBuffer() write_int(b, i) assert len(b.getvalue()) == 4 b = ReadBuffer(b.getvalue()) assert read_int(b) == i def test_buffer_int_powers() -> None: # 0, 1, 2 are tested above b: WriteBuffer | ReadBuffer for p in range(2, 100): b = WriteBuffer() write_int(b, 1 << p) write_int(b, -1 << p) b = ReadBuffer(b.getvalue()) assert read_int(b) == 1 << p assert read_int(b) == -1 << p def test_buffer_str_size() -> None: b: WriteBuffer | ReadBuffer for s in ("", "a", "a" * 117): b = WriteBuffer() write_str(b, s) assert len(b.getvalue()) == len(s) + 1 b = ReadBuffer(b.getvalue()) assert read_str(b) == s for s in ("a" * 118, "a" * 16283): b = WriteBuffer() write_str(b, s) assert len(b.getvalue()) == len(s) + 2 b = ReadBuffer(b.getvalue()) assert read_str(b) == s def test_base64_basic() -> None: assert b64encode(b"x") == b"eA==" with pytest.raises(TypeError): b64encode(bytearray(b"x")) # type: ignore assert b64decode(b"eA==") == b"x" with pytest.raises(TypeError): b64decode(bytearray(b"eA==")) # type: ignore for non_ascii in "\x80", "foo\u100bar", "foo\ua1234bar": with pytest.raises(ValueError): b64decode(non_ascii) def check_encode(b: bytes) -> None: assert b64encode(b) == base64.b64encode(b) def check_decode(b: bytes) -> None: enc = b64encode(b) assert b64decode(enc) == base64.b64decode(enc) if enc.isascii(): enc_str = enc.decode("ascii") assert b64decode(enc_str) == base64.b64decode(enc_str) def test_base64_samples() -> None: for i in range(256): check_encode(bytes([i])) check_encode(bytes([i]) + b"x") check_encode(bytes([i]) + b"xy") check_encode(bytes([i]) + b"xyz") check_encode(bytes([i]) + b"xyza") check_encode(b"x" + bytes([i])) check_encode(b"xy" + bytes([i])) check_encode(b"xyz" + bytes([i])) check_encode(b"xyza" + bytes([i])) b = b"a\x00\xb7" * 1000 for i in range(1000): check_encode(b[:i]) for b in b"", b"ab", b"bac", b"1234", b"xyz88", b"abc" * 200: check_encode(b) for i in range(256): check_decode(bytes([i])) check_decode(bytes([i]) + b"x") check_decode(bytes([i]) + b"xy") check_decode(bytes([i]) + b"xyz") check_decode(bytes([i]) + b"xyza") check_decode(b"x" + bytes([i])) check_decode(b"xy" + bytes([i])) check_decode(b"xyz" + bytes([i])) check_decode(b"xyza" + bytes([i])) b = b"a\x00\xb7" * 1000 for i in range(1000): check_decode(b[:i]) for b in b"", b"ab", b"bac", b"1234", b"xyz88", b"abc" * 200: check_decode(b) def check_urlsafe_encode(b: bytes) -> None: assert urlsafe_b64encode(b) == base64.urlsafe_b64encode(b) def check_urlsafe_decode(b: bytes) -> None: enc = urlsafe_b64encode(b) assert urlsafe_b64decode(enc) == base64.urlsafe_b64decode(enc) enc2 = b64encode(b) assert urlsafe_b64decode(enc2) == base64.urlsafe_b64decode(enc2) def test_base64_urlsafe() -> None: check_urlsafe_encode(b"") check_urlsafe_encode(b"a") check_urlsafe_encode(b"\xf8") check_urlsafe_encode(b"\xfc") check_urlsafe_encode(b"\xfcx") check_urlsafe_encode(b"\xfcxy") check_urlsafe_encode(b"\xfcxyz") check_urlsafe_encode(bytes([x for x in range(256)])) check_urlsafe_decode(b"") check_urlsafe_decode(b"a") check_urlsafe_decode(b"\xf8") check_urlsafe_decode(b"\xfc") check_urlsafe_decode(b"\xfcx") check_urlsafe_decode(b"\xfcxy") check_urlsafe_decode(b"\xfcxyz") check_urlsafe_decode(bytes([x for x in range(256)])) assert urlsafe_b64decode(b" e A = == !") == b"x" for b in b"eA", b"eA=", b"eHk": with pytest.raises(ValueError): b64decode(b) def test_time_increments() -> None: t1 = time() t2 = time() # Time should not go backwards (allowing for same value due to precision) assert t2 >= t1 def test_time_comparable_to_stdlib() -> None: # Our time() should return similar values to stdlib time.time() our_time = time() std_time = stdlib_time() # Should be within 0.25 seconds of each other (usually should be much less, # but keep it relatively high to avoid test flakiness in CI) assert abs(our_time - std_time) < 0.25 def test_bytes_writer_basics() -> None: w = BytesWriter() assert w.getvalue() == b"" assert len(w) == 0 assert repr(w) == "BytesWriter(b'')" w = BytesWriter() w.append(ord('a')) w.write(b'bc') assert w.getvalue() == b"abc" assert repr(w) == "BytesWriter(b'abc')" def test_string_writer_basics() -> None: w = StringWriter() assert w.getvalue() == "" assert repr(w) == "StringWriter('')" w.append(ord('h')) w.append(ord('i')) assert repr(w) == "StringWriter('hi')" # Kind 2 (UCS-2) w2 = StringWriter() w2.append(0x100) w2.append(0x200) assert repr(w2) == "StringWriter('" + chr(0x100) + chr(0x200) + "')" # Kind 4 (UCS-4) w3 = StringWriter() w3.append(0x10000) expected = "StringWriter('" + chr(0x10000) + "')" assert repr(w3) == expected def test_random_construct() -> None: r = Random() assert isinstance(r, Random) def test_randint_basic() -> None: r = Random() for i in range(100): val = r.randint(0, 10) assert 0 <= val <= 10 def test_random_basic() -> None: r = Random() for i in range(100): val = r.random() assert 0.0 <= val < 1.0 def test_module_random_basic() -> None: for i in range(100): val = random() assert 0.0 <= val < 1.0 def test_module_randint_basic() -> None: for i in range(100): val = randint(0, 10) assert 0 <= val <= 10 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/static_data.c0000644000175100017510000000513315200142331014770 0ustar00runnerrunner#ifndef STATIC_DATA #define STATIC_DATA #include "static_data.h" // Adopted from numpy 2.4.0: numpy/_core/src/multiarry/npy_static_data.c mypyc_interned_str_struct mypyc_interned_str; #define INTERN_STRING(struct_member, string) \ assert(mypyc_interned_str.struct_member == NULL); \ mypyc_interned_str.struct_member = PyUnicode_InternFromString(string); \ if (mypyc_interned_str.struct_member == NULL) { \ return -1; \ } int intern_strings(void) { if (mypyc_interned_str.values != NULL) { // Already interned. return 0; } INTERN_STRING(__init_subclass__, "__init_subclass__"); INTERN_STRING(__module__, "__module__"); INTERN_STRING(__mro_entries__, "__mro_entries__"); INTERN_STRING(__mypyc_attrs__, "__mypyc_attrs__"); INTERN_STRING(__name__, "__name__"); INTERN_STRING(__orig_bases__, "__orig_bases__"); INTERN_STRING(__qualname__, "__qualname__"); INTERN_STRING(__slots__, "__slots__"); INTERN_STRING(__radd__, "__radd__"); INTERN_STRING(__rsub__, "__rsub__"); INTERN_STRING(__rmul__, "__rmul__"); INTERN_STRING(__rtruediv__, "__rtruediv__"); INTERN_STRING(__rmod__, "__rmod__"); INTERN_STRING(__rdivmod__, "__rdivmod__"); INTERN_STRING(__rfloordiv__, "__rfloordiv__"); INTERN_STRING(__rpow__, "__rpow__"); INTERN_STRING(__rmatmul__, "__rmatmul__"); INTERN_STRING(__rand__, "__rand__"); INTERN_STRING(__ror__, "__ror__"); INTERN_STRING(__rxor__, "__rxor__"); INTERN_STRING(__rlshift__, "__rlshift__"); INTERN_STRING(__rrshift__, "__rrshift__"); INTERN_STRING(__eq__, "__eq__"); INTERN_STRING(__ne__, "__ne__"); INTERN_STRING(__gt__, "__gt__"); INTERN_STRING(__le__, "__le__"); INTERN_STRING(__lt__, "__lt__"); INTERN_STRING(__ge__, "__ge__"); INTERN_STRING(clear, "clear"); INTERN_STRING(close_, "close"); INTERN_STRING(copy, "copy"); INTERN_STRING(dispatch_cache, "dispatch_cache"); INTERN_STRING(endswith, "endswith"); INTERN_STRING(get_type_hints, "get_type_hints"); INTERN_STRING(keys, "keys"); INTERN_STRING(lower, "lower"); INTERN_STRING(items, "items"); INTERN_STRING(join, "join"); INTERN_STRING(register_, "register"); INTERN_STRING(registry, "registry"); INTERN_STRING(send, "send"); INTERN_STRING(setdefault, "setdefault"); INTERN_STRING(startswith, "startswith"); INTERN_STRING(super, "super"); INTERN_STRING(throw_, "throw"); INTERN_STRING(translate, "translate"); INTERN_STRING(update, "update"); INTERN_STRING(upper, "upper"); INTERN_STRING(values, "values"); return 0; } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/static_data.h0000644000175100017510000000304115200142331014771 0ustar00runnerrunner#ifndef STATIC_DATA_H #define STATIC_DATA_H #include #ifdef __cplusplus extern "C" { #endif // Adopted from numpy 2.4.0: numpy/_core/src/multiarry/npy_static_data.h int intern_strings(void); typedef struct mypyc_interned_str_struct { PyObject *__init_subclass__; PyObject *__module__; PyObject *__mro_entries__; PyObject *__mypyc_attrs__; PyObject *__orig_bases__; PyObject *__qualname__; PyObject *__slots__; PyObject *__name__; PyObject *__radd__; PyObject *__rsub__; PyObject *__rmul__; PyObject *__rtruediv__; PyObject *__rmod__; PyObject *__rdivmod__; PyObject *__rfloordiv__; PyObject *__rpow__; PyObject *__rmatmul__; PyObject *__rand__; PyObject *__ror__; PyObject *__rxor__; PyObject *__rlshift__; PyObject *__rrshift__; PyObject *__eq__; PyObject *__ne__; PyObject *__gt__; PyObject *__le__; PyObject *__lt__; PyObject *__ge__; PyObject *clear; PyObject *close_; PyObject *copy; PyObject *dispatch_cache; PyObject *endswith; PyObject *get_type_hints; PyObject *keys; PyObject *lower; PyObject *items; PyObject *join; PyObject *register_; PyObject *registry; PyObject *send; PyObject *setdefault; PyObject *startswith; PyObject *super; PyObject *throw_; PyObject *translate; PyObject *update; PyObject *upper; PyObject *values; } mypyc_interned_str_struct; extern mypyc_interned_str_struct mypyc_interned_str; #ifdef __cplusplus } #endif #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/str_extra_ops.c0000644000175100017510000000022315200142331015377 0ustar00runnerrunner#include "str_extra_ops.h" // All str extra ops are inline functions in str_extra_ops.h // This file exists to satisfy the SourceDep requirements ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/str_extra_ops.h0000644000175100017510000000154115200142331015410 0ustar00runnerrunner#ifndef MYPYC_STR_EXTRA_OPS_H #define MYPYC_STR_EXTRA_OPS_H #include #include #include "CPy.h" // Optimized str indexing for ord(s[i]) // If index is negative, convert to non-negative index (no range checking) static inline int64_t CPyStr_AdjustIndex(PyObject *obj, int64_t index) { if (index < 0) { return index + PyUnicode_GET_LENGTH(obj); } return index; } // Check if index is in valid range [0, len) static inline bool CPyStr_RangeCheck(PyObject *obj, int64_t index) { return index >= 0 && index < PyUnicode_GET_LENGTH(obj); } // Get character at index as int (ord value) - no bounds checking, returns as CPyTagged static inline CPyTagged CPyStr_GetItemUnsafeAsInt(PyObject *obj, int64_t index) { int kind = PyUnicode_KIND(obj); return PyUnicode_READ(kind, PyUnicode_DATA(obj), index) << 1; } #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/str_ops.c0000644000175100017510000006335515200142331014213 0ustar00runnerrunner#include "pythoncapi_compat.h" // String primitive operations // // These are registered in mypyc.primitives.str_ops. #include #include "CPy.h" // The _PyUnicode_CheckConsistency definition has been moved to the internal API // https://github.com/python/cpython/pull/106398 #if defined(Py_DEBUG) && CPY_3_13_FEATURES #include "internal/pycore_unicodeobject.h" #endif // Copied from cpython.git:Objects/unicodeobject.c@0ef4ffeefd1737c18dc9326133c7894d58108c2e. #define BLOOM_MASK unsigned long #define BLOOM(mask, ch) ((mask & (1UL << ((ch) & (BLOOM_WIDTH - 1))))) #if LONG_BIT >= 128 #define BLOOM_WIDTH 128 #elif LONG_BIT >= 64 #define BLOOM_WIDTH 64 #elif LONG_BIT >= 32 #define BLOOM_WIDTH 32 #else #error "LONG_BIT is smaller than 32" #endif // Copied from cpython.git:Objects/unicodeobject.c@0ef4ffeefd1737c18dc9326133c7894d58108c2e. // This is needed for str.strip("..."). static inline BLOOM_MASK make_bloom_mask(int kind, const void* ptr, Py_ssize_t len) { #define BLOOM_UPDATE(TYPE, MASK, PTR, LEN) \ do { \ TYPE *data = (TYPE *)PTR; \ TYPE *end = data + LEN; \ Py_UCS4 ch; \ for (; data != end; data++) { \ ch = *data; \ MASK |= (1UL << (ch & (BLOOM_WIDTH - 1))); \ } \ break; \ } while (0) /* calculate simple bloom-style bitmask for a given unicode string */ BLOOM_MASK mask; mask = 0; switch (kind) { case PyUnicode_1BYTE_KIND: BLOOM_UPDATE(Py_UCS1, mask, ptr, len); break; case PyUnicode_2BYTE_KIND: BLOOM_UPDATE(Py_UCS2, mask, ptr, len); break; case PyUnicode_4BYTE_KIND: BLOOM_UPDATE(Py_UCS4, mask, ptr, len); break; default: Py_UNREACHABLE(); } return mask; #undef BLOOM_UPDATE } static inline char _CPyStr_Equal_NoIdentCheck(PyObject *str1, PyObject *str2, Py_ssize_t str2_length) { // This helper function only exists to deduplicate code in CPyStr_Equal and CPyStr_EqualLiteral Py_ssize_t str1_length = PyUnicode_GET_LENGTH(str1); if (str1_length != str2_length) return 0; int kind = PyUnicode_KIND(str1); if (PyUnicode_KIND(str2) != kind) return 0; const void *data1 = PyUnicode_DATA(str1); const void *data2 = PyUnicode_DATA(str2); return memcmp(data1, data2, str1_length * kind) == 0; } // Adapted from CPython 3.13.1 (_PyUnicode_Equal) char CPyStr_Equal(PyObject *str1, PyObject *str2) { if (str1 == str2) { return 1; } Py_ssize_t str2_length = PyUnicode_GET_LENGTH(str2); return _CPyStr_Equal_NoIdentCheck(str1, str2, str2_length); } char CPyStr_EqualLiteral(PyObject *str, PyObject *literal_str, Py_ssize_t literal_length) { if (str == literal_str) { return 1; } return _CPyStr_Equal_NoIdentCheck(str, literal_str, literal_length); } 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); if (ch < 256) { // Latin-1 single-char strings are cached by CPython, so // PyUnicode_FromOrdinal returns the cached object (with a // new reference) instead of allocating a new string each time. return PyUnicode_FromOrdinal(ch); } PyObject *unicode = PyUnicode_New(1, ch); if (unicode == NULL) return NULL; 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); PyObject *result = PyObject_GetItem(str, index_obj); Py_DECREF(index_obj); return result; } } PyObject *CPyStr_GetItemUnsafe(PyObject *str, Py_ssize_t index) { // This is unsafe since we don't check for overflow when doing <<. return CPyStr_GetItem(str, index << 1); } // 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) { #if CPY_3_13_FEATURES PyUnicode_CopyCharacters(res, res_offset, item, 0, itemlen); #else _PyUnicode_FastCopyCharacters(res, res_offset, item, 0, itemlen); #endif res_offset += itemlen; } } va_end(args); assert(res_offset == PyUnicode_GET_LENGTH(res)); } #ifdef Py_DEBUG assert(_PyUnicode_CheckConsistency(res, 1)); #endif return res; } CPyTagged CPyStr_Find(PyObject *str, PyObject *substr, CPyTagged start, int direction) { CPyTagged end = PyUnicode_GET_LENGTH(str) << 1; return CPyStr_FindWithEnd(str, substr, start, end, direction); } CPyTagged CPyStr_FindWithEnd(PyObject *str, PyObject *substr, CPyTagged start, CPyTagged end, int direction) { Py_ssize_t temp_start = CPyTagged_AsSsize_t(start); if (temp_start == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return CPY_INT_TAG; } Py_ssize_t temp_end = CPyTagged_AsSsize_t(end); if (temp_end == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return CPY_INT_TAG; } Py_ssize_t index = PyUnicode_Find(str, substr, temp_start, temp_end, direction); if (unlikely(index == -2)) { return CPY_INT_TAG; } return index << 1; } 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_RSplit(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_RSplit(str, sep, temp_max_split); } // This function has been copied from _PyUnicode_XStrip in cpython.git:Objects/unicodeobject.c@0ef4ffeefd1737c18dc9326133c7894d58108c2e. static PyObject *_PyStr_XStrip(PyObject *self, int striptype, PyObject *sepobj) { const void *data; int kind; Py_ssize_t i, j, len; BLOOM_MASK sepmask; Py_ssize_t seplen; // This check is needed from Python 3.9 and earlier. if (PyUnicode_READY(self) == -1 || PyUnicode_READY(sepobj) == -1) return NULL; kind = PyUnicode_KIND(self); data = PyUnicode_DATA(self); len = PyUnicode_GET_LENGTH(self); seplen = PyUnicode_GET_LENGTH(sepobj); sepmask = make_bloom_mask(PyUnicode_KIND(sepobj), PyUnicode_DATA(sepobj), seplen); i = 0; if (striptype != RIGHTSTRIP) { while (i < len) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); if (!BLOOM(sepmask, ch)) break; if (PyUnicode_FindChar(sepobj, ch, 0, seplen, 1) < 0) break; i++; } } j = len; if (striptype != LEFTSTRIP) { j--; while (j >= i) { Py_UCS4 ch = PyUnicode_READ(kind, data, j); if (!BLOOM(sepmask, ch)) break; if (PyUnicode_FindChar(sepobj, ch, 0, seplen, 1) < 0) break; j--; } j++; } return PyUnicode_Substring(self, i, j); } // Copied from do_strip function in cpython.git/Objects/unicodeobject.c@0ef4ffeefd1737c18dc9326133c7894d58108c2e. PyObject *_CPyStr_Strip(PyObject *self, int strip_type, PyObject *sep) { if (sep == NULL || Py_IsNone(sep)) { Py_ssize_t len, i, j; // This check is needed from Python 3.9 and earlier. if (PyUnicode_READY(self) == -1) return NULL; len = PyUnicode_GET_LENGTH(self); if (PyUnicode_IS_ASCII(self)) { const Py_UCS1 *data = PyUnicode_1BYTE_DATA(self); i = 0; if (strip_type != RIGHTSTRIP) { while (i < len) { Py_UCS1 ch = data[i]; if (!_Py_ascii_whitespace[ch]) break; i++; } } j = len; if (strip_type != LEFTSTRIP) { j--; while (j >= i) { Py_UCS1 ch = data[j]; if (!_Py_ascii_whitespace[ch]) break; j--; } j++; } } else { int kind = PyUnicode_KIND(self); const void *data = PyUnicode_DATA(self); i = 0; if (strip_type != RIGHTSTRIP) { while (i < len) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); if (!Py_UNICODE_ISSPACE(ch)) break; i++; } } j = len; if (strip_type != LEFTSTRIP) { j--; while (j >= i) { Py_UCS4 ch = PyUnicode_READ(kind, data, j); if (!Py_UNICODE_ISSPACE(ch)) break; j--; } j++; } } return PyUnicode_Substring(self, i, j); } return _PyStr_XStrip(self, strip_type, sep); } 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); } int CPyStr_Startswith(PyObject *self, PyObject *subobj) { Py_ssize_t start = 0; Py_ssize_t end = PyUnicode_GET_LENGTH(self); if (PyTuple_Check(subobj)) { Py_ssize_t i; for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { PyObject *substring = PyTuple_GET_ITEM(subobj, i); if (!PyUnicode_Check(substring)) { PyErr_Format(PyExc_TypeError, "tuple for startswith must only contain str, " "not %.100s", Py_TYPE(substring)->tp_name); return 2; } int result = PyUnicode_Tailmatch(self, substring, start, end, -1); if (result) { return 1; } } return 0; } return PyUnicode_Tailmatch(self, subobj, start, end, -1); } int CPyStr_Endswith(PyObject *self, PyObject *subobj) { Py_ssize_t start = 0; Py_ssize_t end = PyUnicode_GET_LENGTH(self); if (PyTuple_Check(subobj)) { Py_ssize_t i; for (i = 0; i < PyTuple_GET_SIZE(subobj); i++) { PyObject *substring = PyTuple_GET_ITEM(subobj, i); if (!PyUnicode_Check(substring)) { PyErr_Format(PyExc_TypeError, "tuple for endswith must only contain str, " "not %.100s", Py_TYPE(substring)->tp_name); return 2; } int result = PyUnicode_Tailmatch(self, substring, start, end, 1); if (result) { return 1; } } return 0; } return PyUnicode_Tailmatch(self, subobj, start, end, 1); } PyObject *CPyStr_Removeprefix(PyObject *self, PyObject *prefix) { Py_ssize_t end = PyUnicode_GET_LENGTH(self); int match = PyUnicode_Tailmatch(self, prefix, 0, end, -1); if (match) { Py_ssize_t prefix_end = PyUnicode_GET_LENGTH(prefix); return PyUnicode_Substring(self, prefix_end, end); } return Py_NewRef(self); } PyObject *CPyStr_Removesuffix(PyObject *self, PyObject *suffix) { Py_ssize_t end = PyUnicode_GET_LENGTH(self); int match = PyUnicode_Tailmatch(self, suffix, 0, end, 1); if (match) { Py_ssize_t suffix_end = PyUnicode_GET_LENGTH(suffix); return PyUnicode_Substring(self, 0, end - suffix_end); } return Py_NewRef(self); } /* 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. its 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_DecodeUTF8(PyObject *bytes) { if (PyBytes_CheckExact(bytes)) { char *buffer = PyBytes_AsString(bytes); // Borrowed reference if (buffer == NULL) { return NULL; } Py_ssize_t size = PyBytes_Size(bytes); return PyUnicode_DecodeUTF8(buffer, size, "strict"); } else { return PyUnicode_FromEncodedObject(bytes, "utf-8", "strict"); } } PyObject *CPy_DecodeASCII(PyObject *bytes) { if (PyBytes_CheckExact(bytes)) { char *buffer = PyBytes_AsString(bytes); // Borrowed reference if (buffer == NULL) { return NULL; } Py_ssize_t size = PyBytes_Size(bytes); return PyUnicode_DecodeASCII(buffer, size, "strict");; } else { return PyUnicode_FromEncodedObject(bytes, "ascii", "strict"); } } PyObject *CPy_DecodeLatin1(PyObject *bytes) { if (PyBytes_CheckExact(bytes)) { char *buffer = PyBytes_AsString(bytes); // Borrowed reference if (buffer == NULL) { return NULL; } Py_ssize_t size = PyBytes_Size(bytes); return PyUnicode_DecodeLatin1(buffer, size, "strict"); } else { return PyUnicode_FromEncodedObject(bytes, "latin1", "strict"); } } 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; } } Py_ssize_t CPyStr_Count(PyObject *unicode, PyObject *substring, CPyTagged start) { Py_ssize_t temp_start = CPyTagged_AsSsize_t(start); if (temp_start == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return -1; } Py_ssize_t end = PyUnicode_GET_LENGTH(unicode); return PyUnicode_Count(unicode, substring, temp_start, end); } Py_ssize_t CPyStr_CountFull(PyObject *unicode, PyObject *substring, CPyTagged start, CPyTagged end) { Py_ssize_t temp_start = CPyTagged_AsSsize_t(start); if (temp_start == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return -1; } Py_ssize_t temp_end = CPyTagged_AsSsize_t(end); if (temp_end == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return -1; } return PyUnicode_Count(unicode, substring, temp_start, temp_end); } CPyTagged CPyStr_Ord(PyObject *obj) { Py_ssize_t s = PyUnicode_GET_LENGTH(obj); if (s == 1) { int kind = PyUnicode_KIND(obj); return PyUnicode_READ(kind, PyUnicode_DATA(obj), 0) << 1; } PyErr_Format( PyExc_TypeError, "ord() expected a character, but a string of length %zd found", s); return CPY_INT_TAG; } PyObject *CPyStr_Multiply(PyObject *str, CPyTagged count) { Py_ssize_t temp_count = CPyTagged_AsSsize_t(count); if (temp_count == -1 && PyErr_Occurred()) { PyErr_SetString(PyExc_OverflowError, CPYTHON_LARGE_INT_ERRMSG); return NULL; } return PySequence_Repeat(str, temp_count); } bool CPyStr_IsSpace(PyObject *str) { Py_ssize_t len = PyUnicode_GET_LENGTH(str); if (len == 0) return false; if (PyUnicode_IS_ASCII(str)) { const Py_UCS1 *data = PyUnicode_1BYTE_DATA(str); for (Py_ssize_t i = 0; i < len; i++) { if (!_Py_ascii_whitespace[data[i]]) return false; } return true; } int kind = PyUnicode_KIND(str); const void *data = PyUnicode_DATA(str); for (Py_ssize_t i = 0; i < len; i++) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); if (!Py_UNICODE_ISSPACE(ch)) return false; } return true; } bool CPyStr_IsAlnum(PyObject *str) { Py_ssize_t len = PyUnicode_GET_LENGTH(str); if (len == 0) return false; if (PyUnicode_IS_ASCII(str)) { const Py_UCS1 *data = PyUnicode_1BYTE_DATA(str); for (Py_ssize_t i = 0; i < len; i++) { if (!Py_ISALNUM(data[i])) return false; } return true; } int kind = PyUnicode_KIND(str); const void *data = PyUnicode_DATA(str); for (Py_ssize_t i = 0; i < len; i++) { Py_UCS4 ch = PyUnicode_READ(kind, data, i); if (!Py_UNICODE_ISALNUM(ch)) return false; } return true; } static inline int CPy_ASCII_Lower(unsigned char c) { return Py_TOLOWER(c); } static inline int CPy_ASCII_Upper(unsigned char c) { return Py_TOUPPER(c); } static inline PyObject *CPyStr_ChangeCase(PyObject *self, int (*ascii_func)(unsigned char), #if CPY_3_13_FEATURES PyObject *method_name #else int (*unicode_func)(Py_UCS4, Py_UCS4 *) #endif ) { Py_ssize_t len = PyUnicode_GET_LENGTH(self); if (len == 0) { Py_INCREF(self); return self; } // ASCII fast path: 1-to-1, no expansion possible if (PyUnicode_IS_ASCII(self)) { PyObject *res = PyUnicode_New(len, 127); if (res == NULL) return NULL; const Py_UCS1 *data = PyUnicode_1BYTE_DATA(self); Py_UCS1 *res_data = PyUnicode_1BYTE_DATA(res); for (Py_ssize_t i = 0; i < len; i++) { res_data[i] = ascii_func(data[i]); } return res; } #if CPY_3_13_FEATURES // On 3.13+, _PyUnicode_ToLowerFull/ToUpperFull are no longer exported, // so fall back to CPython's method implementation for non-ASCII strings. return PyObject_CallMethodNoArgs(self, method_name); #else // General Unicode: unicode_func handles 1-to-N expansion. // Worst case: each codepoint expands to 3 (per Unicode standard). // The tmp buffer is short-lived, and PyUnicode_FromKindAndData // compacts the result to the optimal string kind automatically. int kind = PyUnicode_KIND(self); const void *data = PyUnicode_DATA(self); Py_UCS4 *tmp = PyMem_Malloc(sizeof(Py_UCS4) * len * 3); if (tmp == NULL) return PyErr_NoMemory(); Py_UCS4 mapped[3]; Py_ssize_t out_len = 0; for (Py_ssize_t i = 0; i < len; i++) { int n = unicode_func(PyUnicode_READ(kind, data, i), mapped); for (int j = 0; j < n; j++) { tmp[out_len++] = mapped[j]; } } PyObject *res = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, tmp, out_len); PyMem_Free(tmp); return res; #endif } PyObject *CPyStr_Lower(PyObject *self) { #if CPY_3_13_FEATURES return CPyStr_ChangeCase(self, CPy_ASCII_Lower, mypyc_interned_str.lower); #else return CPyStr_ChangeCase(self, CPy_ASCII_Lower, _PyUnicode_ToLowerFull); #endif } PyObject *CPyStr_Upper(PyObject *self) { #if CPY_3_13_FEATURES return CPyStr_ChangeCase(self, CPy_ASCII_Upper, mypyc_interned_str.upper); #else return CPyStr_ChangeCase(self, CPy_ASCII_Upper, _PyUnicode_ToUpperFull); #endif } bool CPyStr_IsDigit(PyObject *str) { Py_ssize_t len = PyUnicode_GET_LENGTH(str); if (len == 0) return false; #define CHECK_ISDIGIT(TYPE, DATA, CHECK) \ { \ const TYPE *data = (const TYPE *)(DATA); \ for (Py_ssize_t i = 0; i < len; i++) { \ if (!CHECK(data[i])) \ return false; \ } \ } // ASCII fast path if (PyUnicode_IS_ASCII(str)) { CHECK_ISDIGIT(Py_UCS1, PyUnicode_1BYTE_DATA(str), Py_ISDIGIT); return true; } switch (PyUnicode_KIND(str)) { case PyUnicode_1BYTE_KIND: CHECK_ISDIGIT(Py_UCS1, PyUnicode_1BYTE_DATA(str), Py_UNICODE_ISDIGIT); break; case PyUnicode_2BYTE_KIND: CHECK_ISDIGIT(Py_UCS2, PyUnicode_2BYTE_DATA(str), Py_UNICODE_ISDIGIT); break; case PyUnicode_4BYTE_KIND: CHECK_ISDIGIT(Py_UCS4, PyUnicode_4BYTE_DATA(str), Py_UNICODE_ISDIGIT); break; default: Py_UNREACHABLE(); } return true; #undef CHECK_ISDIGIT } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8587534 librt-0.11.0/strings/0000755000175100017510000000000015200142335014037 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/strings/librt_strings.c0000644000175100017510000012070215200142331017066 0ustar00runnerrunner#include "pythoncapi_compat.h" #define PY_SSIZE_T_CLEAN #include #include #include "CPy.h" #include "librt_strings.h" #define CPY_BOOL_ERROR 2 // // BytesWriter // #define _WRITE_BYTES(data, type, v) \ do { \ *(type *)(((BytesWriterObject *)data)->buf + ((BytesWriterObject *)data)->len) = v; \ ((BytesWriterObject *)data)->len += sizeof(type); \ } while (0) static PyTypeObject BytesWriterType; static bool _grow_buffer(BytesWriterObject *data, Py_ssize_t n) { if (unlikely(n > PY_SSIZE_T_MAX - data->len)) { PyErr_NoMemory(); return false; } Py_ssize_t target = data->len + n; Py_ssize_t size = data->capacity; do { if (unlikely(size > PY_SSIZE_T_MAX / 2)) { PyErr_NoMemory(); return false; } size *= 2; } while (target >= size); char *new_buf; if (data->buf == data->data) { // Move from embedded buffer to heap-allocated buffer new_buf = PyMem_Malloc(size); if (new_buf != NULL) { memcpy(new_buf, data->data, data->len); } } else { new_buf = PyMem_Realloc(data->buf, size); } if (unlikely(new_buf == NULL)) { PyErr_NoMemory(); return false; } data->buf = new_buf; data->capacity = size; return true; } static inline bool ensure_bytes_writer_size(BytesWriterObject *data, Py_ssize_t n) { if (likely(data->capacity - data->len >= n)) { return true; } else { return _grow_buffer(data, n); } } static inline void BytesWriter_init_internal(BytesWriterObject *self) { self->buf = self->data; self->len = 0; self->capacity = WRITER_EMBEDDED_BUF_LEN; } static PyObject* BytesWriter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { if (type != &BytesWriterType) { PyErr_SetString(PyExc_TypeError, "BytesWriter cannot be subclassed"); return NULL; } BytesWriterObject *self = (BytesWriterObject *)type->tp_alloc(type, 0); if (self != NULL) BytesWriter_init_internal(self); return (PyObject *)self; } static PyObject * BytesWriter_internal(void) { BytesWriterObject *self = (BytesWriterObject *)BytesWriterType.tp_alloc(&BytesWriterType, 0); if (self == NULL) return NULL; BytesWriter_init_internal(self); return (PyObject *)self; } static int BytesWriter_init(BytesWriterObject *self, PyObject *args, PyObject *kwds) { if (!PyArg_ParseTuple(args, "")) { return -1; } if (kwds != NULL && PyDict_Size(kwds) > 0) { PyErr_SetString(PyExc_TypeError, "BytesWriter() takes no keyword arguments"); return -1; } // Soft reset: free any heap buffer so re-initialization doesn't leak. if (self->buf != self->data && self->buf != NULL) PyMem_Free(self->buf); BytesWriter_init_internal(self); return 0; } static void BytesWriter_dealloc(BytesWriterObject *self) { if (self->buf != self->data) { PyMem_Free(self->buf); self->buf = NULL; } Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject* BytesWriter_getvalue_internal(PyObject *self) { BytesWriterObject *obj = (BytesWriterObject *)self; return PyBytes_FromStringAndSize(obj->buf, obj->len); } static PyObject* BytesWriter_repr(BytesWriterObject *self) { PyObject *value = BytesWriter_getvalue_internal((PyObject *)self); if (value == NULL) { return NULL; } PyObject *value_repr = PyObject_Repr(value); Py_DECREF(value); if (value_repr == NULL) { return NULL; } PyObject *result = PyUnicode_FromFormat("BytesWriter(%U)", value_repr); Py_DECREF(value_repr); return result; } static PyObject* BytesWriter_getvalue(BytesWriterObject *self, PyObject *Py_UNUSED(ignored)) { return PyBytes_FromStringAndSize(self->buf, self->len); } static Py_ssize_t BytesWriter_length(BytesWriterObject *self) { return self->len; } static PyObject* BytesWriter_item(BytesWriterObject *self, Py_ssize_t index) { Py_ssize_t length = self->len; // Check bounds if (index < 0 || index >= length) { PyErr_SetString(PyExc_IndexError, "BytesWriter index out of range"); return NULL; } // Return the byte at the given index as a Python int return PyLong_FromLong((unsigned char)self->buf[index]); } static int BytesWriter_ass_item(BytesWriterObject *self, Py_ssize_t index, PyObject *value) { Py_ssize_t length = self->len; // Check bounds if (index < 0 || index >= length) { PyErr_SetString(PyExc_IndexError, "BytesWriter index out of range"); return -1; } // Check that value is not NULL (deletion not supported) if (value == NULL) { PyErr_SetString(PyExc_TypeError, "BytesWriter does not support item deletion"); return -1; } // Convert value to uint8 uint8_t byte_value = CPyLong_AsUInt8(value); if (unlikely(byte_value == CPY_LL_UINT_ERROR && PyErr_Occurred())) { CPy_TypeError("u8", value); return -1; } // Assign the byte self->buf[index] = (char)byte_value; return 0; } static PySequenceMethods BytesWriter_as_sequence = { .sq_length = (lenfunc)BytesWriter_length, .sq_item = (ssizeargfunc)BytesWriter_item, .sq_ass_item = (ssizeobjargproc)BytesWriter_ass_item, }; static PyObject* BytesWriter_append(PyObject *self, PyObject *const *args, size_t nargs); static PyObject* BytesWriter_write(PyObject *self, PyObject *const *args, size_t nargs); static PyObject* BytesWriter_truncate(PyObject *self, PyObject *const *args, size_t nargs); static PyMethodDef BytesWriter_methods[] = { {"append", (PyCFunction) BytesWriter_append, METH_FASTCALL, PyDoc_STR("Append a single byte to the buffer") }, {"write", (PyCFunction) BytesWriter_write, METH_FASTCALL, PyDoc_STR("Append bytes to the buffer") }, {"getvalue", (PyCFunction) BytesWriter_getvalue, METH_NOARGS, "Return the buffer content as bytes object" }, {"truncate", (PyCFunction) BytesWriter_truncate, METH_FASTCALL, PyDoc_STR("Truncate the buffer to the specified size") }, {NULL} /* Sentinel */ }; static PyTypeObject BytesWriterType = { .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "BytesWriter", .tp_doc = PyDoc_STR("Memory buffer for building bytes objects from parts"), .tp_basicsize = sizeof(BytesWriterObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = BytesWriter_new, .tp_init = (initproc) BytesWriter_init, .tp_dealloc = (destructor) BytesWriter_dealloc, .tp_methods = BytesWriter_methods, .tp_as_sequence = &BytesWriter_as_sequence, .tp_repr = (reprfunc)BytesWriter_repr, }; static inline bool check_bytes_writer(PyObject *data) { if (unlikely(Py_TYPE(data) != &BytesWriterType)) { PyErr_Format( PyExc_TypeError, "data must be a BytesWriter object, got %s", Py_TYPE(data)->tp_name ); return false; } return true; } static char BytesWriter_write_internal(BytesWriterObject *self, PyObject *value) { const char *data; Py_ssize_t size; if (likely(PyBytes_Check(value))) { data = PyBytes_AS_STRING(value); size = PyBytes_GET_SIZE(value); } else { data = PyByteArray_AS_STRING(value); size = PyByteArray_GET_SIZE(value); } // Write bytes content. if (!ensure_bytes_writer_size(self, size)) return CPY_NONE_ERROR; memcpy(self->buf + self->len, data, size); self->len += size; return CPY_NONE; } static PyObject* BytesWriter_write(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "write() takes exactly 1 argument (%zu given)", nargs); return NULL; } if (!check_bytes_writer(self)) { return NULL; } PyObject *value = args[0]; if (unlikely(!PyBytes_Check(value) && !PyByteArray_Check(value))) { PyErr_SetString(PyExc_TypeError, "value must be a bytes or bytearray object"); return NULL; } if (unlikely(BytesWriter_write_internal((BytesWriterObject *)self, value) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } static inline char BytesWriter_append_internal(BytesWriterObject *self, uint8_t value) { if (!ensure_bytes_writer_size(self, 1)) return CPY_NONE_ERROR; _WRITE_BYTES(self, uint8_t, value); return CPY_NONE; } static PyObject* BytesWriter_append(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "append() takes exactly 1 argument (%zu given)", nargs); return NULL; } if (!check_bytes_writer(self)) { return NULL; } PyObject *value = args[0]; uint8_t unboxed = CPyLong_AsUInt8(value); if (unlikely(unboxed == CPY_LL_UINT_ERROR && PyErr_Occurred())) { CPy_TypeError("u8", value); return NULL; } if (unlikely(BytesWriter_append_internal((BytesWriterObject *)self, unboxed) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } static char BytesWriter_truncate_internal(PyObject *self, int64_t size) { BytesWriterObject *writer = (BytesWriterObject *)self; Py_ssize_t current_size = writer->len; // Validate size is non-negative if (size < 0) { PyErr_SetString(PyExc_ValueError, "size must be non-negative"); return CPY_NONE_ERROR; } // Validate size doesn't exceed current size if (size > current_size) { PyErr_SetString(PyExc_ValueError, "size cannot be larger than current buffer size"); return CPY_NONE_ERROR; } writer->len = size; return CPY_NONE; } static PyObject* BytesWriter_truncate(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "truncate() takes exactly 1 argument (%zu given)", nargs); return NULL; } if (!check_bytes_writer(self)) { return NULL; } PyObject *size_obj = args[0]; int overflow; long long size = PyLong_AsLongLongAndOverflow(size_obj, &overflow); if (size == -1 && PyErr_Occurred()) { return NULL; } if (overflow != 0) { PyErr_SetString(PyExc_ValueError, "integer out of range"); return NULL; } if (unlikely(BytesWriter_truncate_internal(self, size) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } static PyTypeObject * BytesWriter_type_internal(void) { return &BytesWriterType; // Return borrowed reference }; static CPyTagged BytesWriter_len_internal(PyObject *self) { BytesWriterObject *writer = (BytesWriterObject *)self; return writer->len << 1; } // // StringWriter // static PyTypeObject StringWriterType; static void convert_string_data_in_place(char *buf, Py_ssize_t len, char old_kind, char new_kind); // Helper to grow string buffer and optionally convert to new kind // Returns true on success, false on failure (with PyErr set) // Updates self->buf, self->capacity, and self->kind static bool grow_string_buffer_helper(StringWriterObject *self, Py_ssize_t target_capacity, char new_kind) { char old_kind = self->kind; Py_ssize_t new_capacity = self->capacity; // Limit so that (new_capacity * 2) * new_kind stays within Py_ssize_t. // new_kind is always 1, 2, or 4, so use a shift instead of division. int shift = (new_kind == 4) ? 3 : (new_kind == 2 ? 2 : 1); Py_ssize_t cap_limit = PY_SSIZE_T_MAX >> shift; while (target_capacity >= new_capacity) { if (unlikely(new_capacity > cap_limit)) { PyErr_NoMemory(); return false; } new_capacity *= 2; } if (unlikely(new_capacity > cap_limit * 2)) { PyErr_NoMemory(); return false; } Py_ssize_t size_bytes = new_capacity * new_kind; char *new_buf; bool from_embedded = (self->buf == self->data); if (from_embedded) { // Move from embedded buffer to heap-allocated buffer new_buf = PyMem_Malloc(size_bytes); if (new_buf != NULL) { // Copy existing data from embedded buffer memcpy(new_buf, self->data, self->len * old_kind); } } else { // Realloc existing heap buffer new_buf = PyMem_Realloc(self->buf, size_bytes); } if (unlikely(new_buf == NULL)) { PyErr_NoMemory(); return false; } // Convert data if kind changed if (old_kind != new_kind) { convert_string_data_in_place(new_buf, self->len, old_kind, new_kind); } self->buf = new_buf; self->capacity = new_capacity; self->kind = new_kind; return true; } static bool grow_string_buffer(StringWriterObject *data, Py_ssize_t n) { if (unlikely(n > PY_SSIZE_T_MAX - data->len)) { PyErr_NoMemory(); return false; } return grow_string_buffer_helper(data, data->len + n, data->kind); } static inline bool ensure_string_writer_size(StringWriterObject *data, Py_ssize_t n) { if (likely(data->capacity - data->len >= n)) { return true; } else { // Don't inline the grow function since this is slow path and we // want to keep this as short as possible for better inlining return grow_string_buffer(data, n); } } static inline void StringWriter_init_internal(StringWriterObject *self) { self->buf = self->data; self->kind = 1; self->len = 0; self->capacity = WRITER_EMBEDDED_BUF_LEN; } static PyObject* StringWriter_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { if (type != &StringWriterType) { PyErr_SetString(PyExc_TypeError, "StringWriter cannot be subclassed"); return NULL; } StringWriterObject *self = (StringWriterObject *)type->tp_alloc(type, 0); if (self != NULL) StringWriter_init_internal(self); return (PyObject *)self; } static PyObject * StringWriter_internal(void) { StringWriterObject *self = (StringWriterObject *)StringWriterType.tp_alloc(&StringWriterType, 0); if (self == NULL) return NULL; StringWriter_init_internal(self); return (PyObject *)self; } static int StringWriter_init(StringWriterObject *self, PyObject *args, PyObject *kwds) { if (!PyArg_ParseTuple(args, "")) { return -1; } if (kwds != NULL && PyDict_Size(kwds) > 0) { PyErr_SetString(PyExc_TypeError, "StringWriter() takes no keyword arguments"); return -1; } // Soft reset: free any heap buffer so re-initialization doesn't leak. if (self->buf != self->data && self->buf != NULL) PyMem_Free(self->buf); StringWriter_init_internal(self); return 0; } static void StringWriter_dealloc(StringWriterObject *self) { if (self->buf != self->data) { PyMem_Free(self->buf); self->buf = NULL; } Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject* StringWriter_getvalue_internal(PyObject *self) { StringWriterObject *obj = (StringWriterObject *)self; return PyUnicode_FromKindAndData(obj->kind, obj->buf, obj->len); } static PyObject* StringWriter_repr(StringWriterObject *self) { PyObject *value = StringWriter_getvalue_internal((PyObject *)self); if (value == NULL) { return NULL; } PyObject *value_repr = PyObject_Repr(value); Py_DECREF(value); if (value_repr == NULL) { return NULL; } PyObject *result = PyUnicode_FromFormat("StringWriter(%U)", value_repr); Py_DECREF(value_repr); return result; } static PyObject* StringWriter_getvalue(StringWriterObject *self, PyObject *Py_UNUSED(ignored)) { return PyUnicode_FromKindAndData(self->kind, self->buf, self->len); } static Py_ssize_t StringWriter_length(StringWriterObject *self) { return self->len; } static PyObject* StringWriter_item(StringWriterObject *self, Py_ssize_t index) { Py_ssize_t length = self->len; // Check bounds if (index < 0 || index >= length) { PyErr_SetString(PyExc_IndexError, "StringWriter index out of range"); return NULL; } // Read the character at the given index based on kind using memcpy uint32_t value; if (self->kind == 1) { uint8_t val; memcpy(&val, self->buf + index, 1); value = val; } else if (self->kind == 2) { uint16_t val; memcpy(&val, self->buf + index * 2, 2); value = val; } else { memcpy(&value, self->buf + index * 4, 4); } return PyLong_FromLong(value); } static PySequenceMethods StringWriter_as_sequence = { .sq_length = (lenfunc)StringWriter_length, .sq_item = (ssizeargfunc)StringWriter_item, }; static PyObject* StringWriter_append(PyObject *self, PyObject *const *args, size_t nargs); static PyObject* StringWriter_write(PyObject *self, PyObject *const *args, size_t nargs); static PyMethodDef StringWriter_methods[] = { {"append", (PyCFunction) StringWriter_append, METH_FASTCALL, PyDoc_STR("Append a single character (as int codepoint) to the buffer") }, {"write", (PyCFunction) StringWriter_write, METH_FASTCALL, PyDoc_STR("Append a string to the buffer") }, {"getvalue", (PyCFunction) StringWriter_getvalue, METH_NOARGS, "Return the buffer content as str object" }, {NULL} /* Sentinel */ }; static PyTypeObject StringWriterType = { .ob_base = PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "StringWriter", .tp_doc = PyDoc_STR("Memory buffer for building string objects from parts"), .tp_basicsize = sizeof(StringWriterObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = StringWriter_new, .tp_init = (initproc) StringWriter_init, .tp_dealloc = (destructor) StringWriter_dealloc, .tp_methods = StringWriter_methods, .tp_as_sequence = &StringWriter_as_sequence, .tp_repr = (reprfunc)StringWriter_repr, }; static inline bool check_string_writer(PyObject *data) { if (unlikely(Py_TYPE(data) != &StringWriterType)) { PyErr_Format( PyExc_TypeError, "data must be a StringWriter object, got %s", Py_TYPE(data)->tp_name ); return false; } return true; } static char string_writer_switch_kind(StringWriterObject *self, int32_t value); static char StringWriter_write_internal(PyObject *obj, PyObject *value) { StringWriterObject *self = (StringWriterObject *)obj; Py_ssize_t str_len = PyUnicode_GET_LENGTH(value); if (str_len == 0) { return CPY_NONE; } int src_kind = PyUnicode_KIND(value); void *src_data = PyUnicode_DATA(value); int self_kind = self->kind; // Switch kind if source requires wider characters if (src_kind > self_kind) { // Use value in the source kind range to trigger proper kind switch int32_t codepoint = (src_kind == 2) ? 0x100 : 0x10000; if (string_writer_switch_kind(self, codepoint) == CPY_NONE_ERROR) { return CPY_NONE_ERROR; } self_kind = self->kind; } // Ensure we have enough space if (!ensure_string_writer_size(self, str_len)) { return CPY_NONE_ERROR; } // Copy data - ASCII/Latin1 (kind 1) are handled uniformly if (self_kind == src_kind) { // Same kind, direct copy memcpy(self->buf + self->len * self_kind, src_data, str_len * src_kind); } else { // Different kinds, convert character by character for (Py_ssize_t i = 0; i < str_len; i++) { Py_UCS4 ch = PyUnicode_READ(src_kind, src_data, i); PyUnicode_WRITE(self_kind, self->buf, self->len + i, ch); } } self->len += str_len; return CPY_NONE; } static PyObject* StringWriter_write(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "write() takes exactly 1 argument (%zu given)", nargs); return NULL; } if (!check_string_writer(self)) { return NULL; } PyObject *value = args[0]; if (unlikely(!PyUnicode_Check(value))) { PyErr_SetString(PyExc_TypeError, "value must be a str object"); return NULL; } if (unlikely(StringWriter_write_internal(self, value) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } // Convert string data to next larger kind (1->2 or 2->4) static void convert_string_data_in_place(char *buf, Py_ssize_t len, char old_kind, char new_kind) { if (old_kind == 1 && new_kind == 2) { // Convert backwards to avoid overwriting for (Py_ssize_t i = len - 1; i >= 0; i--) { uint8_t val = (uint8_t)buf[i]; uint16_t expanded = val; memcpy(buf + i * 2, &expanded, 2); } } else if (old_kind == 2 && new_kind == 4) { // Convert backwards to avoid overwriting for (Py_ssize_t i = len - 1; i >= 0; i--) { uint16_t val; memcpy(&val, buf + i * 2, 2); uint32_t expanded = val; memcpy(buf + i * 4, &expanded, 4); } } else { assert(false); } } static char convert_string_buffer_kind(StringWriterObject *self, char old_kind, char new_kind) { // new_kind is always 2 or 4, so the max representable len is PY_SSIZE_T_MAX >> {1,2}. // Use a shift instead of a division for cheap overflow check. Py_ssize_t max_len = PY_SSIZE_T_MAX >> (new_kind == 4 ? 2 : 1); if (unlikely(self->len > max_len)) { PyErr_NoMemory(); return CPY_NONE_ERROR; } // Current buffer size in bytes Py_ssize_t current_buf_size = (self->buf == self->data) ? WRITER_EMBEDDED_BUF_LEN : (self->capacity * old_kind); // Needed buffer size in bytes for new kind Py_ssize_t needed_size = self->len * new_kind; if (current_buf_size >= needed_size) { // Convert in place convert_string_data_in_place(self->buf, self->len, old_kind, new_kind); self->kind = new_kind; self->capacity = current_buf_size / new_kind; } else { // Need to allocate new buffer if (!grow_string_buffer_helper(self, self->len, new_kind)) { return CPY_NONE_ERROR; } } return CPY_NONE; } static char string_writer_switch_kind(StringWriterObject *self, int32_t value) { if (self->kind == 1) { // Either kind 1 -> 2 or 1 -> 4. First switch to kind 2. if (convert_string_buffer_kind(self, 1, 2) == CPY_NONE_ERROR) return CPY_NONE_ERROR; if ((uint32_t)value > 0xffff) { // Call recursively to switch from kind 2 to 4 return string_writer_switch_kind(self, value); } return CPY_NONE; } else { // Must be kind 2 -> 4 assert(self->kind == 2); assert((uint32_t)value > 0xffff); return convert_string_buffer_kind(self, 2, 4); } } // Handle all append cases except for append that stays within kind 1 static char string_append_slow_path(StringWriterObject *self, int32_t value) { if (self->kind == 2) { if ((uint32_t)value <= 0xffff) { // Fast path - kind 2 stays the same if (!ensure_string_writer_size(self, 1)) return CPY_NONE_ERROR; // Copy 2-byte character to buffer uint16_t val16 = (uint16_t)value; memcpy(self->buf + self->len * 2, &val16, 2); self->len++; return CPY_NONE; } // Always validate code point range before promotion (but after fast path). if (unlikely((uint32_t)value > 0x10FFFF)) goto fail_range; if (string_writer_switch_kind(self, value) == CPY_NONE_ERROR) return CPY_NONE_ERROR; return string_append_slow_path(self, value); } else if (self->kind == 1) { // Check precondition -- this must only be used on slow path assert((uint32_t)value > 0xff); if (unlikely((uint32_t)value > 0x10FFFF)) goto fail_range; if (string_writer_switch_kind(self, value) == CPY_NONE_ERROR) return CPY_NONE_ERROR; return string_append_slow_path(self, value); } assert(self->kind == 4); if (unlikely((uint32_t)value > 0x10FFFF)) goto fail_range; if (!ensure_string_writer_size(self, 1)) return CPY_NONE_ERROR; // Copy 4-byte character to buffer uint32_t val32 = (uint32_t)value; memcpy(self->buf + self->len * 4, &val32, 4); self->len++; return CPY_NONE; fail_range: PyErr_Format(PyExc_ValueError, "code point %d is outside valid Unicode range (0-1114111)", value); return CPY_NONE_ERROR; } static inline char StringWriter_append_internal(StringWriterObject *self, int32_t value) { char kind = self->kind; if (kind == 1 && (uint32_t)value < 256) { if (!ensure_string_writer_size(self, 1)) return CPY_NONE_ERROR; self->buf[self->len++] = value; self->kind = kind; return CPY_NONE; } return string_append_slow_path(self, value); } static PyObject* StringWriter_append(PyObject *self, PyObject *const *args, size_t nargs) { if (unlikely(nargs != 1)) { PyErr_Format(PyExc_TypeError, "append() takes exactly 1 argument (%zu given)", nargs); return NULL; } if (!check_string_writer(self)) { return NULL; } PyObject *value = args[0]; int32_t unboxed = CPyLong_AsInt32(value); if (unlikely(unboxed == CPY_LL_INT_ERROR && PyErr_Occurred())) { CPy_TypeError("i32", value); return NULL; } if (unlikely(StringWriter_append_internal((StringWriterObject *)self, unboxed) == CPY_NONE_ERROR)) { return NULL; } Py_INCREF(Py_None); return Py_None; } static PyTypeObject * StringWriter_type_internal(void) { return &StringWriterType; // Return borrowed reference }; static CPyTagged StringWriter_len_internal(PyObject *self) { StringWriterObject *writer = (StringWriterObject *)self; return writer->len << 1; } // End of StringWriter // Helper for write_*_le/be functions - validates args and returns BytesWriter static inline BytesWriterObject * parse_write_args(PyObject *const *args, size_t nargs, const char *func_name) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "%s() takes exactly 2 arguments (%zu given)", func_name, nargs); return NULL; } PyObject *writer = args[0]; if (!check_bytes_writer(writer)) { return NULL; } return (BytesWriterObject *)writer; } // Helper for read_*_le/be functions - validates args and returns data pointer // Returns NULL on error, sets *out_index to the validated index on success static inline const unsigned char * parse_read_args(PyObject *const *args, size_t nargs, const char *func_name, Py_ssize_t num_bytes, int64_t *out_index) { if (unlikely(nargs != 2)) { PyErr_Format(PyExc_TypeError, "%s() takes exactly 2 arguments (%zu given)", func_name, nargs); return NULL; } PyObject *bytes_obj = args[0]; if (unlikely(!PyBytes_Check(bytes_obj))) { PyErr_Format(PyExc_TypeError, "%s() argument 1 must be bytes", func_name); return NULL; } int64_t index = CPyLong_AsInt64(args[1]); if (unlikely(index == CPY_LL_INT_ERROR && PyErr_Occurred())) { return NULL; } if (unlikely(index < 0)) { PyErr_SetString(PyExc_ValueError, "index must be non-negative"); return NULL; } Py_ssize_t size = PyBytes_GET_SIZE(bytes_obj); if (unlikely(index > size - num_bytes)) { PyErr_Format(PyExc_IndexError, "index %lld out of range for bytes of length %zd", (long long)index, size); return NULL; } *out_index = index; return (const unsigned char *)PyBytes_AS_STRING(bytes_obj); } static PyObject* write_i16_le(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_i16_le"); if (bw == NULL) return NULL; int16_t unboxed = CPyLong_AsInt16(args[1]); if (unlikely(unboxed == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 2))) return NULL; BytesWriter_WriteI16LEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* write_i16_be(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_i16_be"); if (bw == NULL) return NULL; int16_t unboxed = CPyLong_AsInt16(args[1]); if (unlikely(unboxed == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 2))) return NULL; BytesWriter_WriteI16BEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* read_i16_le(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_i16_le", 2, &index); if (data == NULL) return NULL; return PyLong_FromLong(CPyBytes_ReadI16LEUnsafe(data + index)); } static PyObject* read_i16_be(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_i16_be", 2, &index); if (data == NULL) return NULL; return PyLong_FromLong(CPyBytes_ReadI16BEUnsafe(data + index)); } static PyObject* write_i32_le(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_i32_le"); if (bw == NULL) return NULL; int32_t unboxed = CPyLong_AsInt32(args[1]); if (unlikely(unboxed == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 4))) return NULL; BytesWriter_WriteI32LEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* write_i32_be(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_i32_be"); if (bw == NULL) return NULL; int32_t unboxed = CPyLong_AsInt32(args[1]); if (unlikely(unboxed == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 4))) return NULL; BytesWriter_WriteI32BEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* read_i32_le(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_i32_le", 4, &index); if (data == NULL) return NULL; return PyLong_FromLong(CPyBytes_ReadI32LEUnsafe(data + index)); } static PyObject* read_i32_be(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_i32_be", 4, &index); if (data == NULL) return NULL; return PyLong_FromLong(CPyBytes_ReadI32BEUnsafe(data + index)); } static PyObject* write_i64_le(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_i64_le"); if (bw == NULL) return NULL; int64_t unboxed = CPyLong_AsInt64(args[1]); if (unlikely(unboxed == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 8))) return NULL; BytesWriter_WriteI64LEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* write_i64_be(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_i64_be"); if (bw == NULL) return NULL; int64_t unboxed = CPyLong_AsInt64(args[1]); if (unlikely(unboxed == CPY_LL_INT_ERROR && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 8))) return NULL; BytesWriter_WriteI64BEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* read_i64_le(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_i64_le", 8, &index); if (data == NULL) return NULL; return PyLong_FromLongLong(CPyBytes_ReadI64LEUnsafe(data + index)); } static PyObject* read_i64_be(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_i64_be", 8, &index); if (data == NULL) return NULL; return PyLong_FromLongLong(CPyBytes_ReadI64BEUnsafe(data + index)); } static PyObject* write_f32_le(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_f32_le"); if (bw == NULL) return NULL; double unboxed = PyFloat_AsDouble(args[1]); if (unlikely(unboxed == -1.0 && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 4))) return NULL; BytesWriter_WriteF32LEUnsafe(bw, (float)unboxed); Py_RETURN_NONE; } static PyObject* write_f32_be(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_f32_be"); if (bw == NULL) return NULL; double unboxed = PyFloat_AsDouble(args[1]); if (unlikely(unboxed == -1.0 && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 4))) return NULL; BytesWriter_WriteF32BEUnsafe(bw, (float)unboxed); Py_RETURN_NONE; } static PyObject* read_f32_le(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_f32_le", 4, &index); if (data == NULL) return NULL; return PyFloat_FromDouble((double)CPyBytes_ReadF32LEUnsafe(data + index)); } static PyObject* read_f32_be(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_f32_be", 4, &index); if (data == NULL) return NULL; return PyFloat_FromDouble((double)CPyBytes_ReadF32BEUnsafe(data + index)); } static PyObject* write_f64_le(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_f64_le"); if (bw == NULL) return NULL; double unboxed = PyFloat_AsDouble(args[1]); if (unlikely(unboxed == -1.0 && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 8))) return NULL; BytesWriter_WriteF64LEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* write_f64_be(PyObject *module, PyObject *const *args, size_t nargs) { BytesWriterObject *bw = parse_write_args(args, nargs, "write_f64_be"); if (bw == NULL) return NULL; double unboxed = PyFloat_AsDouble(args[1]); if (unlikely(unboxed == -1.0 && PyErr_Occurred())) return NULL; if (unlikely(!ensure_bytes_writer_size(bw, 8))) return NULL; BytesWriter_WriteF64BEUnsafe(bw, unboxed); Py_RETURN_NONE; } static PyObject* read_f64_le(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_f64_le", 8, &index); if (data == NULL) return NULL; return PyFloat_FromDouble(CPyBytes_ReadF64LEUnsafe(data + index)); } static PyObject* read_f64_be(PyObject *module, PyObject *const *args, size_t nargs) { int64_t index; const unsigned char *data = parse_read_args(args, nargs, "read_f64_be", 8, &index); if (data == NULL) return NULL; return PyFloat_FromDouble(CPyBytes_ReadF64BEUnsafe(data + index)); } static PyMethodDef librt_strings_module_methods[] = { {"write_i16_le", (PyCFunction) write_i16_le, METH_FASTCALL, PyDoc_STR("Write a 16-bit signed integer to BytesWriter in little-endian format") }, {"write_i16_be", (PyCFunction) write_i16_be, METH_FASTCALL, PyDoc_STR("Write a 16-bit signed integer to BytesWriter in big-endian format") }, {"read_i16_le", (PyCFunction) read_i16_le, METH_FASTCALL, PyDoc_STR("Read a 16-bit signed integer from bytes in little-endian format") }, {"read_i16_be", (PyCFunction) read_i16_be, METH_FASTCALL, PyDoc_STR("Read a 16-bit signed integer from bytes in big-endian format") }, {"write_i32_le", (PyCFunction) write_i32_le, METH_FASTCALL, PyDoc_STR("Write a 32-bit signed integer to BytesWriter in little-endian format") }, {"write_i32_be", (PyCFunction) write_i32_be, METH_FASTCALL, PyDoc_STR("Write a 32-bit signed integer to BytesWriter in big-endian format") }, {"read_i32_le", (PyCFunction) read_i32_le, METH_FASTCALL, PyDoc_STR("Read a 32-bit signed integer from bytes in little-endian format") }, {"read_i32_be", (PyCFunction) read_i32_be, METH_FASTCALL, PyDoc_STR("Read a 32-bit signed integer from bytes in big-endian format") }, {"write_i64_le", (PyCFunction) write_i64_le, METH_FASTCALL, PyDoc_STR("Write a 64-bit signed integer to BytesWriter in little-endian format") }, {"write_i64_be", (PyCFunction) write_i64_be, METH_FASTCALL, PyDoc_STR("Write a 64-bit signed integer to BytesWriter in big-endian format") }, {"read_i64_le", (PyCFunction) read_i64_le, METH_FASTCALL, PyDoc_STR("Read a 64-bit signed integer from bytes in little-endian format") }, {"read_i64_be", (PyCFunction) read_i64_be, METH_FASTCALL, PyDoc_STR("Read a 64-bit signed integer from bytes in big-endian format") }, {"write_f32_le", (PyCFunction) write_f32_le, METH_FASTCALL, PyDoc_STR("Write a 32-bit float to BytesWriter in little-endian format") }, {"write_f32_be", (PyCFunction) write_f32_be, METH_FASTCALL, PyDoc_STR("Write a 32-bit float to BytesWriter in big-endian format") }, {"read_f32_le", (PyCFunction) read_f32_le, METH_FASTCALL, PyDoc_STR("Read a 32-bit float from bytes in little-endian format") }, {"read_f32_be", (PyCFunction) read_f32_be, METH_FASTCALL, PyDoc_STR("Read a 32-bit float from bytes in big-endian format") }, {"write_f64_le", (PyCFunction) write_f64_le, METH_FASTCALL, PyDoc_STR("Write a 64-bit float to BytesWriter in little-endian format") }, {"write_f64_be", (PyCFunction) write_f64_be, METH_FASTCALL, PyDoc_STR("Write a 64-bit float to BytesWriter in big-endian format") }, {"read_f64_le", (PyCFunction) read_f64_le, METH_FASTCALL, PyDoc_STR("Read a 64-bit float from bytes in little-endian format") }, {"read_f64_be", (PyCFunction) read_f64_be, METH_FASTCALL, PyDoc_STR("Read a 64-bit float from bytes in big-endian format") }, {NULL, NULL, 0, NULL} }; static int strings_abi_version(void) { return LIBRT_STRINGS_ABI_VERSION; } static int strings_api_version(void) { return LIBRT_STRINGS_API_VERSION; } static int librt_strings_module_exec(PyObject *m) { if (PyType_Ready(&BytesWriterType) < 0) { return -1; } if (PyType_Ready(&StringWriterType) < 0) { return -1; } if (PyModule_AddObjectRef(m, "BytesWriter", (PyObject *) &BytesWriterType) < 0) { return -1; } if (PyModule_AddObjectRef(m, "StringWriter", (PyObject *) &StringWriterType) < 0) { return -1; } // Export mypy internal C API, be careful with the order! static void *librt_strings_api[LIBRT_STRINGS_API_LEN] = { (void *)strings_abi_version, (void *)strings_api_version, (void *)BytesWriter_internal, (void *)BytesWriter_getvalue_internal, (void *)BytesWriter_append_internal, (void *)_grow_buffer, (void *)BytesWriter_type_internal, (void *)BytesWriter_truncate_internal, (void *)StringWriter_internal, (void *)StringWriter_getvalue_internal, (void *)string_append_slow_path, (void *)StringWriter_type_internal, (void *)StringWriter_write_internal, (void *)grow_string_buffer, }; PyObject *c_api_object = PyCapsule_New((void *)librt_strings_api, "librt.strings._C_API", NULL); if (PyModule_Add(m, "_C_API", c_api_object) < 0) { return -1; } return 0; } static PyModuleDef_Slot librt_strings_module_slots[] = { {Py_mod_exec, librt_strings_module_exec}, #ifdef Py_MOD_GIL_NOT_USED {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} }; static PyModuleDef librt_strings_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "strings", .m_doc = "Utilities for working with str and bytes objects", .m_size = 0, .m_methods = librt_strings_module_methods, .m_slots = librt_strings_module_slots, }; PyMODINIT_FUNC PyInit_strings(void) { intern_strings(); return PyModuleDef_Init(&librt_strings_module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/strings/librt_strings.h0000644000175100017510000000215315200142331017072 0ustar00runnerrunner#ifndef LIBRT_STRINGS_H #define LIBRT_STRINGS_H #include #include #include "librt_strings_common.h" // ABI version -- only an exact match is compatible. This will only be changed in // very exceptional cases (likely never) due to strict backward compatibility // requirements. #define LIBRT_STRINGS_ABI_VERSION 1 // API version -- more recent versions must maintain backward compatibility, i.e. // we can add new features but not remove or change existing features (unless // ABI version is changed, but see the comment above). #define LIBRT_STRINGS_API_VERSION 4 // Number of functions in the capsule API. If you add a new function, also increase // LIBRT_STRINGS_API_VERSION. #define LIBRT_STRINGS_API_LEN 14 typedef struct { PyObject_HEAD char *buf; // Beginning of the buffer char kind; // Bytes per code point (1, 2 or 4) Py_ssize_t len; // Current length (number of code points written) Py_ssize_t capacity; // Total capacity of the buffer (number of code points) char data[WRITER_EMBEDDED_BUF_LEN]; // Default buffer } StringWriterObject; #endif // LIBRT_STRINGS_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/strings/librt_strings_api.c0000644000175100017510000000306415200142331017720 0ustar00runnerrunner#include "librt_strings_api.h" void *LibRTStrings_API[LIBRT_STRINGS_API_LEN] = {0}; int import_librt_strings(void) { PyObject *mod = PyImport_ImportModule("librt.strings"); if (mod == NULL) return -1; Py_DECREF(mod); // we import just for the side effect of making the below work. void **capsule = (void **)PyCapsule_Import("librt.strings._C_API", 0); if (capsule == NULL) return -1; // Only after version validation succeeds can we safely copy the full table. int (*abi_version)(void) = (int (*)(void))capsule[0]; int (*api_version)(void) = (int (*)(void))capsule[1]; if (abi_version() != LIBRT_STRINGS_ABI_VERSION) { char err[128]; snprintf(err, sizeof(err), "ABI version conflict for librt.strings, expected %d, found %d", LIBRT_STRINGS_ABI_VERSION, abi_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } if (api_version() < LIBRT_STRINGS_API_VERSION) { char err[128]; snprintf(err, sizeof(err), "API version conflict for librt.strings, expected %d or newer, found %d (hint: upgrade librt)", LIBRT_STRINGS_API_VERSION, api_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } // Provider API version is >= our expected version, which (by the API // compatibility contract) means it has at least LIBRT_STRINGS_API_LEN // entries, so this copy is safe. memcpy(LibRTStrings_API, capsule, sizeof(LibRTStrings_API)); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/strings/librt_strings_api.h0000644000175100017510000000363315200142331017727 0ustar00runnerrunner#ifndef LIBRT_STRINGS_API_H #define LIBRT_STRINGS_API_H int import_librt_strings(void); #include #include #include "librt_strings.h" extern void *LibRTStrings_API[LIBRT_STRINGS_API_LEN]; #define LibRTStrings_ABIVersion (*(int (*)(void)) LibRTStrings_API[0]) #define LibRTStrings_APIVersion (*(int (*)(void)) LibRTStrings_API[1]) #define LibRTStrings_BytesWriter_internal (*(PyObject* (*)(void)) LibRTStrings_API[2]) #define LibRTStrings_BytesWriter_getvalue_internal (*(PyObject* (*)(PyObject *source)) LibRTStrings_API[3]) #define LibRTStrings_BytesWriter_append_internal (*(char (*)(PyObject *source, uint8_t value)) LibRTStrings_API[4]) #define LibRTStrings_ByteWriter_grow_buffer_internal (*(bool (*)(BytesWriterObject *obj, Py_ssize_t size)) LibRTStrings_API[5]) #define LibRTStrings_BytesWriter_type_internal (*(PyTypeObject* (*)(void)) LibRTStrings_API[6]) #define LibRTStrings_BytesWriter_truncate_internal (*(char (*)(PyObject *self, int64_t size)) LibRTStrings_API[7]) #define LibRTStrings_StringWriter_internal (*(PyObject* (*)(void)) LibRTStrings_API[8]) #define LibRTStrings_StringWriter_getvalue_internal (*(PyObject* (*)(PyObject *source)) LibRTStrings_API[9]) #define LibRTStrings_string_append_slow_path (*(char (*)(StringWriterObject *obj, int32_t value)) LibRTStrings_API[10]) #define LibRTStrings_StringWriter_type_internal (*(PyTypeObject* (*)(void)) LibRTStrings_API[11]) #define LibRTStrings_StringWriter_write_internal (*(char (*)(PyObject *source, PyObject *value)) LibRTStrings_API[12]) #define LibRTStrings_grow_string_buffer (*(bool (*)(StringWriterObject *obj, Py_ssize_t n)) LibRTStrings_API[13]) static inline bool CPyBytesWriter_Check(PyObject *obj) { return Py_TYPE(obj) == LibRTStrings_BytesWriter_type_internal(); } static inline bool CPyStringWriter_Check(PyObject *obj) { return Py_TYPE(obj) == LibRTStrings_StringWriter_type_internal(); } #endif // LIBRT_STRINGS_API_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/strings/librt_strings_common.h0000644000175100017510000002657415200142331020457 0ustar00runnerrunner#ifndef LIBRT_STRINGS_COMMON_H #define LIBRT_STRINGS_COMMON_H #include #include #include // Byte-swap functions for endianness conversion (needed for both LE and BE operations) #if defined(_MSC_VER) # include # define BSWAP16(x) _byteswap_ushort(x) # define BSWAP32(x) _byteswap_ulong(x) # define BSWAP64(x) _byteswap_uint64(x) #elif defined(__GNUC__) || defined(__clang__) # define BSWAP16(x) __builtin_bswap16(x) # define BSWAP32(x) __builtin_bswap32(x) # define BSWAP64(x) __builtin_bswap64(x) #else // Fallback for other compilers (slower but portable) static inline uint16_t BSWAP16(uint16_t x) { return (uint16_t)((x >> 8) | (x << 8)); } static inline uint32_t BSWAP32(uint32_t x) { return ((x >> 24) & 0xFFU) | ((x >> 8) & 0xFF00U) | ((x << 8) & 0xFF0000U) | ((x << 24) & 0xFF000000U); } static inline uint64_t BSWAP64(uint64_t x) { return ((x >> 56) & 0xFFULL) | ((x >> 40) & 0xFF00ULL) | ((x >> 24) & 0xFF0000ULL) | ((x >> 8) & 0xFF000000ULL) | ((x << 8) & 0xFF00000000ULL) | ((x << 24) & 0xFF0000000000ULL) | ((x << 40) & 0xFF000000000000ULL) | ((x << 56) & 0xFF00000000000000ULL); } #endif // Length of the default buffer embedded directly in a BytesWriter object #define WRITER_EMBEDDED_BUF_LEN 256 typedef struct { PyObject_HEAD char *buf; // Beginning of the buffer Py_ssize_t len; // Current length (number of bytes written) Py_ssize_t capacity; // Total capacity of the buffer char data[WRITER_EMBEDDED_BUF_LEN]; // Default buffer } BytesWriterObject; // Write a 16-bit signed integer in little-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteI16LEUnsafe(BytesWriterObject *self, int16_t value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN uint16_t swapped = BSWAP16((uint16_t)value); memcpy(self->buf + self->len, &swapped, 2); #else memcpy(self->buf + self->len, &value, 2); #endif self->len += 2; } // Write a 16-bit signed integer in big-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteI16BEUnsafe(BytesWriterObject *self, int16_t value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN memcpy(self->buf + self->len, &value, 2); #else uint16_t swapped = BSWAP16((uint16_t)value); memcpy(self->buf + self->len, &swapped, 2); #endif self->len += 2; } // Read a 16-bit signed integer in little-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline int16_t CPyBytes_ReadI16LEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC uint16_t value; memcpy(&value, data, 2); #if PY_BIG_ENDIAN value = BSWAP16(value); #endif return (int16_t)value; } // Read a 16-bit signed integer in big-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline int16_t CPyBytes_ReadI16BEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC uint16_t value; memcpy(&value, data, 2); #if PY_BIG_ENDIAN // Already in big-endian format, no swap needed #else value = BSWAP16(value); #endif return (int16_t)value; } // Write a 32-bit signed integer in little-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteI32LEUnsafe(BytesWriterObject *self, int32_t value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN uint32_t swapped = BSWAP32((uint32_t)value); memcpy(self->buf + self->len, &swapped, 4); #else memcpy(self->buf + self->len, &value, 4); #endif self->len += 4; } // Write a 32-bit signed integer in big-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteI32BEUnsafe(BytesWriterObject *self, int32_t value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN memcpy(self->buf + self->len, &value, 4); #else uint32_t swapped = BSWAP32((uint32_t)value); memcpy(self->buf + self->len, &swapped, 4); #endif self->len += 4; } // Read a 32-bit signed integer in little-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline int32_t CPyBytes_ReadI32LEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC uint32_t value; memcpy(&value, data, 4); #if PY_BIG_ENDIAN value = BSWAP32(value); #endif return (int32_t)value; } // Read a 32-bit signed integer in big-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline int32_t CPyBytes_ReadI32BEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC uint32_t value; memcpy(&value, data, 4); #if PY_BIG_ENDIAN // Already in big-endian format, no swap needed #else value = BSWAP32(value); #endif return (int32_t)value; } // Write a 64-bit signed integer in little-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteI64LEUnsafe(BytesWriterObject *self, int64_t value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN uint64_t swapped = BSWAP64((uint64_t)value); memcpy(self->buf + self->len, &swapped, 8); #else memcpy(self->buf + self->len, &value, 8); #endif self->len += 8; } // Write a 64-bit signed integer in big-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteI64BEUnsafe(BytesWriterObject *self, int64_t value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN memcpy(self->buf + self->len, &value, 8); #else uint64_t swapped = BSWAP64((uint64_t)value); memcpy(self->buf + self->len, &swapped, 8); #endif self->len += 8; } // Read a 64-bit signed integer in little-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline int64_t CPyBytes_ReadI64LEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC uint64_t value; memcpy(&value, data, 8); #if PY_BIG_ENDIAN value = BSWAP64(value); #endif return (int64_t)value; } // Read a 64-bit signed integer in big-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline int64_t CPyBytes_ReadI64BEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC uint64_t value; memcpy(&value, data, 8); #if PY_BIG_ENDIAN // Already in big-endian format, no swap needed #else value = BSWAP64(value); #endif return (int64_t)value; } // Write a 32-bit float in little-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteF32LEUnsafe(BytesWriterObject *self, float value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN uint32_t bits; memcpy(&bits, &value, 4); bits = BSWAP32(bits); memcpy(self->buf + self->len, &bits, 4); #else memcpy(self->buf + self->len, &value, 4); #endif self->len += 4; } // Write a 32-bit float in big-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteF32BEUnsafe(BytesWriterObject *self, float value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN memcpy(self->buf + self->len, &value, 4); #else uint32_t bits; memcpy(&bits, &value, 4); bits = BSWAP32(bits); memcpy(self->buf + self->len, &bits, 4); #endif self->len += 4; } // Read a 32-bit float in little-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline float CPyBytes_ReadF32LEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC float value; #if PY_BIG_ENDIAN uint32_t bits; memcpy(&bits, data, 4); bits = BSWAP32(bits); memcpy(&value, &bits, 4); #else memcpy(&value, data, 4); #endif return value; } // Read a 32-bit float in big-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline float CPyBytes_ReadF32BEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC float value; #if PY_BIG_ENDIAN memcpy(&value, data, 4); #else uint32_t bits; memcpy(&bits, data, 4); bits = BSWAP32(bits); memcpy(&value, &bits, 4); #endif return value; } // Write a 64-bit float (double) in little-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteF64LEUnsafe(BytesWriterObject *self, double value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN uint64_t bits; memcpy(&bits, &value, 8); bits = BSWAP64(bits); memcpy(self->buf + self->len, &bits, 8); #else memcpy(self->buf + self->len, &value, 8); #endif self->len += 8; } // Write a 64-bit float (double) in big-endian format to BytesWriter. // NOTE: This does NOT check buffer capacity - caller must ensure space is available. static inline void BytesWriter_WriteF64BEUnsafe(BytesWriterObject *self, double value) { // memcpy is reliably optimized to a single store by GCC, Clang, and MSVC #if PY_BIG_ENDIAN memcpy(self->buf + self->len, &value, 8); #else uint64_t bits; memcpy(&bits, &value, 8); bits = BSWAP64(bits); memcpy(self->buf + self->len, &bits, 8); #endif self->len += 8; } // Read a 64-bit float (double) in little-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline double CPyBytes_ReadF64LEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC double value; #if PY_BIG_ENDIAN uint64_t bits; memcpy(&bits, data, 8); bits = BSWAP64(bits); memcpy(&value, &bits, 8); #else memcpy(&value, data, 8); #endif return value; } // Read a 64-bit float (double) in big-endian format from bytes. // NOTE: This does NOT check bounds - caller must ensure valid index. static inline double CPyBytes_ReadF64BEUnsafe(const unsigned char *data) { // memcpy is reliably optimized to a single load by GCC, Clang, and MSVC double value; #if PY_BIG_ENDIAN memcpy(&value, data, 8); #else uint64_t bits; memcpy(&bits, data, 8); bits = BSWAP64(bits); memcpy(&value, &bits, 8); #endif return value; } #endif // LIBRT_STRINGS_COMMON_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/stringwriter_extra_ops.c0000644000175100017510000000051515200142331017336 0ustar00runnerrunner// Primitives related to librt.strings.StringWriter that get linked statically // with compiled modules, instead of being called via a capsule. #include "stringwriter_extra_ops.h" // All StringWriter operations are currently implemented as inline functions // in stringwriter_extra_ops.h, or use the exported capsule API directly. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/stringwriter_extra_ops.h0000644000175100017510000000414315200142331017344 0ustar00runnerrunner#ifndef STRINGWRITER_EXTRA_OPS_H #define STRINGWRITER_EXTRA_OPS_H #include #include #include #include "mypyc_util.h" #include "strings/librt_strings_api.h" static inline CPyTagged CPyStringWriter_Len(PyObject *obj) { return (CPyTagged)((StringWriterObject *)obj)->len << 1; } static inline bool CPyStringWriter_EnsureSize(StringWriterObject *data, Py_ssize_t n) { if (likely(data->capacity - data->len >= n)) { return true; } else { return LibRTStrings_grow_string_buffer(data, n); } } static inline char CPyStringWriter_Append(PyObject *obj, int32_t value) { StringWriterObject *self = (StringWriterObject *)obj; char kind = self->kind; // Fast path: kind 1 (ASCII/Latin-1) with character < 256 if (kind == 1 && (uint32_t)value < 256) { // Store length in local variable to enable additional optimizations Py_ssize_t len = self->len; if (!CPyStringWriter_EnsureSize(self, 1)) return CPY_NONE_ERROR; self->buf[len] = (char)value; self->len = len + 1; return CPY_NONE; } // Slow path: handles kind switching and other cases return LibRTStrings_string_append_slow_path(self, value); } // If index is negative, convert to non-negative index (no range checking) static inline int64_t CPyStringWriter_AdjustIndex(PyObject *obj, int64_t index) { if (index < 0) { return index + ((StringWriterObject *)obj)->len; } return index; } static inline bool CPyStringWriter_RangeCheck(PyObject *obj, int64_t index) { return index >= 0 && index < ((StringWriterObject *)obj)->len; } static inline int32_t CPyStringWriter_GetItem(PyObject *obj, int64_t index) { StringWriterObject *self = (StringWriterObject *)obj; char kind = self->kind; char *buf = self->buf; if (kind == 1) { return (uint8_t)buf[index]; } else if (kind == 2) { uint16_t val; memcpy(&val, buf + index * 2, 2); return (int32_t)val; } else { uint32_t val; memcpy(&val, buf + index * 4, 4); return (int32_t)val; } } #endif ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1778435292.859478 librt-0.11.0/time/0000755000175100017510000000000015200142335013304 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/time/librt_time.c0000644000175100017510000000717315200142331015606 0ustar00runnerrunner#define PY_SSIZE_T_CLEAN #include #include #include #include "librt_time.h" #include "pythoncapi_compat.h" #include "mypyc_util.h" #ifdef _WIN32 #include #else #include #endif // Internal function that returns a C double for mypyc primitives // Returns high-precision time in seconds (like time.time()) static double time_time_internal(void) { #ifdef _WIN32 // Windows: Use GetSystemTimePreciseAsFileTime for ~100ns precision FILETIME ft; ULARGE_INTEGER large; GetSystemTimePreciseAsFileTime(&ft); large.LowPart = ft.dwLowDateTime; large.HighPart = ft.dwHighDateTime; // Windows FILETIME is 100-nanosecond intervals since January 1, 1601 // 116444736000000000 = number of 100-ns intervals between 1601 and 1970 // Convert directly to seconds: 100ns * 1e-9 = 1e-7 int64_t intervals = large.QuadPart - 116444736000000000LL; return (double)intervals * 1e-7; #else // Unix-like systems (Linux, macOS, BSD, etc.) // Try clock_gettime(CLOCK_REALTIME) for nanosecond precision // This is available on POSIX.1-2001 and later (widely available on modern systems) #if defined(_POSIX_TIMERS) && _POSIX_TIMERS > 0 struct timespec ts; if (clock_gettime(CLOCK_REALTIME, &ts) == 0) { // Convert seconds and nanoseconds separately to avoid large integer operations return (double)ts.tv_sec + (double)ts.tv_nsec * 1e-9; } // Fall through to gettimeofday if clock_gettime failed #endif // Fallback: gettimeofday for microsecond precision // This is widely available (POSIX.1-2001, BSD, etc.) struct timeval tv; if (unlikely(gettimeofday(&tv, NULL) != 0)) { PyErr_SetFromErrno(PyExc_OSError); return CPY_FLOAT_ERROR; } // Convert seconds and microseconds separately to avoid large integer operations return (double)tv.tv_sec + (double)tv.tv_usec * 1e-6; #endif } // Wrapper function for normal Python extension usage static PyObject* time_time(PyObject *self, PyObject *const *args, size_t nargs) { if (nargs != 0) { PyErr_SetString(PyExc_TypeError, "time() takes no arguments"); return NULL; } double result = time_time_internal(); if (result == CPY_FLOAT_ERROR) { return NULL; } return PyFloat_FromDouble(result); } static PyMethodDef librt_time_module_methods[] = { {"time", (PyCFunction)time_time, METH_FASTCALL, PyDoc_STR("Return the current time in seconds since the Unix epoch as a floating point number.")}, {NULL, NULL, 0, NULL} }; static int time_abi_version(void) { return LIBRT_TIME_ABI_VERSION; } static int time_api_version(void) { return LIBRT_TIME_API_VERSION; } static int librt_time_module_exec(PyObject *m) { // Export mypyc internal C API via capsule static void *time_api[LIBRT_TIME_API_LEN] = { (void *)time_abi_version, (void *)time_api_version, (void *)time_time_internal, }; PyObject *c_api_object = PyCapsule_New((void *)time_api, "librt.time._C_API", NULL); if (PyModule_Add(m, "_C_API", c_api_object) < 0) { return -1; } return 0; } static PyModuleDef_Slot librt_time_module_slots[] = { {Py_mod_exec, librt_time_module_exec}, #ifdef Py_MOD_GIL_NOT_USED {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} }; static PyModuleDef librt_time_module = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "time", .m_doc = "Fast time() function optimized for mypyc", .m_size = 0, .m_methods = librt_time_module_methods, .m_slots = librt_time_module_slots, }; PyMODINIT_FUNC PyInit_time(void) { return PyModuleDef_Init(&librt_time_module); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/time/librt_time.h0000644000175100017510000000027015200142331015602 0ustar00runnerrunner#ifndef LIBRT_TIME_H #define LIBRT_TIME_H #include #define LIBRT_TIME_ABI_VERSION 1 #define LIBRT_TIME_API_VERSION 1 #define LIBRT_TIME_API_LEN 3 #endif // LIBRT_TIME_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/time/librt_time_api.c0000644000175100017510000000300715200142331016427 0ustar00runnerrunner#include "librt_time_api.h" void *LibRTTime_API[LIBRT_TIME_API_LEN] = {0}; int import_librt_time(void) { PyObject *mod = PyImport_ImportModule("librt.time"); if (mod == NULL) return -1; Py_DECREF(mod); // we import just for the side effect of making the below work. void **capsule = (void **)PyCapsule_Import("librt.time._C_API", 0); if (capsule == NULL) return -1; // Only after version validation succeeds can we safely copy the full table. int (*abi_version)(void) = (int (*)(void))capsule[0]; int (*api_version)(void) = (int (*)(void))capsule[1]; if (abi_version() != LIBRT_TIME_ABI_VERSION) { char err[128]; snprintf(err, sizeof(err), "ABI version conflict for librt.time, expected %d, found %d", LIBRT_TIME_ABI_VERSION, abi_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } if (api_version() < LIBRT_TIME_API_VERSION) { char err[128]; snprintf(err, sizeof(err), "API version conflict for librt.time, expected %d or newer, found %d (hint: upgrade librt)", LIBRT_TIME_API_VERSION, api_version() ); PyErr_SetString(PyExc_ValueError, err); return -1; } // Provider API version is >= our expected version, which (by the API // compatibility contract) means it has at least LIBRT_TIME_API_LEN // entries, so this copy is safe. memcpy(LibRTTime_API, capsule, sizeof(LibRTTime_API)); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/time/librt_time_api.h0000644000175100017510000000057015200142331016436 0ustar00runnerrunner#ifndef LIBRT_TIME_API_H #define LIBRT_TIME_API_H #include "librt_time.h" int import_librt_time(void); extern void *LibRTTime_API[LIBRT_TIME_API_LEN]; #define LibRTTime_ABIVersion (*(int (*)(void)) LibRTTime_API[0]) #define LibRTTime_APIVersion (*(int (*)(void)) LibRTTime_API[1]) #define LibRTTime_time (*(double (*)(void)) LibRTTime_API[2]) #endif // LIBRT_TIME_API_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/tuple_ops.c0000644000175100017510000000364415200142331014527 0ustar00runnerrunner// Tuple primitive operations // // These are registered in mypyc.primitives.tuple_ops. #include #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); } // No error checking PyObject *CPySequenceTuple_GetItemUnsafe(PyObject *tuple, Py_ssize_t index) { PyObject *result = PyTuple_GET_ITEM(tuple, index); Py_INCREF(result); return result; } // PyTuple_SET_ITEM does no error checking, // and should only be used to fill in brand new tuples. void CPySequenceTuple_SetItemUnsafe(PyObject *tuple, Py_ssize_t index, PyObject *value) { PyTuple_SET_ITEM(tuple, index, value); } ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1778435292.8620987 librt-0.11.0/vecs/0000755000175100017510000000000015200142335013306 5ustar00runnerrunner././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/librt_vecs.c0000644000175100017510000010640015200142331015603 0ustar00runnerrunner// Definition of the mypyc.vecs module, which implements 'vec' and related functionality. // // NOTE: This is still experimental and work in progress. // // vec[t] is a sequence type that is optimized for use in mypyc-compiled code. // Performance in interpreted code is a secondary concern. It's primarily optimized // to provide fast item get/set operations and fast len(), especially for primitive // value item types, such as 'i32', 'float' or 'bool'. // // Example: // // from mypy_extensions import i64 // // v = vec[i64]() // v = append(v, 123) // print(v[0]) // v[-1] = 234 // // Key properties: // // * In native code, a vec instance is an immutable value type with two fields // (length, item buffer). // * The item buffer can only store types of a specific type (enforced at runtime). // * There are specialized item buffer types for certain primitive value item types, // such as 'i32', 'float' and 'bool'. These use a packed value encoding. // * Since vec values are immutable (only the buffer is mutable), any operation // that changes the length (such as append) must return the updated vec value. // * The buffer often a has higher capacity than the length of a vec. Append // operations only allocate a new buffer if the capacity is exhausted, for O(1) // amortized time complexity for appends. // * Vec values can be boxed to PyObject *; this happens transparently and uses // a wrapper object. // * The item type can be a class type, or 't | None' if t is a class type. However, // optional value item types such as 'float | None' are not supported, and 'int' // is not valid as item type -- a native integer type such as `i64` or `u8` must // be used instead. // * Nested vecs are also supported (e.g. vec[vec[i32]]). // * All features are also available in interpreted code, but often at some // performance cost compared to using plain lists. // // Implementation summary: // // * In a non-native context, instances are constructed via a temporary VecGenericAlias // object, which is the result of 'vec[]' (indexing the 'vec' type). // * The module exports a C API via a capsule that mypyc compiled code uses for most // operations. // * There are multiple C structs that represent vec value objects with different item // types, such as VecI64 and VecT. The latter is for arbitrary reference objects // ('PyObject *' items internally). // * There are also multiple buffer types, such as VecI64Buf and VecTBuf. // * Similarly, there are multiple Python wrapper object types for boxed vecs, such as // VecI64Type and VecTType. // * An empty vec in compiled code can use a NULL pointer to represent the buffer, // saving an object allocation in a common use case. // // Motivation: // * A vec with value type items, such as vec[i64] or vec[vec[i32]], is very efficient // compared to a list object, since values are not boxed, there is no need for runtime // type checks on read, and index overflow checks are very fast due to the immutable // value encoding. // * A vec with a reference item type, such as vec[str], is often faster than a list, // since there is no need for a cast on item read and the index checks are faster // (among other things), but here the benefit is much smaller compared to using a // value item type. // // Summary of files: // * vec_t.c implements vec[t] and vec[t | None] for reference types // * vec_nested.c implements nested vecs, such as vec[vec[str]] // * vec_template.c is #included in multiples files (e.g. vec_i64.c) to produce // specialized code for vecs with value item types (e.g. vec[i64]) // * This file defines the C extension and has some shared code #define PY_SSIZE_T_CLEAN #include #include "librt_vecs.h" PyTypeObject *LibRTVecs_I64TypeObj; PyTypeObject *LibRTVecs_I32TypeObj; PyTypeObject *LibRTVecs_I16TypeObj; PyTypeObject *LibRTVecs_U8TypeObj; // vec generic alias // // Used for the result of vec[t] (indexing) in interpreted context that must preserve // knowledge of 't'. These aren't real types. This only supports constructing instances. typedef struct { PyObject_HEAD // Tagged pointer to PyTypeObject *, lowest bit set for optional item type // Can also be one of magic VEC_ITEM_TYPE_* constants size_t item_type; size_t depth; // Number of nested VecNested or VecT types } VecGenericAlias; static PyObject *vec_generic_alias_call(PyObject *self, PyObject *args, PyObject *kw) { static char *kwlist[] = {"", "capacity", NULL}; PyObject *init = NULL; int64_t cap = 0; if (!PyArg_ParseTupleAndKeywords(args, kw, "|OL:vec", kwlist, &init, &cap)) { return NULL; } if (cap < 0) { PyErr_SetString(PyExc_ValueError, "capacity must not be negative"); return NULL; } VecGenericAlias *p = (VecGenericAlias *)self; if (p->depth == 0) { if (init == NULL) { VecT vec = VecT_New(0, cap, p->item_type); if (VEC_IS_ERROR(vec)) return NULL; return VecT_Box(vec, p->item_type); } else { VecT vec = VecT_FromIterable(p->item_type, init, cap); if (VEC_IS_ERROR(vec)) return NULL; return VecT_Box(vec, p->item_type); } } else { if (init == NULL) { VecNested vec = VecNested_New(0, cap, p->item_type, p->depth); if (VEC_IS_ERROR(vec)) return NULL; return VecNested_Box(vec); } else { return VecNested_FromIterable(p->item_type, p->depth, init, cap); } } } static int VecGenericAlias_traverse(VecGenericAlias *self, visitproc visit, void *arg) { if (!Vec_IsMagicItemType(self->item_type)) Py_VISIT((PyObject *)(self->item_type & ~1)); return 0; } static void VecGenericAlias_dealloc(VecGenericAlias *self) { PyObject_GC_UnTrack(self); if (self->item_type && !Vec_IsMagicItemType(self->item_type)) { Py_DECREF((PyObject *)(self->item_type & ~1)); self->item_type = 0; } PyObject_GC_Del(self); } PyObject *Vec_TypeToStr(size_t item_type, size_t depth) { PyObject *item = NULL; PyObject *result = NULL; if (depth == 0) { if ((item_type & ~1) == VEC_ITEM_TYPE_I64) { item = PyUnicode_FromFormat("i64"); } else if ((item_type & ~1) == VEC_ITEM_TYPE_U8) { item = PyUnicode_FromFormat("u8"); } else if ((item_type & ~1) == VEC_ITEM_TYPE_FLOAT) { item = PyUnicode_FromFormat("float"); } else if ((item_type & ~1) == VEC_ITEM_TYPE_I32) { item = PyUnicode_FromFormat("i32"); } else if ((item_type & ~1) == VEC_ITEM_TYPE_I16) { item = PyUnicode_FromFormat("i16"); } else if ((item_type & ~1) == VEC_ITEM_TYPE_BOOL) { item = PyUnicode_FromFormat("bool"); } else { item = PyObject_GetAttrString((PyObject *)(item_type & ~1), "__name__"); if (item == NULL) { return NULL; } if (item_type & 1) { PyObject *optional_item = PyUnicode_FromFormat("%U | None", item); Py_DECREF(item); if (optional_item == NULL) { return NULL; } item = optional_item; } } } else { item = Vec_TypeToStr(item_type, depth - 1); } if (item == NULL) { return NULL; } result = PyUnicode_FromFormat("vec[%U]", item); Py_DECREF(item); return result; } PyObject *VecGenericAlias_repr(PyObject *self) { PyObject *l = NULL; PyObject *prefix = NULL; PyObject *suffix = NULL; PyObject *sep = NULL; PyObject *type_str = NULL; PyObject *result = NULL; l = PyList_New(0); if (l == NULL) goto error; prefix = PyUnicode_FromString(""); if (suffix == NULL) goto error; sep = PyUnicode_FromString(""); if (sep == NULL) goto error; if (PyList_Append(l, prefix) < 0) goto error; VecGenericAlias *v = (VecGenericAlias *)self; type_str = Vec_TypeToStr(v->item_type, v->depth); if (type_str == NULL) goto error; if (PyList_Append(l, type_str) < 0) goto error; if (PyList_Append(l, suffix) < 0) goto error; result = PyUnicode_Join(sep, l); error: Py_XDECREF(l); Py_XDECREF(prefix); Py_XDECREF(suffix); Py_XDECREF(sep); Py_XDECREF(type_str); return result; } PyTypeObject VecGenericAliasType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec_generic_alias", .tp_basicsize = sizeof(VecGenericAlias), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_call = vec_generic_alias_call, .tp_traverse = (traverseproc)VecGenericAlias_traverse, .tp_dealloc = (destructor)VecGenericAlias_dealloc, .tp_repr = (reprfunc)VecGenericAlias_repr, }; // The 'vec' type // // This cannot be instantiated, and it's only used for isinstance and indexing: vec[T]. // All specialized vec types (VecI64Type, VecI32Type, etc.) inherit from this base type, // so isinstance(v, vec) returns True for any specialized vec instance. static PyObject *extract_optional_item(PyObject *item) { PyObject *args = PyObject_GetAttrString(item, "__args__"); if (args == NULL) { PyErr_Clear(); return NULL; } if (!PyTuple_CheckExact(args)) goto error; if (PyTuple_GET_SIZE(args) != 2) goto error; PyObject *item0 = PyTuple_GET_ITEM(args, 0); PyObject *item1 = PyTuple_GET_ITEM(args, 1); if (item0 == (PyObject *)Py_None->ob_type) { Py_DECREF(args); return item1; } else if (item1 == (PyObject *)Py_None->ob_type) { Py_DECREF(args); return item0; } error: Py_DECREF(args); return NULL; } // Evaluation vec[] in interpreted code and produce a generic alias object. static PyObject *vec_class_getitem(PyObject *type, PyObject *item) { if (item == (PyObject *)LibRTVecs_I64TypeObj) { Py_INCREF(&VecI64Type); return (PyObject *)&VecI64Type; } else if (item == (PyObject *)LibRTVecs_U8TypeObj) { Py_INCREF(&VecU8Type); return (PyObject *)&VecU8Type; } else if (item == (PyObject *)&PyFloat_Type) { Py_INCREF(&VecFloatType); return (PyObject *)&VecFloatType; } else if (item == (PyObject *)LibRTVecs_I32TypeObj) { Py_INCREF(&VecI32Type); return (PyObject *)&VecI32Type; } else if (item == (PyObject *)LibRTVecs_I16TypeObj) { Py_INCREF(&VecI16Type); return (PyObject *)&VecI16Type; } else if (item == (PyObject *)&PyBool_Type) { Py_INCREF(&VecBoolType); return (PyObject *)&VecBoolType; } else { size_t depth = 0; size_t item_type; int optional = 0; if (!PyObject_TypeCheck(item, &PyType_Type)) { PyObject *it = extract_optional_item(item); if (it != NULL) { optional = 1; item = it; // Check if this is a specialized value type that doesn't support None if (item == (PyObject *)LibRTVecs_I64TypeObj || item == (PyObject *)LibRTVecs_U8TypeObj || item == (PyObject *)&PyFloat_Type || item == (PyObject *)LibRTVecs_I32TypeObj || item == (PyObject *)LibRTVecs_I16TypeObj || item == (PyObject *)&PyBool_Type) { PyErr_SetString(PyExc_TypeError, "vec does not support optional value types (use vec[object] instead)"); return NULL; } } if (item->ob_type == &VecGenericAliasType) { if (optional) { PyErr_SetString(PyExc_TypeError, "optional type not expected in vec[...]"); return NULL; } VecGenericAlias *p = (VecGenericAlias *)item; item_type = p->item_type; depth = p->depth + 1; } else if (!PyObject_TypeCheck(item, &PyType_Type)) { PyErr_SetString(PyExc_TypeError, "type object expected in vec[...]"); return NULL; } else { item_type = (size_t)item | optional; } } else { if (item == (PyObject *)&VecI64Type) { item_type = VEC_ITEM_TYPE_I64; depth = 1; } else if (item == (PyObject *)&VecU8Type) { item_type = VEC_ITEM_TYPE_U8; depth = 1; } else if (item == (PyObject *)&VecFloatType) { item_type = VEC_ITEM_TYPE_FLOAT; depth = 1; } else if (item == (PyObject *)&VecI32Type) { item_type = VEC_ITEM_TYPE_I32; depth = 1; } else if (item == (PyObject *)&VecI16Type) { item_type = VEC_ITEM_TYPE_I16; depth = 1; } else if (item == (PyObject *)&VecBoolType) { item_type = VEC_ITEM_TYPE_BOOL; depth = 1; } else { item_type = (size_t)item; } } if (item == (PyObject *)&PyLong_Type) { PyErr_Format(PyExc_ValueError, "unsupported type in vec[%s] (use i64, i32, i16, or u8)", ((PyTypeObject *)item)->tp_name); return NULL; } VecGenericAlias *p; p = PyObject_GC_New(VecGenericAlias, &VecGenericAliasType); if (p == NULL) return NULL; Py_INCREF(item); p->item_type = item_type; p->depth = depth; PyObject_GC_Track(p); return (PyObject *)p; } } static PyMethodDef vec_methods[] = { {"__class_getitem__", vec_class_getitem, METH_O|METH_CLASS, NULL}, {NULL, NULL, 0, NULL}, /* Sentinel */ }; PyTypeObject VecType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec", .tp_basicsize = sizeof(VecBaseObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, // No Py_TPFLAGS_BASETYPE - prevent Python subclassing .tp_methods = vec_methods, }; // Common helpers PyObject *Vec_GenericRepr(PyObject *vec, size_t item_type, size_t depth, int verbose) { PyObject *l = NULL; PyObject *prefix = NULL; PyObject *mid = NULL; PyObject *suffix = NULL; PyObject *sep = NULL; PyObject *comma = NULL; PyObject *result = NULL; l = PyList_New(0); if (l == NULL) goto error; sep = PyUnicode_FromString(""); if (sep == NULL) goto error; comma = PyUnicode_FromString(", "); if (comma == NULL) goto error; if (verbose) { prefix = Vec_TypeToStr(item_type, depth); if (prefix == NULL) goto error; mid = PyUnicode_FromString("(["); if (mid == NULL) goto error; suffix = PyUnicode_FromString("])"); if (suffix == NULL) goto error; } else { prefix = PyUnicode_FromString(""); if (prefix == NULL) goto error; mid = PyUnicode_FromString("["); if (mid == NULL) goto error; suffix = PyUnicode_FromString("]"); if (suffix == NULL) goto error; } if (PyList_Append(l, prefix) < 0) goto error; if (PyList_Append(l, mid) < 0) goto error; Py_ssize_t len = PyObject_Length(vec); if (len < 0) goto error; for (Py_ssize_t i = 0; i < len; i++) { PyObject *it = PySequence_GetItem(vec, i); if (it == NULL) goto error; PyObject *r; if (depth == 0 || it == Py_None) { r = PyObject_Repr(it); } else { r = Vec_GenericRepr(it, item_type, depth - 1, 0); } Py_DECREF(it); if (r == NULL) goto error; if (PyList_Append(l, r) < 0) { Py_DECREF(r); goto error; } Py_DECREF(r); if (i + 1 < len) { if (PyList_Append(l, comma) < 0) goto error; } } if (PyList_Append(l, suffix) < 0) goto error; result = PyUnicode_Join(sep, l); error: Py_XDECREF(l); Py_XDECREF(prefix); Py_XDECREF(mid); Py_XDECREF(suffix); Py_XDECREF(sep); Py_XDECREF(comma); return result; } // Generic comparison implementation for vecs with PyObject * items. PyObject *Vec_GenericRichcompare(Py_ssize_t *len, PyObject **items, Py_ssize_t *other_len, PyObject **other_items, int op) { int cmp = 1; PyObject *res; if (op == Py_EQ || op == Py_NE) { if (*len != *other_len) { cmp = 0; } else { for (Py_ssize_t i = 0; i < *len && i < *other_len; i++) { int itemcmp = PyObject_RichCompareBool(items[i], other_items[i], Py_EQ); if (itemcmp < 0) return NULL; if (!itemcmp) { cmp = 0; break; } } } if (op == Py_NE) cmp = cmp ^ 1; res = cmp ? Py_True : Py_False; } else res = Py_NotImplemented; Py_INCREF(res); return res; } int Vec_GenericRemove(Py_ssize_t *len, PyObject **items, PyObject *item) { for (Py_ssize_t i = 0; i < *len; i++) { int match = 0; if (items[i] == item) match = 1; else { int itemcmp = PyObject_RichCompareBool(items[i], item, Py_EQ); if (itemcmp < 0) return 0; match = itemcmp; } if (match) { Py_CLEAR(items[i]); for (; i < *len - 1; i++) { items[i] = items[i + 1]; } (*len)--; return 1; } } PyErr_SetString(PyExc_ValueError, "vec.remove(x): x not in vec"); return 0; } PyObject *Vec_GenericPop(Py_ssize_t *len, PyObject **items, Py_ssize_t index) { if (index < 0) index += *len; if (index < 0 || index >= *len) { PyErr_SetString(PyExc_IndexError, "index out of range"); return NULL; } PyObject *item = items[index]; for (Py_ssize_t i = index; i < *len - 1; i++) items[i] = items[i + 1]; (*len)--; return item; } PyObject *Vec_GenericPopWrapper(Py_ssize_t *len, PyObject **items, PyObject *args) { Py_ssize_t index = -1; if (!PyArg_ParseTuple(args, "|n:pop", &index)) return NULL; return Vec_GenericPop(len, items, index); } // Module-level functions static PyObject *vec_append(PyObject *self, PyObject *args) { PyObject *vec; PyObject *item; if (!PyArg_ParseTuple(args, "OO", &vec, &item)) return NULL; if (VecI64_Check(vec)) { int64_t x = VecI64_UnboxItem(item); if (VecI64_IsUnboxError(x)) { return NULL; } VecI64 v = ((VecI64Object *)vec)->vec; VEC_I64_INCREF(v); v = VecI64_Append(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecI64_Box(v); } else if (VecU8_Check(vec)) { uint8_t x = VecU8_UnboxItem(item); if (VecU8_IsUnboxError(x)) { return NULL; } VecU8 v = ((VecU8Object *)vec)->vec; VEC_U8_INCREF(v); v = VecU8_Append(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecU8_Box(v); } else if (VecFloat_Check(vec)) { double x = VecFloat_UnboxItem(item); if (VecFloat_IsUnboxError(x)) { return NULL; } VecFloat v = ((VecFloatObject *)vec)->vec; VEC_FLOAT_INCREF(v); v = VecFloat_Append(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecFloat_Box(v); } else if (VecI32_Check(vec)) { int32_t x = VecI32_UnboxItem(item); if (VecI32_IsUnboxError(x)) { return NULL; } VecI32 v = ((VecI32Object *)vec)->vec; VEC_I32_INCREF(v); v = VecI32_Append(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecI32_Box(v); } else if (VecI16_Check(vec)) { int16_t x = VecI16_UnboxItem(item); if (VecI16_IsUnboxError(x)) { return NULL; } VecI16 v = ((VecI16Object *)vec)->vec; VEC_I16_INCREF(v); v = VecI16_Append(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecI16_Box(v); } else if (VecBool_Check(vec)) { double x = VecBool_UnboxItem(item); if (VecBool_IsUnboxError(x)) { return NULL; } VecBool v = ((VecBoolObject *)vec)->vec; VEC_BOOL_INCREF(v); v = VecBool_Append(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecBool_Box(v); } else if (VecT_Check(vec)) { VecT v = ((VecTObject *)vec)->vec; if (!VecT_ItemCheck(v, item, VEC_T_BUF(v)->item_type)) { return NULL; } VEC_T_INCREF(v); v = VecT_Append(v, item, VEC_T_BUF(v)->item_type); if (VEC_IS_ERROR(v)) return NULL; return VecT_Box(v, VEC_T_BUF(v)->item_type); } else if (VecNested_Check(vec)) { VecNested v = ((VecNestedObject *)vec)->vec; VecNestedBufItem vecitem; if (VecNested_UnboxItem(v, item, &vecitem) < 0) return NULL; VEC_NESTED_INCREF(v); v = VecNested_Append(v, vecitem); if (VEC_IS_ERROR(v)) return NULL; return VecNested_Box(v); } else { PyErr_Format(PyExc_TypeError, "vec argument expected, got %.100s", Py_TYPE(vec)->tp_name); return NULL; } } static PyObject *vec_remove(PyObject *self, PyObject *args) { PyObject *vec; PyObject *item; if (!PyArg_ParseTuple(args, "OO", &vec, &item)) return NULL; if (VecI64_Check(vec)) { int64_t x = VecI64_UnboxItem(item); if (VecI64_IsUnboxError(x)) { return NULL; } VecI64 v = ((VecI64Object *)vec)->vec; VEC_I64_INCREF(v); v = VecI64_Remove(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecI64_Box(v); } else if (VecU8_Check(vec)) { uint8_t x = VecU8_UnboxItem(item); if (VecU8_IsUnboxError(x)) { return NULL; } VecU8 v = ((VecU8Object *)vec)->vec; VEC_U8_INCREF(v); v = VecU8_Remove(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecU8_Box(v); } else if (VecFloat_Check(vec)) { double x = VecFloat_UnboxItem(item); if (VecFloat_IsUnboxError(x)) { return NULL; } VecFloat v = ((VecFloatObject *)vec)->vec; VEC_FLOAT_INCREF(v); v = VecFloat_Remove(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecFloat_Box(v); } else if (VecI32_Check(vec)) { int32_t x = VecI32_UnboxItem(item); if (VecI32_IsUnboxError(x)) { return NULL; } VecI32 v = ((VecI32Object *)vec)->vec; VEC_I32_INCREF(v); v = VecI32_Remove(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecI32_Box(v); } else if (VecI16_Check(vec)) { int16_t x = VecI16_UnboxItem(item); if (VecI16_IsUnboxError(x)) { return NULL; } VecI16 v = ((VecI16Object *)vec)->vec; VEC_I16_INCREF(v); v = VecI16_Remove(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecI16_Box(v); } else if (VecBool_Check(vec)) { char x = VecBool_UnboxItem(item); if (VecBool_IsUnboxError(x)) { return NULL; } VecBool v = ((VecBoolObject *)vec)->vec; VEC_BOOL_INCREF(v); v = VecBool_Remove(v, x); if (VEC_IS_ERROR(v)) return NULL; return VecBool_Box(v); } else if (VecT_Check(vec)) { VecT v = ((VecTObject *)vec)->vec; if (!VecT_ItemCheck(v, item, VEC_T_BUF(v)->item_type)) { return NULL; } VEC_T_INCREF(v); v = VecT_Remove(v, item); if (VEC_IS_ERROR(v)) return NULL; return VecT_Box(v, VEC_T_BUF(v)->item_type); } else if (VecNested_Check(vec)) { VecNested v = ((VecNestedObject *)vec)->vec; VecNestedBufItem vecitem; if (VecNested_UnboxItem(v, item, &vecitem) < 0) return NULL; VEC_NESTED_INCREF(v); v = VecNested_Remove(v, vecitem); if (VEC_IS_ERROR(v)) return NULL; return VecNested_Box(v); } else { PyErr_Format(PyExc_TypeError, "vec argument expected, got %.100s", Py_TYPE(vec)->tp_name); return NULL; } } static PyObject *vec_pop(PyObject *self, PyObject *args) { PyObject *vec; Py_ssize_t index = -1; if (!PyArg_ParseTuple(args, "O|n:pop", &vec, &index)) return NULL; PyObject *result_item0; PyObject *result_item1; if (VecI64_Check(vec)) { VecI64 v = ((VecI64Object *)vec)->vec; VEC_I64_INCREF(v); VecI64PopResult r; r = VecI64_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; if ((result_item0 = VecI64_Box(r.f0)) == NULL) return NULL; result_item1 = VecI64_BoxItem(r.f1); } else if (VecU8_Check(vec)) { VecU8 v = ((VecU8Object *)vec)->vec; VEC_U8_INCREF(v); VecU8PopResult r; r = VecU8_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; if ((result_item0 = VecU8_Box(r.f0)) == NULL) return NULL; result_item1 = VecU8_BoxItem(r.f1); } else if (VecFloat_Check(vec)) { VecFloat v = ((VecFloatObject *)vec)->vec; VEC_FLOAT_INCREF(v); VecFloatPopResult r; r = VecFloat_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; if ((result_item0 = VecFloat_Box(r.f0)) == NULL) return NULL; result_item1 = VecFloat_BoxItem(r.f1); } else if (VecI32_Check(vec)) { VecI32 v = ((VecI32Object *)vec)->vec; VEC_I32_INCREF(v); VecI32PopResult r; r = VecI32_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; if ((result_item0 = VecI32_Box(r.f0)) == NULL) return NULL; result_item1 = VecI32_BoxItem(r.f1); } else if (VecI16_Check(vec)) { VecI16 v = ((VecI16Object *)vec)->vec; VEC_I16_INCREF(v); VecI16PopResult r; r = VecI16_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; if ((result_item0 = VecI16_Box(r.f0)) == NULL) return NULL; result_item1 = VecI16_BoxItem(r.f1); } else if (VecBool_Check(vec)) { VecBool v = ((VecBoolObject *)vec)->vec; VEC_BOOL_INCREF(v); VecBoolPopResult r; r = VecBool_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; if ((result_item0 = VecBool_Box(r.f0)) == NULL) return NULL; result_item1 = VecBool_BoxItem(r.f1); } else if (VecT_Check(vec)) { VecT v = ((VecTObject *)vec)->vec; VEC_T_INCREF(v); VecTPopResult r; r = VecT_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; result_item0 = VecT_Box(r.f0, VEC_T_BUF(v)->item_type); if (result_item0 == NULL) { Py_DECREF(r.f1); return NULL; } result_item1 = r.f1; } else if (VecNested_Check(vec)) { VecNested v = ((VecNestedObject *)vec)->vec; VEC_NESTED_INCREF(v); VecNestedPopResult r; r = VecNested_Pop(v, index); if (VEC_IS_ERROR(r.f0)) return NULL; PyObject *popped_buf = VecNested_ItemBuf(VEC_NESTED_BUF(r.f0), r.f1); result_item0 = VecNested_Box(r.f0); if (result_item0 == NULL) { Py_XDECREF(popped_buf); return NULL; } result_item1 = VecNested_BoxItem(r.f0, r.f1); if (result_item1 == NULL) { Py_DECREF(result_item0); Py_XDECREF(popped_buf); return NULL; } Py_XDECREF(popped_buf); } else { PyErr_Format(PyExc_TypeError, "vec argument expected, got %.100s", Py_TYPE(vec)->tp_name); return NULL; } if (result_item1 == NULL) { Py_DECREF(result_item0); return NULL; } PyObject *res = PyTuple_New(2); if (res == NULL) { Py_DECREF(result_item0); Py_DECREF(result_item1); return NULL; } PyTuple_SET_ITEM(res, 0, result_item0); PyTuple_SET_ITEM(res, 1, result_item1); return res; } static PyObject *vec_extend(PyObject *self, PyObject *args) { PyObject *vec; PyObject *iterable; if (!PyArg_ParseTuple(args, "OO:extend", &vec, &iterable)) return NULL; if (VecI64_Check(vec)) { VecI64 v = ((VecI64Object *)vec)->vec; VEC_I64_INCREF(v); v = VecI64_Extend(v, iterable); if (VEC_IS_ERROR(v)) return NULL; return VecI64_Box(v); } else if (VecU8_Check(vec)) { VecU8 v = ((VecU8Object *)vec)->vec; VEC_U8_INCREF(v); v = VecU8_Extend(v, iterable); if (VEC_IS_ERROR(v)) return NULL; return VecU8_Box(v); } else if (VecFloat_Check(vec)) { VecFloat v = ((VecFloatObject *)vec)->vec; VEC_FLOAT_INCREF(v); v = VecFloat_Extend(v, iterable); if (VEC_IS_ERROR(v)) return NULL; return VecFloat_Box(v); } else if (VecI32_Check(vec)) { VecI32 v = ((VecI32Object *)vec)->vec; VEC_I32_INCREF(v); v = VecI32_Extend(v, iterable); if (VEC_IS_ERROR(v)) return NULL; return VecI32_Box(v); } else if (VecI16_Check(vec)) { VecI16 v = ((VecI16Object *)vec)->vec; VEC_I16_INCREF(v); v = VecI16_Extend(v, iterable); if (VEC_IS_ERROR(v)) return NULL; return VecI16_Box(v); } else if (VecBool_Check(vec)) { VecBool v = ((VecBoolObject *)vec)->vec; VEC_BOOL_INCREF(v); v = VecBool_Extend(v, iterable); if (VEC_IS_ERROR(v)) return NULL; return VecBool_Box(v); } else if (VecT_Check(vec)) { VecT v = ((VecTObject *)vec)->vec; size_t item_type = VEC_T_BUF(v)->item_type; VEC_T_INCREF(v); v = VecT_Extend(v, iterable, item_type); if (VEC_IS_ERROR(v)) return NULL; return VecT_Box(v, item_type); } else if (VecNested_Check(vec)) { VecNested v = ((VecNestedObject *)vec)->vec; VEC_NESTED_INCREF(v); v = VecNested_Extend(v, iterable); if (VEC_IS_ERROR(v)) return NULL; return VecNested_Box(v); } else { PyErr_Format(PyExc_TypeError, "vec argument expected, got %.100s", Py_TYPE(vec)->tp_name); return NULL; } } // Return the base VecType for isinstance checks static PyTypeObject *get_vec_type(void) { return &VecType; } static int vecs_abi_version(void) { return LIBRT_VECS_ABI_VERSION; } static int vecs_api_version(void) { return LIBRT_VECS_API_VERSION; } static VecCapsule Capsule = { vecs_abi_version, vecs_api_version, &Vec_TAPI, &Vec_NestedAPI, &Vec_I64API, &Vec_I32API, &Vec_I16API, &Vec_U8API, &Vec_FloatAPI, &Vec_BoolAPI, get_vec_type, }; static PyMethodDef VecsMethods[] = { {"append", vec_append, METH_VARARGS, "Append a value to the end of a vec"}, {"remove", vec_remove, METH_VARARGS, "Remove first occurrence of value from a vec"}, {"pop", vec_pop, METH_VARARGS, "Remove and return vec item at index (default last)"}, {"extend", vec_extend, METH_VARARGS, "Extend a vec with items from an iterable"}, {NULL, NULL, 0, NULL} /* Sentinel */ }; static int librt_vecs_module_exec(PyObject *m) { PyObject *ext = PyImport_ImportModule("mypy_extensions"); if (ext == NULL) { return -1; } LibRTVecs_I64TypeObj = (PyTypeObject *)PyObject_GetAttrString(ext, "i64"); if (LibRTVecs_I64TypeObj == NULL) { return -1; } if (!PyType_Check(LibRTVecs_I64TypeObj)) { PyErr_SetString(PyExc_TypeError, "mypy_extensions.i64 is not a type"); return -1; } LibRTVecs_I32TypeObj = (PyTypeObject *)PyObject_GetAttrString(ext, "i32"); if (LibRTVecs_I32TypeObj == NULL) { return -1; } if (!PyType_Check(LibRTVecs_I32TypeObj)) { PyErr_SetString(PyExc_TypeError, "mypy_extensions.i32 is not a type"); return -1; } LibRTVecs_I16TypeObj = (PyTypeObject *)PyObject_GetAttrString(ext, "i16"); if (LibRTVecs_I16TypeObj == NULL) { return -1; } if (!PyType_Check(LibRTVecs_I16TypeObj)) { PyErr_SetString(PyExc_TypeError, "mypy_extensions.i16 is not a type"); return -1; } LibRTVecs_U8TypeObj = (PyTypeObject *)PyObject_GetAttrString(ext, "u8"); if (LibRTVecs_U8TypeObj == NULL) { return -1; } if (!PyType_Check(LibRTVecs_U8TypeObj)) { PyErr_SetString(PyExc_TypeError, "mypy_extensions.u8 is not a type"); return -1; } if (PyType_Ready(&VecType) < 0) return -1; if (PyType_Ready(&VecGenericAliasType) < 0) return -1; if (PyType_Ready(&VecTType) < 0) return -1; if (PyType_Ready(&VecTBufType) < 0) return -1; if (PyType_Ready(&VecTIterType) < 0) return -1; if (PyType_Ready(&VecNestedType) < 0) return -1; if (PyType_Ready(&VecNestedBufType) < 0) return -1; if (PyType_Ready(&VecNestedIterType) < 0) return -1; if (PyType_Ready(&VecI64Type) < 0) return -1; if (PyType_Ready(&VecI64BufType) < 0) return -1; if (PyType_Ready(&VecI64IterType) < 0) return -1; if (PyType_Ready(&VecI32Type) < 0) return -1; if (PyType_Ready(&VecI32BufType) < 0) return -1; if (PyType_Ready(&VecI32IterType) < 0) return -1; if (PyType_Ready(&VecI16Type) < 0) return -1; if (PyType_Ready(&VecI16BufType) < 0) return -1; if (PyType_Ready(&VecI16IterType) < 0) return -1; if (PyType_Ready(&VecU8Type) < 0) return -1; if (PyType_Ready(&VecU8BufType) < 0) return -1; if (PyType_Ready(&VecU8IterType) < 0) return -1; if (PyType_Ready(&VecFloatType) < 0) return -1; if (PyType_Ready(&VecFloatBufType) < 0) return -1; if (PyType_Ready(&VecFloatIterType) < 0) return -1; if (PyType_Ready(&VecBoolType) < 0) return -1; if (PyType_Ready(&VecBoolBufType) < 0) return -1; if (PyType_Ready(&VecBoolIterType) < 0) return -1; Py_INCREF(&VecType); if (PyModule_AddObject(m, "vec", (PyObject *)&VecType) < 0) { Py_DECREF(&VecType); return -1; } PyObject *c_api = PyCapsule_New(&Capsule, "librt.vecs._C_API", NULL); if (c_api == NULL) return -1; if (PyModule_AddObject(m, "_C_API", c_api) < 0) { Py_XDECREF(c_api); Py_DECREF(&VecType); return -1; } Py_DECREF(ext); return 0; } static PyModuleDef_Slot librt_vecs_module_slots[] = { {Py_mod_exec, librt_vecs_module_exec}, #ifdef Py_MOD_GIL_NOT_USED {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} }; static PyModuleDef vecsmodule = { .m_base = PyModuleDef_HEAD_INIT, .m_name = "vecs", .m_doc = "This module implements the vec type and related functionality.", .m_size = 0, .m_methods = VecsMethods, .m_slots = librt_vecs_module_slots, }; PyMODINIT_FUNC PyInit_vecs(void) { return PyModuleDef_Init(&vecsmodule); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/librt_vecs.h0000644000175100017510000007710015200142331015614 0ustar00runnerrunner#ifndef VEC_H_INCL #define VEC_H_INCL // Header for the implementation of librt.vecs, which defines the 'vec' type. // Refer to librt_vecs.c for more detailed information. #define PY_SSIZE_T_CLEAN #include #include #include #include "mypyc_util.h" // ABI version -- only an exact match is compatible. This will only be changed in // very exceptional cases (likely never) due to strict backward compatibility // requirements. #define LIBRT_VECS_ABI_VERSION 1 // API version -- more recent versions must maintain backward compatibility, i.e. // we can add new features but not remove or change existing features (unless // ABI version is changed, but see the comment above). #define LIBRT_VECS_API_VERSION 1 // Magic (native) integer return value on exception. Caller must also // use PyErr_Occurred() since this overlaps with valid integer values. #define MYPYC_INT_ERROR -113 // Item type constants for supported packed/specialized item types; must be // even but not a multiple of 4 (2 + 4 * n). Each of these has a corresponding // distinct implementation C extension class. For example, vec[i64] has a // different runtime type than vec[i32]. All other item types use generic // implementations. #define VEC_ITEM_TYPE_I64 2 #define VEC_ITEM_TYPE_I32 6 #define VEC_ITEM_TYPE_I16 10 #define VEC_ITEM_TYPE_U8 14 #define VEC_ITEM_TYPE_FLOAT 18 #define VEC_ITEM_TYPE_BOOL 22 static inline size_t Vec_IsMagicItemType(size_t item_type) { return item_type & 2; } // Buffer objects // vecbuf[i64] typedef struct _VecI64BufObject { PyObject_VAR_HEAD int64_t items[1]; } VecI64BufObject; // vecbuf[i32] typedef struct _VecI32BufObject { PyObject_VAR_HEAD int32_t items[1]; } VecI32BufObject; // vecbuf[i16] typedef struct _VecI16BufObject { PyObject_VAR_HEAD int16_t items[1]; } VecI16BufObject; // vecbuf[u8] typedef struct _VecU8BufObject { PyObject_VAR_HEAD uint8_t items[1]; } VecU8BufObject; // vecbuf[float] typedef struct _VecFloatBufObject { PyObject_VAR_HEAD double items[1]; } VecFloatBufObject; // vecbuf[bool] typedef struct _VecBoolBufObject { PyObject_VAR_HEAD char items[1]; } VecBoolBufObject; // Simple generic vecbuf: vecbuf[t] when t is a type object typedef struct _VecTBufObject { PyObject_VAR_HEAD // Tagged pointer to PyTypeObject *. The lowest bit is 1 for optional item type. size_t item_type; PyObject *items[1]; } VecTBufObject; typedef struct _VecNestedBufItem { Py_ssize_t len; void *items; } VecNestedBufItem; // Nested vec type: vec[vec[...]], vec[vec[...] | None], etc. typedef struct _VecNestedBufObject { PyObject_VAR_HEAD // Tagged pointer to PyTypeObject *. Lowest bit is set for optional item type. // The second lowest bit is set for a packed item type (VEC_ITEM_TYPE_*). size_t item_type; // Number of nested vec types (of any kind, at least 1) size_t depth; VecNestedBufItem items[1]; } VecNestedBufObject; // Unboxed vec objects // // The items pointer points to the first element of the items array in the // corresponding buffer object. Use VEC_*_BUF() to recover the buffer object // from the items pointer (only needed on cold paths like grow/refcount). // Items pointer is NULL for empty/uninitialized vecs. typedef struct _VecI64 { Py_ssize_t len; int64_t *items; } VecI64; typedef struct _VecI32 { Py_ssize_t len; int32_t *items; } VecI32; typedef struct _VecI16 { Py_ssize_t len; int16_t *items; } VecI16; typedef struct _VecU8 { Py_ssize_t len; uint8_t *items; } VecU8; typedef struct _VecFloat { Py_ssize_t len; double *items; } VecFloat; typedef struct _VecBool { Py_ssize_t len; char *items; } VecBool; typedef struct _VecT { Py_ssize_t len; PyObject **items; } VecT; typedef struct _VecNested { Py_ssize_t len; VecNestedBufItem *items; } VecNested; // Recover buffer object from items pointer. Only valid when items != NULL. #define VEC_I64_BUF_FROM_ITEMS(items_) \ ((VecI64BufObject *)((char *)(items_) - offsetof(VecI64BufObject, items))) #define VEC_I32_BUF_FROM_ITEMS(items_) \ ((VecI32BufObject *)((char *)(items_) - offsetof(VecI32BufObject, items))) #define VEC_I16_BUF_FROM_ITEMS(items_) \ ((VecI16BufObject *)((char *)(items_) - offsetof(VecI16BufObject, items))) #define VEC_U8_BUF_FROM_ITEMS(items_) \ ((VecU8BufObject *)((char *)(items_) - offsetof(VecU8BufObject, items))) #define VEC_FLOAT_BUF_FROM_ITEMS(items_) \ ((VecFloatBufObject *)((char *)(items_) - offsetof(VecFloatBufObject, items))) #define VEC_BOOL_BUF_FROM_ITEMS(items_) \ ((VecBoolBufObject *)((char *)(items_) - offsetof(VecBoolBufObject, items))) #define VEC_T_BUF_FROM_ITEMS(items_) \ ((VecTBufObject *)((char *)(items_) - offsetof(VecTBufObject, items))) #define VEC_NESTED_BUF_FROM_ITEMS(items_) \ ((VecNestedBufObject *)((char *)(items_) - offsetof(VecNestedBufObject, items))) #define VEC_I64_BUF(v) VEC_I64_BUF_FROM_ITEMS((v).items) #define VEC_I32_BUF(v) VEC_I32_BUF_FROM_ITEMS((v).items) #define VEC_I16_BUF(v) VEC_I16_BUF_FROM_ITEMS((v).items) #define VEC_U8_BUF(v) VEC_U8_BUF_FROM_ITEMS((v).items) #define VEC_FLOAT_BUF(v) VEC_FLOAT_BUF_FROM_ITEMS((v).items) #define VEC_BOOL_BUF(v) VEC_BOOL_BUF_FROM_ITEMS((v).items) #define VEC_T_BUF(v) VEC_T_BUF_FROM_ITEMS((v).items) #define VEC_NESTED_BUF(v) VEC_NESTED_BUF_FROM_ITEMS((v).items) // Type-specific incref/decref. Safe when items may be NULL. #define VEC_I64_INCREF(v) do { if ((v).items) Py_INCREF(VEC_I64_BUF(v)); } while (0) #define VEC_I64_DECREF(v) do { if ((v).items) Py_DECREF(VEC_I64_BUF(v)); } while (0) #define VEC_I32_INCREF(v) do { if ((v).items) Py_INCREF(VEC_I32_BUF(v)); } while (0) #define VEC_I32_DECREF(v) do { if ((v).items) Py_DECREF(VEC_I32_BUF(v)); } while (0) #define VEC_I16_INCREF(v) do { if ((v).items) Py_INCREF(VEC_I16_BUF(v)); } while (0) #define VEC_I16_DECREF(v) do { if ((v).items) Py_DECREF(VEC_I16_BUF(v)); } while (0) #define VEC_U8_INCREF(v) do { if ((v).items) Py_INCREF(VEC_U8_BUF(v)); } while (0) #define VEC_U8_DECREF(v) do { if ((v).items) Py_DECREF(VEC_U8_BUF(v)); } while (0) #define VEC_FLOAT_INCREF(v) do { if ((v).items) Py_INCREF(VEC_FLOAT_BUF(v)); } while (0) #define VEC_FLOAT_DECREF(v) do { if ((v).items) Py_DECREF(VEC_FLOAT_BUF(v)); } while (0) #define VEC_BOOL_INCREF(v) do { if ((v).items) Py_INCREF(VEC_BOOL_BUF(v)); } while (0) #define VEC_BOOL_DECREF(v) do { if ((v).items) Py_DECREF(VEC_BOOL_BUF(v)); } while (0) #define VEC_T_INCREF(v) do { if ((v).items) Py_INCREF(VEC_T_BUF(v)); } while (0) #define VEC_T_DECREF(v) do { if ((v).items) Py_DECREF(VEC_T_BUF(v)); } while (0) #define VEC_NESTED_INCREF(v) do { if ((v).items) Py_INCREF(VEC_NESTED_BUF(v)); } while (0) #define VEC_NESTED_DECREF(v) do { if ((v).items) Py_DECREF(VEC_NESTED_BUF(v)); } while (0) // Boxed vec objects // Arbitrary boxed vec object (only shared bits) typedef struct _VecObject { PyObject_HEAD Py_ssize_t len; } VecObject; // Base vec type object (for isinstance checks) // This is an abstract base type that all specialized vec types inherit from. // It cannot be instantiated directly - only used for isinstance(x, vec). typedef struct _VecBaseObject { PyObject_HEAD } VecBaseObject; // Boxed vec[i64] typedef struct _VecI64Object { PyObject_HEAD VecI64 vec; } VecI64Object; // Boxed vec[i32] typedef struct _VecI32Object { PyObject_HEAD VecI32 vec; } VecI32Object; // Boxed vec[i16] typedef struct _VecI16Object { PyObject_HEAD VecI16 vec; } VecI16Object; // Boxed vec[u8] typedef struct _VecU8Object { PyObject_HEAD VecU8 vec; } VecU8Object; // Boxed vec[float] typedef struct _VecFloatObject { PyObject_HEAD VecFloat vec; } VecFloatObject; // Boxed vec[bool] typedef struct _VecBoolObject { PyObject_HEAD VecBool vec; } VecBoolObject; // Simple boxed generic vecbuf: vecbuf[t] when t is a type object typedef struct _VecTObject { PyObject_HEAD VecT vec; } VecTObject; // Extended generic vec type: vec[t | None], vec[vec[...]], etc. typedef struct _VecNestedObject { PyObject_HEAD VecNested vec; } VecNestedObject; #ifndef MYPYC_DECLARED_tuple_T2V88 #define MYPYC_DECLARED_tuple_T2V88 typedef struct tuple_T2V88 { VecI64 f0; int64_t f1; } tuple_T2V88; static tuple_T2V88 tuple_undefined_T2V88 = { { -1, NULL } , 0 }; #endif #ifndef MYPYC_DECLARED_tuple_T2V44 #define MYPYC_DECLARED_tuple_T2V44 typedef struct tuple_T2V44 { VecI32 f0; int32_t f1; } tuple_T2V44; static tuple_T2V44 tuple_undefined_T2V44 = { { -1, NULL } , 0 }; #endif #ifndef MYPYC_DECLARED_tuple_T2V22 #define MYPYC_DECLARED_tuple_T2V22 typedef struct tuple_T2V22 { VecI16 f0; int16_t f1; } tuple_T2V22; static tuple_T2V22 tuple_undefined_T2V22 = { { -1, NULL } , 0 }; #endif #ifndef MYPYC_DECLARED_tuple_T2VU1U1 #define MYPYC_DECLARED_tuple_T2VU1U1 typedef struct tuple_T2VU1U1 { VecU8 f0; uint8_t f1; } tuple_T2VU1U1; static tuple_T2VU1U1 tuple_undefined_T2VU1U1 = { { -1, NULL } , 0 }; #endif #ifndef MYPYC_DECLARED_tuple_T2VFF #define MYPYC_DECLARED_tuple_T2VFF typedef struct tuple_T2VFF { VecFloat f0; double f1; } tuple_T2VFF; static tuple_T2VFF tuple_undefined_T2VFF = { { -1, NULL } , 0.0 }; #endif #ifndef MYPYC_DECLARED_tuple_T2VCC #define MYPYC_DECLARED_tuple_T2VCC typedef struct tuple_T2VCC { VecBool f0; char f1; } tuple_T2VCC; static tuple_T2VCC tuple_undefined_T2VCC = { { -1, NULL } , 0 }; #endif typedef tuple_T2V88 VecI64PopResult; typedef tuple_T2V44 VecI32PopResult; typedef tuple_T2V22 VecI16PopResult; typedef tuple_T2VU1U1 VecU8PopResult; typedef tuple_T2VFF VecFloatPopResult; typedef tuple_T2VCC VecBoolPopResult; // vec[i64] operations + type objects (stored in a capsule) typedef struct _VecI64API { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecI64 (*alloc)(Py_ssize_t, Py_ssize_t); PyObject *(*box)(VecI64); VecI64 (*unbox)(PyObject *); VecI64 (*convert_from_nested)(VecNestedBufItem); VecI64 (*append)(VecI64, int64_t); VecI64PopResult (*pop)(VecI64, Py_ssize_t); VecI64 (*remove)(VecI64, int64_t); // TODO: Py_ssize_t VecI64 (*slice)(VecI64, int64_t, int64_t); VecI64 (*from_iterable)(PyObject *, int64_t); VecI64 (*extend)(VecI64, PyObject *); VecI64 (*extend_vec)(VecI64, VecI64); PyObject *(*to_list)(VecI64); PyObject *(*to_tuple)(VecI64); } VecI64API; // vec[i32] operations + type objects (stored in a capsule) typedef struct _VecI32API { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecI32 (*alloc)(Py_ssize_t, Py_ssize_t); PyObject *(*box)(VecI32); VecI32 (*unbox)(PyObject *); VecI32 (*convert_from_nested)(VecNestedBufItem); VecI32 (*append)(VecI32, int32_t); VecI32PopResult (*pop)(VecI32, Py_ssize_t); VecI32 (*remove)(VecI32, int32_t); // TODO: Py_ssize_t VecI32 (*slice)(VecI32, int64_t, int64_t); VecI32 (*from_iterable)(PyObject *, int64_t); VecI32 (*extend)(VecI32, PyObject *); VecI32 (*extend_vec)(VecI32, VecI32); PyObject *(*to_list)(VecI32); PyObject *(*to_tuple)(VecI32); } VecI32API; // vec[i16] operations + type objects (stored in a capsule) typedef struct _VecI16API { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecI16 (*alloc)(Py_ssize_t, Py_ssize_t); PyObject *(*box)(VecI16); VecI16 (*unbox)(PyObject *); VecI16 (*convert_from_nested)(VecNestedBufItem); VecI16 (*append)(VecI16, int16_t); VecI16PopResult (*pop)(VecI16, Py_ssize_t); VecI16 (*remove)(VecI16, int16_t); // TODO: Py_ssize_t VecI16 (*slice)(VecI16, int64_t, int64_t); VecI16 (*from_iterable)(PyObject *, int64_t); VecI16 (*extend)(VecI16, PyObject *); VecI16 (*extend_vec)(VecI16, VecI16); PyObject *(*to_list)(VecI16); PyObject *(*to_tuple)(VecI16); } VecI16API; // vec[u8] operations + type objects (stored in a capsule) typedef struct _VecU8API { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecU8 (*alloc)(Py_ssize_t, Py_ssize_t); PyObject *(*box)(VecU8); VecU8 (*unbox)(PyObject *); VecU8 (*convert_from_nested)(VecNestedBufItem); VecU8 (*append)(VecU8, uint8_t); VecU8PopResult (*pop)(VecU8, Py_ssize_t); VecU8 (*remove)(VecU8, uint8_t); // TODO: Py_ssize_t VecU8 (*slice)(VecU8, int64_t, int64_t); VecU8 (*from_iterable)(PyObject *, int64_t); VecU8 (*extend)(VecU8, PyObject *); VecU8 (*extend_vec)(VecU8, VecU8); PyObject *(*to_list)(VecU8); PyObject *(*to_tuple)(VecU8); } VecU8API; // vec[float] operations + type objects (stored in a capsule) typedef struct _VecFloatAPI { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecFloat (*alloc)(Py_ssize_t, Py_ssize_t); PyObject *(*box)(VecFloat); VecFloat (*unbox)(PyObject *); VecFloat (*convert_from_nested)(VecNestedBufItem); VecFloat (*append)(VecFloat, double); VecFloatPopResult (*pop)(VecFloat, Py_ssize_t); VecFloat (*remove)(VecFloat, double); // TODO: Py_ssize_t VecFloat (*slice)(VecFloat, int64_t, int64_t); VecFloat (*from_iterable)(PyObject *, int64_t); VecFloat (*extend)(VecFloat, PyObject *); VecFloat (*extend_vec)(VecFloat, VecFloat); PyObject *(*to_list)(VecFloat); PyObject *(*to_tuple)(VecFloat); } VecFloatAPI; // vec[bool] operations + type objects (stored in a capsule) typedef struct _VecBoolAPI { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecBool (*alloc)(Py_ssize_t, Py_ssize_t); PyObject *(*box)(VecBool); VecBool (*unbox)(PyObject *); VecBool (*convert_from_nested)(VecNestedBufItem); VecBool (*append)(VecBool, char); VecBoolPopResult (*pop)(VecBool, Py_ssize_t); VecBool (*remove)(VecBool, char); // TODO: Py_ssize_t VecBool (*slice)(VecBool, int64_t, int64_t); VecBool (*from_iterable)(PyObject *, int64_t); VecBool (*extend)(VecBool, PyObject *); VecBool (*extend_vec)(VecBool, VecBool); PyObject *(*to_list)(VecBool); PyObject *(*to_tuple)(VecBool); } VecBoolAPI; #ifndef MYPYC_DECLARED_tuple_T2VOO #define MYPYC_DECLARED_tuple_T2VOO typedef struct tuple_T2VOO { VecT f0; PyObject *f1; } tuple_T2VOO; static tuple_T2VOO tuple_undefined_T2VOO = { { -1, NULL } , NULL }; #endif typedef tuple_T2VOO VecTPopResult; // vec[T] operations + type objects (stored in a capsule) // // T is a class type or class type | None typedef struct _VecTAPI { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecT (*alloc)(Py_ssize_t, Py_ssize_t, size_t); PyObject *(*box)(VecT, size_t); VecT (*unbox)(PyObject *, size_t); VecT (*convert_from_nested)(VecNestedBufItem); VecT (*append)(VecT, PyObject *, size_t); VecTPopResult (*pop)(VecT, Py_ssize_t); VecT (*remove)(VecT, PyObject *); // TODO: Py_ssize_t VecT (*slice)(VecT, int64_t, int64_t); VecT (*from_iterable)(size_t, PyObject *, int64_t); VecT (*extend)(VecT, PyObject *, size_t); VecT (*extend_vec)(VecT, VecT, size_t); PyObject *(*to_list)(VecT); PyObject *(*to_tuple)(VecT); } VecTAPI; #ifndef MYPYC_DECLARED_tuple_T2VvVi #define MYPYC_DECLARED_tuple_T2VvVi typedef struct tuple_T2VvVi { VecNested f0; VecNestedBufItem f1; } tuple_T2VvVi; static tuple_T2VvVi tuple_undefined_T2VvVi = { { -1, NULL } , { -1, 0 } }; #endif typedef tuple_T2VvVi VecNestedPopResult; // Nested vec operations + type objects (stored in a capsule) typedef struct _VecNestedAPI { PyTypeObject *boxed_type; PyTypeObject *buf_type; VecNested (*alloc)(Py_ssize_t, Py_ssize_t, size_t, size_t depth); PyObject *(*box)(VecNested); VecNested (*unbox)(PyObject *, size_t, size_t depth); VecNested (*convert_from_nested)(VecNestedBufItem); VecNested (*append)(VecNested, VecNestedBufItem); VecNestedPopResult (*pop)(VecNested, Py_ssize_t); VecNested (*remove)(VecNested, VecNestedBufItem); // TODO: Py_ssize_t VecNested (*slice)(VecNested, int64_t, int64_t); VecNested (*extend)(VecNested, PyObject *); VecNested (*extend_vec)(VecNested, VecNested); } VecNestedAPI; typedef struct { int (*abi_version)(void); int (*api_version)(void); VecTAPI *t; VecNestedAPI *nested; VecI64API *i64; VecI32API *i32; VecI16API *i16; VecU8API *u8; VecFloatAPI *float_; VecBoolAPI *bool_; PyTypeObject *(*get_vec_type)(void); // Function to get base VecType for isinstance checks } VecCapsule; #define VEC_BUF_SIZE(b) ((b)->ob_base.ob_size) #define VEC_ITEM_TYPE(t) ((PyTypeObject *)((t) & ~1)) #define VEC_BUF_ITEM_TYPE(b) VEC_ITEM_TYPE((b)->item_type) #define VEC_IS_ERROR(v) ((v).len < 0) // Type objects // Buffer type objects that store vec items extern PyTypeObject VecI64BufType; extern PyTypeObject VecI32BufType; extern PyTypeObject VecI16BufType; extern PyTypeObject VecU8BufType; extern PyTypeObject VecFloatBufType; extern PyTypeObject VecBoolBufType; extern PyTypeObject VecTBufType; extern PyTypeObject VecNestedBufType; // Wrapper type objects for boxed vec values extern PyTypeObject VecI64Type; extern PyTypeObject VecI32Type; extern PyTypeObject VecI16Type; extern PyTypeObject VecU8Type; extern PyTypeObject VecFloatType; extern PyTypeObject VecBoolType; extern PyTypeObject VecTType; extern PyTypeObject VecNestedType; // Iterator type objects for vec iteration extern PyTypeObject VecI64IterType; extern PyTypeObject VecI32IterType; extern PyTypeObject VecI16IterType; extern PyTypeObject VecU8IterType; extern PyTypeObject VecFloatIterType; extern PyTypeObject VecBoolIterType; extern PyTypeObject VecTIterType; extern PyTypeObject VecNestedIterType; // Type objects corresponding to the 'i64', 'i32', 'i16, and 'u8' types extern PyTypeObject *LibRTVecs_I64TypeObj; extern PyTypeObject *LibRTVecs_I32TypeObj; extern PyTypeObject *LibRTVecs_I16TypeObj; extern PyTypeObject *LibRTVecs_U8TypeObj; extern VecI64API Vec_I64API; extern VecI32API Vec_I32API; extern VecI16API Vec_I16API; extern VecU8API Vec_U8API; extern VecFloatAPI Vec_FloatAPI; extern VecBoolAPI Vec_BoolAPI; extern VecTAPI Vec_TAPI; extern VecNestedAPI Vec_NestedAPI; static inline int Vec_CheckFloatError(PyObject *o) { if (PyFloat_Check(o)) { PyErr_SetString(PyExc_TypeError, "integer argument expected, got float"); return 1; } return 0; } // vec[i64] operations static inline int VecI64_Check(PyObject *o) { return o->ob_type == &VecI64Type; } static inline PyObject *VecI64_BoxItem(int64_t x) { return PyLong_FromLongLong(x); } static inline int64_t VecI64_UnboxItem(PyObject *o) { if (Vec_CheckFloatError(o)) return -1; return PyLong_AsLongLong(o); } static inline int VecI64_IsUnboxError(int64_t x) { return x == -1 && PyErr_Occurred(); } PyObject *VecI64_Box(VecI64); VecI64 VecI64_Append(VecI64, int64_t x); VecI64 VecI64_Extend(VecI64, PyObject *iterable); VecI64 VecI64_ExtendVec(VecI64 dst, VecI64 src); VecI64 VecI64_Remove(VecI64, int64_t x); VecI64PopResult VecI64_Pop(VecI64 v, Py_ssize_t index); // vec[i32] operations static inline int VecI32_Check(PyObject *o) { return o->ob_type == &VecI32Type; } static inline PyObject *VecI32_BoxItem(int32_t x) { return PyLong_FromLongLong(x); } static inline int32_t VecI32_UnboxItem(PyObject *o) { if (Vec_CheckFloatError(o)) return -1; long x = PyLong_AsLong(o); if (x > INT32_MAX || x < INT32_MIN) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to i32"); return -1; } return x; } static inline int VecI32_IsUnboxError(int32_t x) { return x == -1 && PyErr_Occurred(); } PyObject *VecI32_Box(VecI32); VecI32 VecI32_Append(VecI32, int32_t x); VecI32 VecI32_Extend(VecI32, PyObject *iterable); VecI32 VecI32_ExtendVec(VecI32 dst, VecI32 src); VecI32 VecI32_Remove(VecI32, int32_t x); VecI32PopResult VecI32_Pop(VecI32 v, Py_ssize_t index); // vec[i16] operations static inline int VecI16_Check(PyObject *o) { return o->ob_type == &VecI16Type; } static inline PyObject *VecI16_BoxItem(int16_t x) { return PyLong_FromLongLong(x); } static inline int16_t VecI16_UnboxItem(PyObject *o) { if (Vec_CheckFloatError(o)) return -1; long x = PyLong_AsLong(o); if (x >= 32768 || x < -32768) { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to i16"); return -1; } return x; } static inline int VecI16_IsUnboxError(int16_t x) { return x == -1 && PyErr_Occurred(); } PyObject *VecI16_Box(VecI16); VecI16 VecI16_Append(VecI16, int16_t x); VecI16 VecI16_Extend(VecI16, PyObject *iterable); VecI16 VecI16_ExtendVec(VecI16 dst, VecI16 src); VecI16 VecI16_Remove(VecI16, int16_t x); VecI16PopResult VecI16_Pop(VecI16 v, Py_ssize_t index); // vec[u8] operations static inline int VecU8_Check(PyObject *o) { return o->ob_type == &VecU8Type; } static inline PyObject *VecU8_BoxItem(uint8_t x) { return PyLong_FromUnsignedLong(x); } static inline uint8_t VecU8_UnboxItem(PyObject *o) { if (Vec_CheckFloatError(o)) return -1; unsigned long x = PyLong_AsUnsignedLong(o); if (x <= 255) return x; else if (x == (unsigned long)-1) return 239; else { PyErr_SetString(PyExc_OverflowError, "Python int too large to convert to u8"); return 239; } } static inline int VecU8_IsUnboxError(uint8_t x) { return x == 239 && PyErr_Occurred(); } PyObject *VecU8_Box(VecU8); VecU8 VecU8_Append(VecU8, uint8_t x); VecU8 VecU8_Extend(VecU8, PyObject *iterable); VecU8 VecU8_ExtendVec(VecU8 dst, VecU8 src); VecU8 VecU8_Remove(VecU8, uint8_t x); VecU8PopResult VecU8_Pop(VecU8 v, Py_ssize_t index); // vec[float] operations static inline int VecFloat_Check(PyObject *o) { return o->ob_type == &VecFloatType; } static inline PyObject *VecFloat_BoxItem(double x) { return PyFloat_FromDouble(x); } static inline double VecFloat_UnboxItem(PyObject *o) { return PyFloat_AsDouble(o); } static inline int VecFloat_IsUnboxError(double x) { return x == -1.0 && PyErr_Occurred(); } PyObject *VecFloat_Box(VecFloat); VecFloat VecFloat_Append(VecFloat, double x); VecFloat VecFloat_Extend(VecFloat, PyObject *iterable); VecFloat VecFloat_ExtendVec(VecFloat dst, VecFloat src); VecFloat VecFloat_Remove(VecFloat, double x); VecFloatPopResult VecFloat_Pop(VecFloat v, Py_ssize_t index); // vec[bool] operations static inline int VecBool_Check(PyObject *o) { return o->ob_type == &VecBoolType; } static inline PyObject *VecBool_BoxItem(char x) { if (x == 1) { Py_INCREF(Py_True); return Py_True; } else { Py_INCREF(Py_False); return Py_False; } } static inline char VecBool_UnboxItem(PyObject *o) { if (o == Py_False) { return 0; } else if (o == Py_True) { return 1; } else { PyErr_SetString(PyExc_TypeError, "bool value expected"); return 2; } } static inline int VecBool_IsUnboxError(char x) { return x == 2; } PyObject *VecBool_Box(VecBool); VecBool VecBool_Append(VecBool, char x); VecBool VecBool_Extend(VecBool, PyObject *iterable); VecBool VecBool_ExtendVec(VecBool dst, VecBool src); VecBool VecBool_Remove(VecBool, char x); VecBoolPopResult VecBool_Pop(VecBool v, Py_ssize_t index); // vec[t] operations static inline int VecT_Check(PyObject *o) { return o->ob_type == &VecTType; } static inline int VecT_ItemCheck(VecT v, PyObject *item, size_t item_type) { if (PyObject_TypeCheck(item, VEC_ITEM_TYPE(item_type))) { return 1; } else if ((item_type & 1) && item == Py_None) { return 1; } else { // TODO: better error message PyErr_SetString(PyExc_TypeError, "invalid item type"); return 0; } } VecT VecT_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type); VecT VecT_FromIterable(size_t item_type, PyObject *iterable, int64_t cap); PyObject *VecT_Box(VecT vec, size_t item_type); VecT VecT_Append(VecT vec, PyObject *x, size_t item_type); VecT VecT_Extend(VecT vec, PyObject *iterable, size_t item_type); VecT VecT_ExtendVec(VecT dst, VecT src, size_t item_type); VecT VecT_Remove(VecT vec, PyObject *x); VecTPopResult VecT_Pop(VecT v, Py_ssize_t index); // Nested vec operations static inline int VecNested_Check(PyObject *o) { return o->ob_type == &VecNestedType; } VecNested VecNested_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type, size_t depth); PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable, int64_t cap); PyObject *VecNested_Box(VecNested); VecNested VecNested_Append(VecNested vec, VecNestedBufItem x); VecNested VecNested_Extend(VecNested vec, PyObject *iterable); VecNested VecNested_ExtendVec(VecNested dst, VecNested src); VecNested VecNested_Remove(VecNested vec, VecNestedBufItem x); VecNestedPopResult VecNested_Pop(VecNested v, Py_ssize_t index); static inline PyObject *VecNested_ItemBuf(VecNestedBufObject *parent, VecNestedBufItem item) { if (item.items == NULL) return NULL; if (parent->depth > 1) return (PyObject *)VEC_NESTED_BUF_FROM_ITEMS(item.items); if (parent->item_type == VEC_ITEM_TYPE_I64) return (PyObject *)VEC_I64_BUF_FROM_ITEMS(item.items); if (parent->item_type == VEC_ITEM_TYPE_U8) return (PyObject *)VEC_U8_BUF_FROM_ITEMS(item.items); if (parent->item_type == VEC_ITEM_TYPE_FLOAT) return (PyObject *)VEC_FLOAT_BUF_FROM_ITEMS(item.items); if (parent->item_type == VEC_ITEM_TYPE_I32) return (PyObject *)VEC_I32_BUF_FROM_ITEMS(item.items); if (parent->item_type == VEC_ITEM_TYPE_I16) return (PyObject *)VEC_I16_BUF_FROM_ITEMS(item.items); if (parent->item_type == VEC_ITEM_TYPE_BOOL) return (PyObject *)VEC_BOOL_BUF_FROM_ITEMS(item.items); return (PyObject *)VEC_T_BUF_FROM_ITEMS(item.items); } static inline void VecNested_ItemXINCREF(VecNestedBufObject *parent, VecNestedBufItem item) { Py_XINCREF(VecNested_ItemBuf(parent, item)); } static inline void VecNested_ItemXDECREF(VecNestedBufObject *parent, VecNestedBufItem item) { Py_XDECREF(VecNested_ItemBuf(parent, item)); } static inline void VecNested_ItemCLEAR(VecNestedBufObject *parent, VecNestedBufItem *item) { PyObject *buf = VecNested_ItemBuf(parent, *item); item->items = NULL; Py_XDECREF(buf); } static inline int VecNested_ItemVISIT( VecNestedBufObject *parent, VecNestedBufItem item, visitproc visit, void *arg) { PyObject *buf = VecNested_ItemBuf(parent, item); if (buf) { int ret = visit(buf, arg); if (ret) return ret; } return 0; } // Return 0 on success, -1 on error. Store unboxed item in *unboxed if successful. // Return a *borrowed* reference. static inline int VecNested_UnboxItem(VecNested v, PyObject *item, VecNestedBufItem *unboxed) { VecNestedBufObject *v_buf = VEC_NESTED_BUF(v); size_t depth = v_buf->depth; if (depth == 1) { if (item->ob_type == &VecTType) { // Boxed vec[t] always has items != NULL (buf is allocated on boxing) VecTObject *o = (VecTObject *)item; if (VEC_T_BUF(o->vec)->item_type == v_buf->item_type) { unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } } else if (item->ob_type == &VecI64Type && v_buf->item_type == VEC_ITEM_TYPE_I64) { VecI64Object *o = (VecI64Object *)item; unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } else if (item->ob_type == &VecU8Type && v_buf->item_type == VEC_ITEM_TYPE_U8) { VecU8Object *o = (VecU8Object *)item; unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } else if (item->ob_type == &VecFloatType && v_buf->item_type == VEC_ITEM_TYPE_FLOAT) { VecFloatObject *o = (VecFloatObject *)item; unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } else if (item->ob_type == &VecI32Type && v_buf->item_type == VEC_ITEM_TYPE_I32) { VecI32Object *o = (VecI32Object *)item; unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } else if (item->ob_type == &VecI16Type && v_buf->item_type == VEC_ITEM_TYPE_I16) { VecI16Object *o = (VecI16Object *)item; unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } else if (item->ob_type == &VecBoolType && v_buf->item_type == VEC_ITEM_TYPE_BOOL) { VecBoolObject *o = (VecBoolObject *)item; unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } } else if (item->ob_type == &VecNestedType) { VecNestedObject *o = (VecNestedObject *)item; VecNestedBufObject *o_buf = VEC_NESTED_BUF(o->vec); if (o_buf->depth == v_buf->depth - 1 && o_buf->item_type == v_buf->item_type) { unboxed->len = o->vec.len; unboxed->items = o->vec.items; return 0; } } // TODO: better error message PyErr_SetString(PyExc_TypeError, "invalid item type"); return -1; } static inline PyObject *VecNested_BoxItem(VecNested v, VecNestedBufItem item) { if (item.len < 0) Py_RETURN_NONE; VecNestedBufObject *v_buf = VEC_NESTED_BUF(v); VecNested_ItemXINCREF(v_buf, item); if (v_buf->depth > 1) { // Item is a nested vec VecNested iv = { .len = item.len, .items = (VecNestedBufItem *)item.items }; return VecNested_Box(iv); } else { // Item is a non-nested vec size_t item_type = v_buf->item_type; if (item_type == VEC_ITEM_TYPE_I64) { VecI64 iv = { .len = item.len, .items = (int64_t *)item.items }; return VecI64_Box(iv); } else if (item_type == VEC_ITEM_TYPE_U8) { VecU8 iv = { .len = item.len, .items = (uint8_t *)item.items }; return VecU8_Box(iv); } else if (item_type == VEC_ITEM_TYPE_FLOAT) { VecFloat iv = { .len = item.len, .items = (double *)item.items }; return VecFloat_Box(iv); } else if (item_type == VEC_ITEM_TYPE_I32) { VecI32 iv = { .len = item.len, .items = (int32_t *)item.items }; return VecI32_Box(iv); } else if (item_type == VEC_ITEM_TYPE_I16) { VecI16 iv = { .len = item.len, .items = (int16_t *)item.items }; return VecI16_Box(iv); } else if (item_type == VEC_ITEM_TYPE_BOOL) { VecBool iv = { .len = item.len, .items = (char *)item.items }; return VecBool_Box(iv); } else { // Generic vec[t] VecT iv = { .len = item.len, .items = (PyObject **)item.items }; return VecT_Box(iv, item_type); } } } // Growth helpers static inline Py_ssize_t Vec_GrowCapacity(Py_ssize_t cap) { if (unlikely(cap > (PY_SSIZE_T_MAX - 1) / 2)) { // Allocation will fail at this size, but avoid overflow return PY_SSIZE_T_MAX; } return 2 * cap + 1; } static inline Py_ssize_t Vec_GrowCapacityTo(Py_ssize_t cap, Py_ssize_t min_cap) { while (cap < min_cap) { if (unlikely(cap > (PY_SSIZE_T_MAX - 1) / 2)) { cap = min_cap; break; } cap = 2 * cap + 1; } return cap; } // Misc helpers PyObject *Vec_TypeToStr(size_t item_type, size_t depth); PyObject *Vec_GenericRepr(PyObject *vec, size_t item_type, size_t depth, int verbose); PyObject *Vec_GenericRichcompare(Py_ssize_t *len, PyObject **items, Py_ssize_t *other_len, PyObject **other_items, int op); int Vec_GenericRemove(Py_ssize_t *len, PyObject **items, PyObject *item); PyObject *Vec_GenericPopWrapper(Py_ssize_t *len, PyObject **items, PyObject *args); PyObject *Vec_GenericPop(Py_ssize_t *len, PyObject **items, Py_ssize_t index); #endif // VEC_H_INCL ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/librt_vecs_api.c0000644000175100017510000000312215200142331016431 0ustar00runnerrunner#include "librt_vecs_api.h" VecCapsule *VecApi = NULL; VecI64API VecI64Api = {0}; VecI32API VecI32Api = {0}; VecI16API VecI16Api = {0}; VecU8API VecU8Api = {0}; VecFloatAPI VecFloatApi = {0}; VecBoolAPI VecBoolApi = {0}; VecTAPI VecTApi = {0}; VecNestedAPI VecNestedApi = {0}; int import_librt_vecs(void) { PyObject *mod = PyImport_ImportModule("librt.vecs"); if (mod == NULL) return -1; Py_DECREF(mod); // we import just for the side effect of making the below work. VecCapsule *capsule = PyCapsule_Import("librt.vecs._C_API", 0); if (!capsule) return -1; if (capsule->abi_version() != LIBRT_VECS_ABI_VERSION) { char err[128]; snprintf(err, sizeof(err), "ABI version conflict for librt.vecs, expected %d, found %d", LIBRT_VECS_ABI_VERSION, capsule->abi_version()); PyErr_SetString(PyExc_ValueError, err); return -1; } if (capsule->api_version() < LIBRT_VECS_API_VERSION) { char err[128]; snprintf(err, sizeof(err), "API version conflict for librt.vecs, expected %d or newer, found %d (hint: upgrade librt)", LIBRT_VECS_API_VERSION, capsule->api_version()); PyErr_SetString(PyExc_ValueError, err); return -1; } VecApi = capsule; VecI64Api = *VecApi->i64; VecI32Api = *VecApi->i32; VecI16Api = *VecApi->i16; VecU8Api = *VecApi->u8; VecFloatApi = *VecApi->float_; VecBoolApi = *VecApi->bool_; VecTApi = *VecApi->t; VecNestedApi = *VecApi->nested; return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/librt_vecs_api.h0000644000175100017510000000100415200142331016433 0ustar00runnerrunner#ifndef LIBRT_VECS_API_H #define LIBRT_VECS_API_H #include "librt_vecs.h" #define PY_SSIZE_T_CLEAN #include #include int import_librt_vecs(void); // Global API pointers initialized by import_librt_vecs() extern VecCapsule *VecApi; extern VecI64API VecI64Api; extern VecI32API VecI32Api; extern VecI16API VecI16Api; extern VecU8API VecU8Api; extern VecFloatAPI VecFloatApi; extern VecBoolAPI VecBoolApi; extern VecTAPI VecTApi; extern VecNestedAPI VecNestedApi; #endif // LIBRT_VECS_API_H ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_bool.c0000644000175100017510000000100715200142331015234 0ustar00runnerrunner#define VEC VecBool #define VEC_TYPE VecBoolType #define VEC_OBJECT VecBoolObject #define BUF_OBJECT VecBoolBufObject #define BUF_TYPE VecBoolBufType #define NAME(suffix) VecBool##suffix #define FUNC(suffix) VecBool_##suffix #define ITEM_TYPE_STR "bool" #define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_BOOL #define ITEM_C_TYPE char #define FEATURES Vec_BoolAPI #define BOX_ITEM VecBool_BoxItem #define UNBOX_ITEM VecBool_UnboxItem #define IS_UNBOX_ERROR VecBool_IsUnboxError #define BUFFER_FORMAT "b" #include "vec_template.c" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_float.c0000644000175100017510000000110415200142331015404 0ustar00runnerrunner#define VEC VecFloat #define VEC_TYPE VecFloatType #define VEC_OBJECT VecFloatObject #define BUF_OBJECT VecFloatBufObject #define BUF_TYPE VecFloatBufType #define NAME(suffix) VecFloat##suffix #define FUNC(suffix) VecFloat_##suffix #define ITEM_TYPE_STR "float" #define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_FLOAT #define ITEM_C_TYPE double #define FEATURES Vec_FloatAPI #define BOX_ITEM VecFloat_BoxItem #define UNBOX_ITEM VecFloat_UnboxItem #define IS_UNBOX_ERROR VecFloat_IsUnboxError #define BUFFER_FORMAT_CHAR_OK(c) ((c) == 'd') #define BUFFER_FORMAT "d" #include "vec_template.c" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_i16.c0000644000175100017510000000105315200142331014701 0ustar00runnerrunner#define VEC VecI16 #define VEC_TYPE VecI16Type #define VEC_OBJECT VecI16Object #define BUF_OBJECT VecI16BufObject #define BUF_TYPE VecI16BufType #define NAME(suffix) VecI16##suffix #define FUNC(suffix) VecI16_##suffix #define ITEM_TYPE_STR "i16" #define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_I16 #define ITEM_C_TYPE int16_t #define FEATURES Vec_I16API #define BOX_ITEM VecI16_BoxItem #define UNBOX_ITEM VecI16_UnboxItem #define IS_UNBOX_ERROR VecI16_IsUnboxError #define BUFFER_FORMAT_CHAR_OK(c) ((c) == 'h') #define BUFFER_FORMAT "h" #include "vec_template.c" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_i32.c0000644000175100017510000000112015200142331014672 0ustar00runnerrunner#define VEC VecI32 #define VEC_TYPE VecI32Type #define VEC_OBJECT VecI32Object #define BUF_OBJECT VecI32BufObject #define BUF_TYPE VecI32BufType #define NAME(suffix) VecI32##suffix #define FUNC(suffix) VecI32_##suffix #define ITEM_TYPE_STR "i32" #define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_I32 #define ITEM_C_TYPE int32_t #define FEATURES Vec_I32API #define BOX_ITEM VecI32_BoxItem #define UNBOX_ITEM VecI32_UnboxItem #define IS_UNBOX_ERROR VecI32_IsUnboxError #define BUFFER_FORMAT_CHAR_OK(c) ((c) == 'i' || ((c) == 'l' && sizeof(long) == 4)) #define BUFFER_FORMAT "i" #include "vec_template.c" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_i64.c0000644000175100017510000000112015200142331014677 0ustar00runnerrunner#define VEC VecI64 #define VEC_TYPE VecI64Type #define VEC_OBJECT VecI64Object #define BUF_OBJECT VecI64BufObject #define BUF_TYPE VecI64BufType #define NAME(suffix) VecI64##suffix #define FUNC(suffix) VecI64_##suffix #define ITEM_TYPE_STR "i64" #define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_I64 #define ITEM_C_TYPE int64_t #define FEATURES Vec_I64API #define BOX_ITEM VecI64_BoxItem #define UNBOX_ITEM VecI64_UnboxItem #define IS_UNBOX_ERROR VecI64_IsUnboxError #define BUFFER_FORMAT_CHAR_OK(c) ((c) == 'q' || ((c) == 'l' && sizeof(long) == 8)) #define BUFFER_FORMAT "q" #include "vec_template.c" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_nested.c0000644000175100017510000006025615200142331015576 0ustar00runnerrunner// Implementation of nested vec[t], when t is a vec type. // // Examples of types supported: // - vec[vec[i64]] // - vec[vec[vec[str]]] // - vec[vec[str | None]] #define PY_SSIZE_T_CLEAN #include #include "librt_vecs.h" #include "vecs_internal.h" #define VEC_BUF(v) ((VecNestedBufObject *)((char *)(v).items - offsetof(VecNestedBufObject, items))) #define VEC_CAP(v) (VEC_BUF(v)->ob_base.ob_size) #define VEC_INCREF(v) do { if ((v).items) Py_INCREF(VEC_BUF(v)); } while (0) #define VEC_DECREF(v) do { if ((v).items) Py_DECREF(VEC_BUF(v)); } while (0) static inline VecNested vec_error() { VecNested v = { .len = -1 }; return v; } static inline void vec_track_buffer(VecNested *vec) { PyObject_GC_Track(VEC_BUF(*vec)); } static inline PyObject *box_vec_item_by_index(VecNested v, Py_ssize_t index) { return VecNested_BoxItem(v, v.items[index]); } // Alloc a partially initialized vec. If size > 0, caller *must* immediately initialize len, // and items. Caller *must* also call vec_track_buffer on the returned vec but only // after initializing the items. static VecNested vec_alloc(Py_ssize_t size, size_t item_type, size_t depth) { VecNestedBufObject *buf = PyObject_GC_NewVar(VecNestedBufObject, &VecNestedBufType, size); if (buf == NULL) return vec_error(); buf->item_type = item_type; buf->depth = depth; if (!Vec_IsMagicItemType(item_type)) Py_INCREF(VEC_BUF_ITEM_TYPE(buf)); VecNested res = { .items = buf->items }; return res; } // Box a nested vec value, stealing 'vec'. On error, decref 'vec'. PyObject *VecNested_Box(VecNested vec) { VecNestedObject *obj = PyObject_GC_New(VecNestedObject, &VecNestedType); if (obj == NULL) { VEC_DECREF(vec); return NULL; } obj->vec = vec; PyObject_GC_Track(obj); return (PyObject *)obj; } VecNested VecNested_Unbox(PyObject *obj, size_t item_type, size_t depth) { if (obj->ob_type == &VecNestedType) { VecNested result = ((VecNestedObject *)obj)->vec; VecNestedBufObject *buf = VEC_BUF(result); if (buf->item_type == item_type && buf->depth == depth) { VEC_INCREF(result); // TODO: Should we borrow instead? return result; } } // TODO: Better error message, with name of type PyErr_SetString(PyExc_TypeError, "vec[t] expected"); return vec_error(); } VecNested VecNested_ConvertFromNested(VecNestedBufItem item) { return (VecNested) { item.len, (VecNestedBufItem *)item.items }; } VecNested VecNested_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type, size_t depth) { if (cap < 0) { PyErr_SetString(PyExc_ValueError, "capacity must not be negative"); return vec_error(); } if (cap < size) cap = size; VecNested vec = vec_alloc(cap, item_type, depth); if (VEC_IS_ERROR(vec)) return vec; for (Py_ssize_t i = 0; i < cap; i++) { vec.items[i].len = -1; vec.items[i].items = 0; } vec.len = size; vec_track_buffer(&vec); return vec; } static PyObject *vec_repr(PyObject *self) { VecNested v = ((VecNestedObject *)self)->vec; VecNestedBufObject *buf = VEC_BUF(v); return Vec_GenericRepr(self, buf->item_type, buf->depth, 1); } static PyObject *vec_get_item(PyObject *o, Py_ssize_t i) { VecNested v = ((VecNestedObject *)o)->vec; if ((size_t)i < (size_t)v.len) { return box_vec_item_by_index(v, i); } else if ((size_t)i + (size_t)v.len < (size_t)v.len) { return box_vec_item_by_index(v, i + v.len); } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return NULL; } } VecNested VecNested_Slice(VecNested vec, int64_t start, int64_t end) { if (start < 0) start += vec.len; if (end < 0) end += vec.len; if (start < 0) start = 0; if (start >= vec.len) start = vec.len; if (end < start) end = start; if (end > vec.len) end = vec.len; int64_t slicelength = end - start; VecNestedBufObject *vec_buf = VEC_BUF(vec); VecNested res = vec_alloc(slicelength, vec_buf->item_type, vec_buf->depth); if (VEC_IS_ERROR(res)) return res; res.len = slicelength; for (Py_ssize_t i = 0; i < slicelength; i++) { VecNestedBufItem item = vec.items[start + i]; VecNested_ItemXINCREF(vec_buf, item); res.items[i] = item; } vec_track_buffer(&res); return res; } static PyObject *vec_subscript(PyObject *self, PyObject *item) { VecNested vec = ((VecNestedObject *)self)->vec; if (PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; if ((size_t)i < (size_t)vec.len) { return box_vec_item_by_index(vec, i); } else if ((size_t)i + (size_t)vec.len < (size_t)vec.len) { return box_vec_item_by_index(vec, i + vec.len); } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return NULL; } } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step; if (PySlice_Unpack(item, &start, &stop, &step) < 0) return NULL; Py_ssize_t slicelength = PySlice_AdjustIndices(vec.len, &start, &stop, step); VecNestedBufObject *vec_buf = VEC_BUF(vec); VecNested res = vec_alloc(slicelength, vec_buf->item_type, vec_buf->depth); if (VEC_IS_ERROR(res)) return NULL; res.len = slicelength; Py_ssize_t j = start; for (Py_ssize_t i = 0; i < slicelength; i++) { VecNestedBufItem item = vec.items[j]; VecNested_ItemXINCREF(vec_buf, item); res.items[i] = item; j += step; } vec_track_buffer(&res); return VecNested_Box(res); } else { PyErr_Format(PyExc_TypeError, "vec indices must be integers or slices, not %.100s", item->ob_type->tp_name); return NULL; } } static int vec_ass_item(PyObject *self, Py_ssize_t i, PyObject *o) { VecNested v = ((VecNestedObject *)self)->vec; if ((size_t)i + (size_t)v.len < (size_t)v.len) { i += v.len; } if ((size_t)i < (size_t)v.len) { VecNestedBufItem item; if (VecNested_UnboxItem(v, o, &item) < 0) return -1; VecNestedBufObject *v_buf = VEC_BUF(v); VecNested_ItemXINCREF(v_buf, item); VecNested_ItemXDECREF(v_buf, v.items[i]); v.items[i] = item; return 0; } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return -1; } } static int vec_contains(PyObject *self, PyObject *value) { VecNested v = ((VecNestedObject *)self)->vec; for (Py_ssize_t i = 0; i < v.len; i++) { PyObject *item = box_vec_item_by_index(v, i); if (item == NULL) return -1; if (item == value) { Py_DECREF(item); return 1; } int cmp = PyObject_RichCompareBool(item, value, Py_EQ); Py_DECREF(item); if (cmp != 0) return cmp; // 1 if equal, -1 on error } return 0; } static PyObject *compare_vec_eq(VecNested x, VecNested y, int op) { int cmp = 1; PyObject *res; VecNestedBufObject *x_buf = VEC_BUF(x); VecNestedBufObject *y_buf = VEC_BUF(y); if (x.len != y.len || x_buf->item_type != y_buf->item_type || x_buf->depth != y_buf->depth) { cmp = 0; } else { for (Py_ssize_t i = 0; i < x.len; i++) { PyObject *x_item = box_vec_item_by_index(x, i); PyObject *y_item = box_vec_item_by_index(y, i); int itemcmp = PyObject_RichCompareBool(x_item, y_item, Py_EQ); Py_DECREF(x_item); Py_DECREF(y_item); if (itemcmp < 0) return NULL; if (!itemcmp) { cmp = 0; break; } } } if (op == Py_NE) cmp = cmp ^ 1; res = cmp ? Py_True : Py_False; Py_INCREF(res); return res; } PyObject *vec_richcompare(PyObject *self, PyObject *other, int op) { PyObject *res; if (op == Py_EQ || op == Py_NE) { if (other->ob_type != &VecNestedType) { res = op == Py_EQ ? Py_False : Py_True; } else { return compare_vec_eq(((VecNestedObject *)self)->vec, ((VecNestedObject *)other)->vec, op); } } else res = Py_NotImplemented; Py_INCREF(res); return res; } // Append item to 'vec', stealing 'vec'. Return 'vec' with item appended. VecNested VecNested_Append(VecNested vec, VecNestedBufItem x) { Py_ssize_t cap = VEC_CAP(vec); VecNestedBufObject *vec_buf = VEC_BUF(vec); VecNested_ItemXINCREF(vec_buf, x); if (vec.len < cap) { // Slot may have duplicate ref from prior remove/pop VecNested_ItemXDECREF(vec_buf, vec.items[vec.len]); vec.items[vec.len] = x; vec.len++; return vec; } else { Py_ssize_t new_size = Vec_GrowCapacity(cap); // TODO: Avoid initializing to zero here VecNested new = vec_alloc(new_size, vec_buf->item_type, vec_buf->depth); if (VEC_IS_ERROR(new)) { VecNested_ItemXDECREF(vec_buf, x); // The input vec is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(vec); return new; } // Copy items to new vec. memcpy(new.items, vec.items, sizeof(VecNestedBufItem) * vec.len); // TODO: How to safely represent deleted items? memset(new.items + vec.len, 0, sizeof(VecNestedBufItem) * (new_size - vec.len)); if (Py_REFCNT(vec_buf) > 1) { // Other references to old buffer exist; INCREF items in new buffer // so old buffer keeps valid references for aliases. for (Py_ssize_t i = 0; i < vec.len; i++) VecNested_ItemXINCREF(vec_buf, new.items[i]); } else { // No aliases; transfer ownership by clearing old buffer items. memset(vec.items, 0, sizeof(VecNestedBufItem) * vec.len); } new.items[vec.len] = x; new.len = vec.len + 1; vec_track_buffer(&new); VEC_DECREF(vec); return new; } } // Extend 'vec' with items from 'iterable', stealing 'vec'. // Return extended 'vec', or error vec on failure. VecNested VecNested_Extend(VecNested vec, PyObject *iterable) { if (VecNested_Check(iterable)) { VecNested src = ((VecNestedObject *)iterable)->vec; VecNestedBufObject *vec_buf = VEC_BUF(vec); VecNestedBufObject *src_buf = VEC_BUF(src); if (src_buf->item_type == vec_buf->item_type && src_buf->depth == vec_buf->depth) { return VecNested_ExtendVec(vec, src); } } PyObject *iter = PyObject_GetIter(iterable); if (iter == NULL) { VEC_DECREF(vec); return vec_error(); } PyObject *item; while ((item = PyIter_Next(iter)) != NULL) { VecNestedBufItem vecitem; if (VecNested_UnboxItem(vec, item, &vecitem) < 0) { Py_DECREF(iter); VEC_DECREF(vec); Py_DECREF(item); return vec_error(); } vec = VecNested_Append(vec, vecitem); Py_DECREF(item); if (VEC_IS_ERROR(vec)) { Py_DECREF(iter); return vec_error(); } } Py_DECREF(iter); if (PyErr_Occurred()) { VEC_DECREF(vec); return vec_error(); } return vec; } // Extend 'dst' with items from 'src' vec, stealing 'dst', borrowing 'src'. // Return extended vec, or error vec on failure. VecNested VecNested_ExtendVec(VecNested dst, VecNested src) { if (src.len == 0) return dst; if (src.len > PY_SSIZE_T_MAX - dst.len) { PyErr_NoMemory(); VEC_DECREF(dst); return vec_error(); } Py_ssize_t new_len = dst.len + src.len; // VecNested buf is never NULL (even for empty vecs), so no NULL guard needed Py_ssize_t cap = VEC_CAP(dst); VecNestedBufObject *dst_buf = VEC_BUF(dst); VecNestedBufObject *src_buf = VEC_BUF(src); if (new_len <= cap && dst.items != src.items) { // Fast path: enough capacity and no aliasing for (Py_ssize_t i = 0; i < src.len; i++) { VecNestedBufItem item = src.items[i]; VecNested_ItemXINCREF(src_buf, item); // Slot may have duplicate ref from prior remove/pop VecNested_ItemXDECREF(dst_buf, dst.items[dst.len + i]); dst.items[dst.len + i] = item; } dst.len = new_len; return dst; } // Need to reallocate (or dst and src share a buffer) Py_ssize_t new_cap = Vec_GrowCapacityTo(cap, new_len); int aliased = dst.items == src.items; VecNested new = vec_alloc(new_cap, dst_buf->item_type, dst_buf->depth); if (VEC_IS_ERROR(new)) { VEC_DECREF(dst); return new; } if (aliased) { // dst and src share a buffer -- incref all items instead of // moving refs, to avoid mutating the shared buffer for (Py_ssize_t i = 0; i < dst.len; i++) { VecNested_ItemXINCREF(dst_buf, dst.items[i]); new.items[i] = dst.items[i]; } } else { memcpy(new.items, dst.items, sizeof(VecNestedBufItem) * dst.len); if (Py_REFCNT(dst_buf) > 1) { for (Py_ssize_t i = 0; i < dst.len; i++) VecNested_ItemXINCREF(dst_buf, new.items[i]); } else { memset(dst.items, 0, sizeof(VecNestedBufItem) * dst.len); } } // Copy src items (incref each buf) for (Py_ssize_t i = 0; i < src.len; i++) { VecNestedBufItem item = src.items[i]; VecNested_ItemXINCREF(src_buf, item); new.items[dst.len + i] = item; } memset(new.items + new_len, 0, sizeof(VecNestedBufItem) * (new_cap - new_len)); new.len = new_len; vec_track_buffer(&new); VEC_DECREF(dst); return new; } // Remove item from 'vec', stealing 'vec'. Return 'vec' with item removed. VecNested VecNested_Remove(VecNested self, VecNestedBufItem arg) { VecNestedBufItem *items = self.items; VecNestedBufObject *self_buf = VEC_BUF(self); PyObject *boxed_arg = VecNested_BoxItem(self, arg); if (boxed_arg == NULL) { // The input self is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(self); return vec_error(); } for (Py_ssize_t i = 0; i < self.len; i++) { int match = 0; if (items[i].len == arg.len && items[i].items == arg.items) match = 1; else { PyObject *item = box_vec_item_by_index(self, i); if (item == NULL) { Py_DECREF(boxed_arg); // The input self is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(self); return vec_error(); } int itemcmp = PyObject_RichCompareBool(item, boxed_arg, Py_EQ); Py_DECREF(item); if (itemcmp < 0) { Py_DECREF(boxed_arg); // The input self is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(self); return vec_error(); } match = itemcmp; } if (match) { if (i < self.len - 1) { VecNested_ItemCLEAR(self_buf, &items[i]); for (; i < self.len - 1; i++) { items[i] = items[i + 1]; } VecNested_ItemXINCREF(self_buf, items[self.len - 1]); } self.len--; Py_DECREF(boxed_arg); // Return the stolen reference without INCREF return self; } } Py_DECREF(boxed_arg); PyErr_SetString(PyExc_ValueError, "vec.remove(x): x not in vec"); // The input self is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(self); return vec_error(); } // Pop item from 'vec', stealing 'vec'. Return struct with modified 'vec' and the popped item. VecNestedPopResult VecNested_Pop(VecNested v, Py_ssize_t index) { VecNestedPopResult result; if (index < 0) index += v.len; if (index < 0 || index >= v.len) { PyErr_SetString(PyExc_IndexError, "index out of range"); // The input v is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(v); result.f0 = vec_error(); result.f1.len = 0; result.f1.items = NULL; return result; } VecNestedBufItem *items = v.items; VecNestedBufObject *v_buf = VEC_BUF(v); result.f1 = items[index]; for (Py_ssize_t i = index; i < v.len - 1; i++) items[i] = items[i + 1]; if (v.len > 0) VecNested_ItemXINCREF(v_buf, items[v.len - 1]); v.len--; // Return the stolen reference without INCREF result.f0 = v; return result; } static int VecNested_traverse(VecNestedObject *self, visitproc visit, void *arg) { if (self->vec.items) Py_VISIT(VEC_BUF(self->vec)); return 0; } static int VecNested_clear(VecNestedObject *self) { if (self->vec.items) { Py_DECREF(VEC_BUF(self->vec)); self->vec.items = NULL; } return 0; } static void VecNested_dealloc(VecNestedObject *self) { PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, VecNested_dealloc) VecNested_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } static int VecNestedBuf_traverse(VecNestedBufObject *self, visitproc visit, void *arg) { if (!Vec_IsMagicItemType(self->item_type)) Py_VISIT(VEC_BUF_ITEM_TYPE(self)); for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) { int ret = VecNested_ItemVISIT(self, self->items[i], visit, arg); if (ret) return ret; } return 0; } static inline int VecNestedBuf_clear(VecNestedBufObject *self) { for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) { VecNested_ItemCLEAR(self, &self->items[i]); } if (self->item_type && !Vec_IsMagicItemType(self->item_type)) { Py_DECREF(VEC_BUF_ITEM_TYPE(self)); self->item_type = 0; } return 0; } static void VecNestedBuf_dealloc(VecNestedBufObject *self) { PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, VecNestedBuf_dealloc) VecNestedBuf_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } static Py_ssize_t vec_ext_length(PyObject *o) { return ((VecNestedObject *)o)->vec.len; } static PyMappingMethods VecNestedMapping = { .mp_length = vec_ext_length, .mp_subscript = vec_subscript, }; static PySequenceMethods VecNestedSequence = { .sq_item = vec_get_item, .sq_ass_item = vec_ass_item, .sq_contains = vec_contains, }; static PyMethodDef vec_methods[] = { {NULL, NULL, 0, NULL}, /* Sentinel */ }; // Iterator type for nested vecs typedef struct { PyObject_HEAD VecNested vec; // Unboxed vec (keeps buffer alive via items reference) Py_ssize_t index; // Current iteration index } VecNestedIterObject; PyTypeObject VecNestedIterType; static PyObject *VecNested_iter(PyObject *self) { VecNestedIterObject *it = PyObject_GC_New(VecNestedIterObject, &VecNestedIterType); if (it == NULL) return NULL; it->vec = ((VecNestedObject *)self)->vec; VEC_INCREF(it->vec); it->index = 0; PyObject_GC_Track(it); return (PyObject *)it; } static int VecNestedIter_traverse(VecNestedIterObject *self, visitproc visit, void *arg) { if (self->vec.items) Py_VISIT(VEC_BUF(self->vec)); return 0; } static int VecNestedIter_clear(VecNestedIterObject *self) { if (self->vec.items) { Py_DECREF(VEC_BUF(self->vec)); self->vec.items = NULL; } return 0; } static void VecNestedIter_dealloc(VecNestedIterObject *self) { PyObject_GC_UnTrack(self); VEC_DECREF(self->vec); PyObject_GC_Del(self); } static PyObject *VecNestedIter_next(VecNestedIterObject *self) { if (self->vec.items == NULL) return NULL; if (self->index < self->vec.len) { PyObject *item = box_vec_item_by_index(self->vec, self->index); if (item == NULL) return NULL; self->index++; return item; } VEC_DECREF(self->vec); self->vec.items = NULL; return NULL; // StopIteration } static PyObject *VecNestedIter_len(VecNestedIterObject *self, PyObject *Py_UNUSED(ignored)) { if (self->vec.items == NULL) return PyLong_FromSsize_t(0); Py_ssize_t remaining = self->vec.len - self->index; if (remaining < 0) remaining = 0; return PyLong_FromSsize_t(remaining); } static PyMethodDef VecNestedIter_methods[] = { {"__length_hint__", (PyCFunction)VecNestedIter_len, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; PyTypeObject VecNestedIterType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec_nested_iterator", .tp_basicsize = sizeof(VecNestedIterObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)VecNestedIter_traverse, .tp_clear = (inquiry)VecNestedIter_clear, .tp_dealloc = (destructor)VecNestedIter_dealloc, .tp_iter = PyObject_SelfIter, .tp_iternext = (iternextfunc)VecNestedIter_next, .tp_methods = VecNestedIter_methods, }; PyTypeObject VecNestedBufType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vecbuf", .tp_doc = "Internal data buffer used by vec objects", .tp_basicsize = sizeof(VecNestedBufObject) - sizeof(VecNestedBufItem), .tp_itemsize = sizeof(VecNestedBufItem), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)VecNestedBuf_traverse, //.tp_new = vecbuf_i64_new, //?? .tp_free = PyObject_GC_Del, .tp_clear = (inquiry)VecNestedBuf_clear, .tp_dealloc = (destructor)VecNestedBuf_dealloc, }; PyTypeObject VecNestedType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec", .tp_doc = "Mutable sequence-like container optimized for compilation with mypyc", .tp_basicsize = sizeof(VecNestedObject), .tp_itemsize = 0, .tp_base = &VecType, // Inherit from base vec type for isinstance() support .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)VecNested_traverse, .tp_clear = (inquiry)VecNested_clear, .tp_dealloc = (destructor)VecNested_dealloc, //.tp_free = PyObject_GC_Del, .tp_repr = (reprfunc)vec_repr, .tp_iter = VecNested_iter, .tp_as_sequence = &VecNestedSequence, .tp_as_mapping = &VecNestedMapping, .tp_richcompare = vec_richcompare, .tp_methods = vec_methods, // TODO: free }; PyObject *VecNested_FromIterable(size_t item_type, size_t depth, PyObject *iterable, int64_t cap) { VecNested v = vec_alloc(cap, item_type, depth); if (VEC_IS_ERROR(v)) return NULL; if (cap > 0) { for (int64_t i = 0; i < cap; i++) { v.items[i].len = -1; v.items[i].items = 0; } } v.len = 0; vec_track_buffer(&v); PyObject *iter = PyObject_GetIter(iterable); if (iter == NULL) { VEC_DECREF(v); return NULL; } PyObject *item; while ((item = PyIter_Next(iter)) != NULL) { VecNestedBufItem vecitem; if (VecNested_UnboxItem(v, item, &vecitem) < 0) { Py_DECREF(iter); VEC_DECREF(v); Py_DECREF(item); return NULL; } v = VecNested_Append(v, vecitem); Py_DECREF(item); if (VEC_IS_ERROR(v)) { Py_DECREF(iter); VEC_DECREF(v); return NULL; } } Py_DECREF(iter); if (PyErr_Occurred()) { VEC_DECREF(v); return NULL; } return VecNested_Box(v); } VecNestedAPI Vec_NestedAPI = { &VecNestedType, &VecNestedBufType, VecNested_New, VecNested_Box, VecNested_Unbox, VecNested_ConvertFromNested, VecNested_Append, VecNested_Pop, VecNested_Remove, VecNested_Slice, VecNested_Extend, VecNested_ExtendVec, }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_t.c0000644000175100017510000006133715200142331014560 0ustar00runnerrunner// Implementation of generic vec[t], when t is a plain type object (possibly optional). // // Examples of types supported: // // - vec[str] // - vec[str | None] // - vec[object] // - vec[UserClass] #define PY_SSIZE_T_CLEAN #include #include "librt_vecs.h" #include "vecs_internal.h" #define VEC_BUF(v) ((VecTBufObject *)((char *)(v).items - offsetof(VecTBufObject, items))) #define VEC_CAP(v) (VEC_BUF(v)->ob_base.ob_size) #define VEC_INCREF(v) do { if ((v).items) Py_INCREF(VEC_BUF(v)); } while (0) #define VEC_DECREF(v) do { if ((v).items) Py_DECREF(VEC_BUF(v)); } while (0) static inline VecT vec_error() { VecT v = { .len = -1 }; return v; } static inline VecTBufObject *alloc_buf(Py_ssize_t size, size_t item_type) { VecTBufObject *buf = PyObject_GC_NewVar(VecTBufObject, &VecTBufType, size); if (buf == NULL) return NULL; buf->item_type = item_type; Py_INCREF(VEC_BUF_ITEM_TYPE(buf)); return buf; } static inline void vec_track_buffer(VecT *vec) { if (vec->items != NULL) { PyObject_GC_Track(VEC_T_BUF(*vec)); } } // Alloc a partially initialized vec. If size > 0, caller *must* immediately initialize len, // and items. Caller *must* also call vec_track_buffer on the returned vec but only // after initializing the items. static VecT vec_alloc(Py_ssize_t size, size_t item_type) { VecTBufObject *buf; if (size == 0) { buf = NULL; } else { buf = alloc_buf(size, item_type); if (buf == NULL) return vec_error(); } return (VecT) { .items = (buf != NULL) ? buf->items : NULL }; } // Box a VecT value, stealing 'vec'. On failure, return NULL and decref 'vec'. PyObject *VecT_Box(VecT vec, size_t item_type) { // An unboxed empty vec may have NULL items, but a boxed vec must have a buf // allocated, since it contains the item type if (vec.items == NULL) { VecTBufObject *buf = alloc_buf(0, item_type); if (buf == NULL) return NULL; vec.items = buf->items; vec_track_buffer(&vec); } VecTObject *obj = PyObject_GC_New(VecTObject, &VecTType); if (obj == NULL) { // items is always defined, so no need for a NULL check Py_DECREF(VEC_BUF(vec)); return NULL; } obj->vec = vec; PyObject_GC_Track(obj); return (PyObject *)obj; } VecT VecT_Unbox(PyObject *obj, size_t item_type) { if (obj->ob_type == &VecTType) { VecT result = ((VecTObject *)obj)->vec; if (VEC_BUF(result)->item_type == item_type) { VEC_INCREF(result); // TODO: Should we borrow instead? return result; } } // TODO: Better error message, with name of type PyErr_SetString(PyExc_TypeError, "vec[t] expected"); return vec_error(); } VecT VecT_ConvertFromNested(VecNestedBufItem item) { return (VecT) { item.len, (PyObject **)item.items }; } VecT VecT_New(Py_ssize_t size, Py_ssize_t cap, size_t item_type) { if (cap < 0) { PyErr_SetString(PyExc_ValueError, "capacity must not be negative"); return vec_error(); } if (cap < size) cap = size; VecT vec = vec_alloc(cap, item_type); if (VEC_IS_ERROR(vec)) return vec; for (Py_ssize_t i = 0; i < cap; i++) { vec.items[i] = NULL; } vec_track_buffer(&vec); vec.len = size; return vec; } static PyObject *vec_repr(PyObject *self) { VecTObject *v = (VecTObject *)self; return Vec_GenericRepr(self, VEC_BUF(v->vec)->item_type, 0, 1); } static PyObject *vec_get_item(PyObject *o, Py_ssize_t i) { VecT v = ((VecTObject *)o)->vec; if ((size_t)i < (size_t)v.len) { PyObject *item = v.items[i]; Py_INCREF(item); return item; } else if ((size_t)i + (size_t)v.len < (size_t)v.len) { PyObject *item = v.items[i + v.len]; Py_INCREF(item); return item; } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return NULL; } } VecT VecT_Slice(VecT vec, int64_t start, int64_t end) { if (start < 0) start += vec.len; if (end < 0) end += vec.len; if (start < 0) start = 0; if (start >= vec.len) start = vec.len; if (end < start) end = start; if (end > vec.len) end = vec.len; int64_t slicelength = end - start; if (slicelength == 0) return (VecT) { .len = 0, .items = NULL }; VecT res = vec_alloc(slicelength, VEC_BUF(vec)->item_type); if (VEC_IS_ERROR(res)) return res; res.len = slicelength; for (Py_ssize_t i = 0; i < slicelength; i++) { PyObject *item = vec.items[start + i]; Py_INCREF(item); res.items[i] = item; } vec_track_buffer(&res); return res; } static PyObject *vec_subscript(PyObject *self, PyObject *item) { VecT vec = ((VecTObject *)self)->vec; if (PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; if ((size_t)i < (size_t)vec.len) { PyObject *result = vec.items[i]; Py_INCREF(result); return result; } else if ((size_t)i + (size_t)vec.len < (size_t)vec.len) { PyObject *result = vec.items[i + vec.len]; Py_INCREF(result); return result; } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return NULL; } } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step; if (PySlice_Unpack(item, &start, &stop, &step) < 0) return NULL; Py_ssize_t slicelength = PySlice_AdjustIndices(vec.len, &start, &stop, step); VecT res = vec_alloc(slicelength, VEC_BUF(vec)->item_type); if (VEC_IS_ERROR(res)) return NULL; res.len = slicelength; Py_ssize_t j = start; for (Py_ssize_t i = 0; i < slicelength; i++) { PyObject *item = vec.items[j]; Py_INCREF(item); res.items[i] = item; j += step; } vec_track_buffer(&res); PyObject *result = VecT_Box(res, VEC_BUF(vec)->item_type); if (result == NULL) { VEC_DECREF(res); } return result; } else { PyErr_Format(PyExc_TypeError, "vec indices must be integers or slices, not %.100s", item->ob_type->tp_name); return NULL; } } static int vec_ass_item(PyObject *self, Py_ssize_t i, PyObject *o) { VecT v = ((VecTObject *)self)->vec; if (!VecT_ItemCheck(v, o, VEC_BUF(v)->item_type)) return -1; if ((size_t)i < (size_t)v.len) { PyObject *old = v.items[i]; Py_INCREF(o); v.items[i] = o; Py_XDECREF(old); return 0; } else if ((size_t)i + (size_t)v.len < (size_t)v.len) { PyObject *old = v.items[i + v.len]; Py_INCREF(o); v.items[i + v.len] = o; Py_XDECREF(old); return 0; } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return -1; } } static int vec_contains(PyObject *self, PyObject *value) { VecT v = ((VecTObject *)self)->vec; for (Py_ssize_t i = 0; i < v.len; i++) { PyObject *item = v.items[i]; if (item == value) { return 1; } Py_INCREF(item); int cmp = PyObject_RichCompareBool(item, value, Py_EQ); Py_DECREF(item); if (cmp != 0) return cmp; // 1 if equal, -1 on error } return 0; } static PyObject *vec_richcompare(PyObject *self, PyObject *other, int op) { PyObject *res; if (op == Py_EQ || op == Py_NE) { if (other->ob_type != &VecTType) { res = op == Py_EQ ? Py_False : Py_True; } else { VecT x = ((VecTObject *)self)->vec; VecT y = ((VecTObject *)other)->vec; if (VEC_BUF(x)->item_type != VEC_BUF(y)->item_type) { res = op == Py_EQ ? Py_False : Py_True; } else { // TODO: why pointers to len? return Vec_GenericRichcompare(&x.len, x.items, &y.len, y.items, op); } } } else res = Py_NotImplemented; Py_INCREF(res); return res; } // Append item to 'vec', stealing 'vec'. Return 'vec' with item appended. VecT VecT_Append(VecT vec, PyObject *x, size_t item_type) { if (vec.items == NULL) { VecT new = vec_alloc(1, item_type); if (VEC_IS_ERROR(new)) return new; Py_INCREF(x); new.len = 1; new.items[0] = x; vec_track_buffer(&new); return new; } Py_ssize_t cap = VEC_CAP(vec); Py_INCREF(x); if (vec.len < cap) { // Slot may have duplicate ref from prior remove/pop Py_XSETREF(vec.items[vec.len], x); vec.len++; return vec; } else { Py_ssize_t new_size = Vec_GrowCapacity(cap); // TODO: Avoid initializing to zero here VecT new = vec_alloc(new_size, VEC_BUF(vec)->item_type); if (VEC_IS_ERROR(new)) { Py_DECREF(x); // The input vec is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(vec); return new; } // Copy items to new vec. memcpy(new.items, vec.items, sizeof(PyObject *) * vec.len); memset(new.items + vec.len, 0, sizeof(PyObject *) * (new_size - vec.len)); VecTBufObject *old_buf = VEC_BUF(vec); if (Py_REFCNT(old_buf) > 1) { // Other references to old buffer exist; INCREF items in new buffer // so old buffer keeps valid references for aliases. for (Py_ssize_t i = 0; i < vec.len; i++) Py_XINCREF(new.items[i]); } else { // No aliases; transfer ownership by clearing old buffer items. memset(vec.items, 0, sizeof(PyObject *) * vec.len); } new.items[vec.len] = x; new.len = vec.len + 1; vec_track_buffer(&new); VEC_DECREF(vec); return new; } } // Extend 'vec' with items from 'iterable', stealing 'vec'. // Return extended 'vec', or error vec on failure. VecT VecT_Extend(VecT vec, PyObject *iterable, size_t item_type) { if (VecT_Check(iterable)) { VecT src = ((VecTObject *)iterable)->vec; if (src.items != NULL && VEC_BUF(src)->item_type == item_type) { return VecT_ExtendVec(vec, src, item_type); } } PyObject *iter = PyObject_GetIter(iterable); if (iter == NULL) { VEC_DECREF(vec); return vec_error(); } PyObject *item; while ((item = PyIter_Next(iter)) != NULL) { if (!VecT_ItemCheck(vec, item, item_type)) { Py_DECREF(iter); VEC_DECREF(vec); Py_DECREF(item); return vec_error(); } vec = VecT_Append(vec, item, item_type); Py_DECREF(item); if (VEC_IS_ERROR(vec)) { Py_DECREF(iter); return vec_error(); } } Py_DECREF(iter); if (PyErr_Occurred()) { VEC_DECREF(vec); return vec_error(); } return vec; } // Extend 'dst' with items from 'src' vec, stealing 'dst', borrowing 'src'. // Return extended vec, or error vec on failure. VecT VecT_ExtendVec(VecT dst, VecT src, size_t item_type) { if (src.len == 0) return dst; if (src.len > PY_SSIZE_T_MAX - dst.len) { PyErr_NoMemory(); VEC_DECREF(dst); return vec_error(); } Py_ssize_t new_len = dst.len + src.len; if (dst.items == NULL) { // dst is empty, allocate new buf VecT new = vec_alloc(new_len, item_type); if (VEC_IS_ERROR(new)) { VEC_DECREF(dst); return new; } for (Py_ssize_t i = 0; i < src.len; i++) { Py_INCREF(src.items[i]); new.items[i] = src.items[i]; } memset(new.items + src.len, 0, sizeof(PyObject *) * (new_len - src.len)); new.len = new_len; vec_track_buffer(&new); return new; } Py_ssize_t cap = VEC_CAP(dst); if (new_len <= cap && dst.items != src.items) { // Fast path: enough capacity and no aliasing for (Py_ssize_t i = 0; i < src.len; i++) { Py_INCREF(src.items[i]); // Slot may have duplicate ref from prior remove/pop Py_XSETREF(dst.items[dst.len + i], src.items[i]); } dst.len = new_len; return dst; } // Need to reallocate (or dst and src share a buffer) Py_ssize_t new_cap = Vec_GrowCapacityTo(cap, new_len); int aliased = dst.items == src.items; VecT new = vec_alloc(new_cap, VEC_BUF(dst)->item_type); if (VEC_IS_ERROR(new)) { VEC_DECREF(dst); return new; } if (aliased) { // dst and src share a buffer -- incref all items instead of // moving refs, to avoid mutating the shared buffer for (Py_ssize_t i = 0; i < dst.len; i++) { Py_INCREF(dst.items[i]); new.items[i] = dst.items[i]; } } else { memcpy(new.items, dst.items, sizeof(PyObject *) * dst.len); VecTBufObject *dst_buf = VEC_BUF(dst); if (Py_REFCNT(dst_buf) > 1) { for (Py_ssize_t i = 0; i < dst.len; i++) Py_XINCREF(new.items[i]); } else { memset(dst.items, 0, sizeof(PyObject *) * dst.len); } } // Copy src items (incref each) for (Py_ssize_t i = 0; i < src.len; i++) { Py_INCREF(src.items[i]); new.items[dst.len + i] = src.items[i]; } memset(new.items + new_len, 0, sizeof(PyObject *) * (new_cap - new_len)); new.len = new_len; vec_track_buffer(&new); VEC_DECREF(dst); return new; } // Convert vec to list, stealing 'v'. PyObject *VecT_ToList(VecT v) { Py_ssize_t n = v.len; PyObject *list = PyList_New(n); if (list == NULL) { VEC_DECREF(v); return NULL; } if (n > 0 && Py_REFCNT(VEC_BUF(v)) == 1) { for (Py_ssize_t i = 0; i < n; i++) { PyList_SET_ITEM(list, i, v.items[i]); v.items[i] = NULL; } } else { for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = v.items[i]; Py_INCREF(item); PyList_SET_ITEM(list, i, item); } } VEC_DECREF(v); return list; } // Convert vec to tuple, stealing 'v'. PyObject *VecT_ToTuple(VecT v) { Py_ssize_t n = v.len; PyObject *tuple = PyTuple_New(n); if (tuple == NULL) { VEC_DECREF(v); return NULL; } if (n > 0 && Py_REFCNT(VEC_BUF(v)) == 1) { for (Py_ssize_t i = 0; i < n; i++) { PyTuple_SET_ITEM(tuple, i, v.items[i]); v.items[i] = NULL; } } else { for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = v.items[i]; Py_INCREF(item); PyTuple_SET_ITEM(tuple, i, item); } } VEC_DECREF(v); return tuple; } // Remove item from 'vec', stealing 'vec'. Return 'vec' with item removed. VecT VecT_Remove(VecT v, PyObject *arg) { PyObject **items = v.items; for (Py_ssize_t i = 0; i < v.len; i++) { int match = 0; if (items[i] == arg) match = 1; else { int itemcmp = PyObject_RichCompareBool(items[i], arg, Py_EQ); if (itemcmp < 0) { // The input v is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(v); return vec_error(); } match = itemcmp; } if (match) { if (i < v.len - 1) { Py_CLEAR(items[i]); for (; i < v.len - 1; i++) { items[i] = items[i + 1]; } // Keep a duplicate item, since there could be another reference // to the buffer with a longer length, and they expect a valid reference. Py_XINCREF(items[v.len - 1]); } v.len--; // Return the stolen reference without INCREF return v; } } PyErr_SetString(PyExc_ValueError, "vec.remove(x): x not in vec"); // The input v is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(v); return vec_error(); } // Pop item from 'vec', stealing 'vec'. Return struct with modified 'vec' and the popped item. VecTPopResult VecT_Pop(VecT v, Py_ssize_t index) { VecTPopResult result; if (index < 0) index += v.len; if (index < 0 || index >= v.len) { PyErr_SetString(PyExc_IndexError, "index out of range"); // The input v is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(v); result.f0 = vec_error(); result.f1 = NULL; return result; } PyObject **items = v.items; result.f1 = items[index]; for (Py_ssize_t i = index; i < v.len - 1; i++) items[i] = items[i + 1]; // Keep duplicate item, since there could be another reference // to the buffer with a longer length, and they expect a valid reference. Py_XINCREF(items[v.len - 1]); v.len--; // Return the stolen reference without INCREF result.f0 = v; return result; } static int VecT_traverse(VecTObject *self, visitproc visit, void *arg) { if (self->vec.items) Py_VISIT(VEC_BUF(self->vec)); return 0; } static int VecT_clear(VecTObject *self) { if (self->vec.items) { Py_DECREF(VEC_BUF(self->vec)); self->vec.items = NULL; } return 0; } static void VecT_dealloc(VecTObject *self) { PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, VecT_dealloc) VecT_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } static int VecTBuf_traverse(VecTBufObject *self, visitproc visit, void *arg) { Py_VISIT(VEC_BUF_ITEM_TYPE(self)); for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) { Py_VISIT(self->items[i]); } return 0; } static inline int VecTBuf_clear(VecTBufObject *self) { if (self->item_type) { Py_DECREF(VEC_BUF_ITEM_TYPE(self)); self->item_type = 0; } for (Py_ssize_t i = 0; i < VEC_BUF_SIZE(self); i++) { Py_CLEAR(self->items[i]); } return 0; } static void VecTBuf_dealloc(VecTBufObject *self) { PyObject_GC_UnTrack(self); Py_TRASHCAN_BEGIN(self, VecTBuf_dealloc) VecTBuf_clear(self); Py_TYPE(self)->tp_free((PyObject *)self); Py_TRASHCAN_END } static Py_ssize_t vec_length(PyObject *o) { return ((VecTObject *)o)->vec.len; } static PyMappingMethods VecTMapping = { .mp_length = vec_length, .mp_subscript = vec_subscript, }; static PySequenceMethods VecTSequence = { .sq_item = vec_get_item, .sq_ass_item = vec_ass_item, .sq_contains = vec_contains, }; static PyMethodDef vec_methods[] = { {NULL, NULL, 0, NULL}, /* Sentinel */ }; // Iterator type for vec[T] (reference types) typedef struct { PyObject_HEAD VecT vec; // Unboxed vec (keeps buffer alive via items reference) Py_ssize_t index; // Current iteration index } VecTIterObject; PyTypeObject VecTIterType; static PyObject *VecT_iter(PyObject *self) { VecTIterObject *it = PyObject_GC_New(VecTIterObject, &VecTIterType); if (it == NULL) return NULL; it->vec = ((VecTObject *)self)->vec; VEC_INCREF(it->vec); it->index = 0; PyObject_GC_Track(it); return (PyObject *)it; } static int VecTIter_traverse(VecTIterObject *self, visitproc visit, void *arg) { if (self->vec.items) Py_VISIT(VEC_BUF(self->vec)); return 0; } static int VecTIter_clear(VecTIterObject *self) { if (self->vec.items) { Py_DECREF(VEC_BUF(self->vec)); self->vec.items = NULL; } return 0; } static void VecTIter_dealloc(VecTIterObject *self) { PyObject_GC_UnTrack(self); VEC_DECREF(self->vec); PyObject_GC_Del(self); } static PyObject *VecTIter_next(VecTIterObject *self) { if (self->vec.items == NULL) return NULL; if (self->index < self->vec.len) { PyObject *item = self->vec.items[self->index]; self->index++; Py_INCREF(item); return item; } VEC_DECREF(self->vec); self->vec.items = NULL; return NULL; // StopIteration } static PyObject *VecTIter_len(VecTIterObject *self, PyObject *Py_UNUSED(ignored)) { if (self->vec.items == NULL) return PyLong_FromSsize_t(0); Py_ssize_t remaining = self->vec.len - self->index; if (remaining < 0) remaining = 0; return PyLong_FromSsize_t(remaining); } static PyMethodDef VecTIter_methods[] = { {"__length_hint__", (PyCFunction)VecTIter_len, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; PyTypeObject VecTIterType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec_iterator", .tp_basicsize = sizeof(VecTIterObject), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)VecTIter_traverse, .tp_clear = (inquiry)VecTIter_clear, .tp_dealloc = (destructor)VecTIter_dealloc, .tp_iter = PyObject_SelfIter, .tp_iternext = (iternextfunc)VecTIter_next, .tp_methods = VecTIter_methods, }; PyTypeObject VecTBufType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vecbuf", .tp_doc = "Internal data buffer used by vec objects", .tp_basicsize = sizeof(VecTBufObject) - sizeof(PyObject *), .tp_itemsize = sizeof(PyObject *), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)VecTBuf_traverse, //.tp_new = vecbuf_i64_new, //?? .tp_free = PyObject_GC_Del, .tp_clear = (inquiry)VecTBuf_clear, .tp_dealloc = (destructor)VecTBuf_dealloc, }; PyTypeObject VecTType = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec", .tp_doc = "Mutable sequence-like container optimized for compilation with mypyc", .tp_basicsize = sizeof(VecTObject), .tp_itemsize = 0, .tp_base = &VecType, // Inherit from base vec type for isinstance() support .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, .tp_traverse = (traverseproc)VecT_traverse, .tp_clear = (inquiry)VecT_clear, .tp_dealloc = (destructor)VecT_dealloc, //.tp_free = PyObject_GC_Del, .tp_repr = (reprfunc)vec_repr, .tp_iter = VecT_iter, .tp_as_sequence = &VecTSequence, .tp_as_mapping = &VecTMapping, .tp_richcompare = vec_richcompare, .tp_methods = vec_methods, // TODO: free }; static inline VecT vec_from_sequence( size_t item_type, PyObject *seq, int64_t cap, const int is_list) { Py_ssize_t n = is_list ? PyList_GET_SIZE(seq) : PyTuple_GET_SIZE(seq); Py_ssize_t alloc_size = n > cap ? n : cap; VecT v = vec_alloc(alloc_size, item_type); if (VEC_IS_ERROR(v)) return vec_error(); for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = is_list ? PyList_GET_ITEM(seq, i) : PyTuple_GET_ITEM(seq, i); if (!VecT_ItemCheck(v, item, item_type)) { for (Py_ssize_t j = i; j < alloc_size; j++) v.items[j] = NULL; VEC_DECREF(v); return vec_error(); } Py_INCREF(item); v.items[i] = item; } for (Py_ssize_t j = n; j < alloc_size; j++) v.items[j] = NULL; vec_track_buffer(&v); v.len = n; return v; } VecT VecT_FromIterable(size_t item_type, PyObject *iterable, int64_t cap) { if (PyList_CheckExact(iterable)) { return vec_from_sequence(item_type, iterable, cap, 1); } else if (PyTuple_CheckExact(iterable)) { return vec_from_sequence(item_type, iterable, cap, 0); } VecT v = vec_alloc(cap, item_type); if (VEC_IS_ERROR(v)) return vec_error(); if (cap > 0) { for (int64_t i = 0; i < cap; i++) v.items[i] = NULL; } v.len = 0; vec_track_buffer(&v); PyObject *iter = PyObject_GetIter(iterable); if (iter == NULL) { VEC_DECREF(v); return vec_error(); } PyObject *item; while ((item = PyIter_Next(iter)) != NULL) { if (!VecT_ItemCheck(v, item, item_type)) { Py_DECREF(iter); VEC_DECREF(v); Py_DECREF(item); return vec_error(); } v = VecT_Append(v, item, item_type); Py_DECREF(item); if (VEC_IS_ERROR(v)) { Py_DECREF(iter); VEC_DECREF(v); return vec_error(); } } Py_DECREF(iter); if (PyErr_Occurred()) { VEC_DECREF(v); return vec_error(); } return v; } VecTAPI Vec_TAPI = { &VecTType, &VecTBufType, VecT_New, VecT_Box, VecT_Unbox, VecT_ConvertFromNested, VecT_Append, VecT_Pop, VecT_Remove, VecT_Slice, VecT_FromIterable, VecT_Extend, VecT_ExtendVec, VecT_ToList, VecT_ToTuple, }; ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_template.c0000644000175100017510000006033115200142331016121 0ustar00runnerrunner// NOTE: This file can't be compiled on its own, it must be #included // with certain #defines set, as described below. // // Implementation of a vec class specialized to a specific item type, such // as vec[i64] or vec[float]. Assume that certain #defines are provided that // provide all the item type specific definitions: // // VEC vec C type (e.g. VecI32) // VEC_TYPE boxed vec type object (e.g. VecI32Type) // VEC_OBJECT boxed Python object struct (e.g. VecI32Object) // BUF_OBJECT buffer Python object struct (e.g. VecI32BufObject) // BUF_TYPE buffer type object (e.g. VecI32BufType) // NAME(suffix) macro to create prefixed name with given suffix (e.g. VecI32##suffix) // FUNC(suffix) macro to create prefixed function name with suffix (e.g. VecI32_##suffix) // ITEM_TYPE_STR vec item type as C string literal (e.g. "i32") // ITEM_TYPE_MAGIC integer constant corresponding to the item type (e.g. VEC_ITEM_TYPE_I32) // ITEM_C_TYPE C type used for items (e.g. int32_t) // FEATURES capsule API struct name (e.g. Vec_I32API) // BOX_ITEM C function to box item (e.g. VecI32_BoxItem) // UNBOX_ITEM C function to unbox item (e.g. VecI32_UnboxItem) // IS_UNBOX_ERROR C function to check for unbox error (e.g. VecI32_IsUnboxError) #ifndef VEC #error "VEC must be defined" #endif #define PY_SSIZE_T_CLEAN #include #include "librt_vecs.h" #include "vecs_internal.h" #include "mypyc_util.h" #define VEC_BUF(v) ((BUF_OBJECT *)((char *)(v).items - offsetof(BUF_OBJECT, items))) #define VEC_CAP(v) (VEC_BUF(v)->ob_base.ob_size) #define VEC_INCREF(v) do { if ((v).items) Py_INCREF(VEC_BUF(v)); } while (0) #define VEC_DECREF(v) do { if ((v).items) Py_DECREF(VEC_BUF(v)); } while (0) inline static VEC vec_error() { VEC v = { .len = -1 }; return v; } // Alloc a partially initialized vec. Caller *must* initialize len. static VEC vec_alloc(Py_ssize_t size) { BUF_OBJECT *buf; /* TODO: Check for overflow */ if (size == 0) { buf = NULL; } else { buf = PyObject_NewVar(BUF_OBJECT, &BUF_TYPE, size); if (buf == NULL) return vec_error(); } VEC res = { .items = (buf != NULL) ? buf->items : NULL }; return res; } static void vec_dealloc(VEC_OBJECT *self) { if (self->vec.items) { Py_DECREF(VEC_BUF(self->vec)); self->vec.items = NULL; } PyObject_Del(self); } // Box a vec[] value, stealing 'vec'. On error, decref 'vec'. PyObject *FUNC(Box)(VEC vec) { VEC_OBJECT *obj = PyObject_New(VEC_OBJECT, &VEC_TYPE); if (obj == NULL) { VEC_DECREF(vec); return NULL; } obj->vec = vec; return (PyObject *)obj; } VEC FUNC(Unbox)(PyObject *obj) { if (obj->ob_type == &VEC_TYPE) { VEC result = ((VEC_OBJECT *)obj)->vec; VEC_INCREF(result); // TODO: Should we borrow instead? return result; } else { PyErr_SetString(PyExc_TypeError, "vec[" ITEM_TYPE_STR "] expected"); return vec_error(); } } VEC FUNC(ConvertFromNested)(VecNestedBufItem item) { return (VEC) { item.len, (ITEM_C_TYPE *)item.items }; } VEC FUNC(New)(Py_ssize_t size, Py_ssize_t cap) { if (cap < 0) { PyErr_SetString(PyExc_ValueError, "capacity must not be negative"); return vec_error(); } if (cap < size) cap = size; VEC vec = vec_alloc(cap); if (VEC_IS_ERROR(vec)) return vec; for (Py_ssize_t i = 0; i < cap; i++) { vec.items[i] = 0; } vec.len = size; return vec; } #ifdef BUFFER_FORMAT_CHAR_OK inline static int buffer_format_matches(const char *fmt) { char c = *fmt; if (c == '@' || c == '=') { c = fmt[1]; } #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ else if (c == '<') { c = fmt[1]; } else if (c == '>' || c == '!') { return 0; } #else else if (c == '>') { c = fmt[1]; } else if (c == '<' || c == '!') { return 0; } #endif return c != '\0' && BUFFER_FORMAT_CHAR_OK(c); } // Try to get a compatible buffer view from 'obj'. Return 1 if successful // (view is filled and caller must call PyBuffer_Release), 0 if the object // doesn't support buffer protocol or the format doesn't match (no cleanup // needed), or -1 on error. inline static int vec_get_buffer(PyObject *obj, Py_buffer *view) { if (PyObject_GetBuffer(obj, view, PyBUF_C_CONTIGUOUS | PyBUF_FORMAT) != 0) { PyErr_Clear(); return 0; } if (view->ndim == 1 && view->itemsize == sizeof(ITEM_C_TYPE) && buffer_format_matches(view->format)) { return 1; } PyBuffer_Release(view); return 0; } #endif static inline VEC vec_from_sequence(PyObject *seq, int64_t cap, const int is_list) { Py_ssize_t n = is_list ? PyList_GET_SIZE(seq) : PyTuple_GET_SIZE(seq); Py_ssize_t alloc_size = n > cap ? n : cap; VEC v = vec_alloc(alloc_size); if (VEC_IS_ERROR(v)) return vec_error(); for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = is_list ? PyList_GET_ITEM(seq, i) : PyTuple_GET_ITEM(seq, i); ITEM_C_TYPE x = UNBOX_ITEM(item); if (IS_UNBOX_ERROR(x)) { VEC_DECREF(v); return vec_error(); } v.items[i] = x; } v.len = n; return v; } VEC FUNC(FromIterable)(PyObject *iterable, int64_t cap) { if (cap < 0) { PyErr_SetString(PyExc_ValueError, "capacity must not be negative"); return vec_error(); } if (ITEM_TYPE_MAGIC == VEC_ITEM_TYPE_U8 && PyBytes_CheckExact(iterable)) { Py_ssize_t n = PyBytes_GET_SIZE(iterable); Py_ssize_t alloc_size = n > cap ? n : cap; VEC v = vec_alloc(alloc_size); if (VEC_IS_ERROR(v)) return vec_error(); if (n > 0) memcpy(v.items, PyBytes_AS_STRING(iterable), n); v.len = n; return v; } #ifdef BUFFER_FORMAT_CHAR_OK Py_buffer view; int buf_ok = vec_get_buffer(iterable, &view); if (buf_ok < 0) return vec_error(); if (buf_ok) { Py_ssize_t n = view.len / (Py_ssize_t)sizeof(ITEM_C_TYPE); Py_ssize_t alloc_size = n > cap ? n : cap; VEC v = vec_alloc(alloc_size); if (VEC_IS_ERROR(v)) { PyBuffer_Release(&view); return vec_error(); } if (n > 0) { memcpy(v.items, view.buf, n * sizeof(ITEM_C_TYPE)); } v.len = n; PyBuffer_Release(&view); return v; } #endif if (PyList_CheckExact(iterable)) { return vec_from_sequence(iterable, cap, 1); } else if (PyTuple_CheckExact(iterable)) { return vec_from_sequence(iterable, cap, 0); } VEC v = vec_alloc(cap); if (VEC_IS_ERROR(v)) return vec_error(); if (cap > 0) { memset(v.items, 0, sizeof(ITEM_C_TYPE) * cap); } v.len = 0; PyObject *iter = PyObject_GetIter(iterable); if (iter == NULL) { VEC_DECREF(v); return vec_error(); } PyObject *item; while ((item = PyIter_Next(iter)) != NULL) { ITEM_C_TYPE x = UNBOX_ITEM(item); Py_DECREF(item); if (IS_UNBOX_ERROR(x)) { Py_DECREF(iter); VEC_DECREF(v); return vec_error(); } v = FUNC(Append)(v, x); if (VEC_IS_ERROR(v)) { Py_DECREF(iter); VEC_DECREF(v); return vec_error(); } } Py_DECREF(iter); if (PyErr_Occurred()) { VEC_DECREF(v); return vec_error(); } return v; } static PyObject *vec_new(PyTypeObject *self, PyObject *args, PyObject *kw) { static char *kwlist[] = {"", "capacity", NULL}; PyObject *init = NULL; int64_t cap = 0; if (!PyArg_ParseTupleAndKeywords(args, kw, "|OL:vec", kwlist, &init, &cap)) { return NULL; } if (cap < 0) { PyErr_SetString(PyExc_ValueError, "capacity must not be negative"); return NULL; } if (init == NULL) { return FUNC(Box)(FUNC(New)(0, cap)); } else { VEC v = FUNC(FromIterable)(init, cap); if (VEC_IS_ERROR(v)) return NULL; return FUNC(Box)(v); } } static PyObject *vec_repr(PyObject *self) { return Vec_GenericRepr(self, ITEM_TYPE_MAGIC, 0, 1); } static PyObject *vec_get_item(PyObject *o, Py_ssize_t i) { VEC v = ((VEC_OBJECT *)o)->vec; if ((size_t)i < (size_t)v.len) { return BOX_ITEM(v.items[i]); } else if ((size_t)i + (size_t)v.len < (size_t)v.len) { return BOX_ITEM(v.items[i + v.len]); } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return NULL; } } VEC FUNC(Slice)(VEC vec, int64_t start, int64_t end) { if (start < 0) start += vec.len; if (end < 0) end += vec.len; if (start < 0) start = 0; if (start >= vec.len) start = vec.len; if (end < start) end = start; if (end > vec.len) end = vec.len; int64_t slicelength = end - start; VEC res = vec_alloc(slicelength); if (VEC_IS_ERROR(res)) return res; res.len = slicelength; for (Py_ssize_t i = 0; i < slicelength; i++) res.items[i] = vec.items[start + i]; return res; } static PyObject *vec_subscript(PyObject *self, PyObject *item) { VEC vec = ((VEC_OBJECT *)self)->vec; if (PyIndex_Check(item)) { Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; if ((size_t)i < (size_t)vec.len) { return BOX_ITEM(vec.items[i]); } else if ((size_t)i + (size_t)vec.len < (size_t)vec.len) { return BOX_ITEM(vec.items[i + vec.len]); } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return NULL; } } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step; if (PySlice_Unpack(item, &start, &stop, &step) < 0) return NULL; Py_ssize_t slicelength = PySlice_AdjustIndices(vec.len, &start, &stop, step); VEC res = vec_alloc(slicelength); if (VEC_IS_ERROR(res)) return NULL; res.len = slicelength; Py_ssize_t j = start; for (Py_ssize_t i = 0; i < slicelength; i++) { res.items[i] = vec.items[j]; j += step; } return FUNC(Box)(res); } else { PyErr_Format(PyExc_TypeError, "vec indices must be integers or slices, not %.100s", item->ob_type->tp_name); return NULL; } } static int vec_ass_item(PyObject *self, Py_ssize_t i, PyObject *o) { ITEM_C_TYPE x = UNBOX_ITEM(o); if (IS_UNBOX_ERROR(x)) return -1; VEC v = ((VEC_OBJECT *)self)->vec; if ((size_t)i < (size_t)v.len) { v.items[i] = x; return 0; } else if ((size_t)i + (size_t)v.len < (size_t)v.len) { v.items[i + v.len] = x; return 0; } else { PyErr_SetString(PyExc_IndexError, "index out of range"); return -1; } } static int vec_contains(PyObject *self, PyObject *value) { ITEM_C_TYPE x = UNBOX_ITEM(value); if (unlikely(IS_UNBOX_ERROR(x))) { if (PyErr_Occurred()) PyErr_Clear(); // Fall back to boxed comparison (e.g. 2.0 == 2) VEC v = ((VEC_OBJECT *)self)->vec; for (Py_ssize_t i = 0; i < v.len; i++) { PyObject *boxed = BOX_ITEM(v.items[i]); if (boxed == NULL) return -1; int cmp = PyObject_RichCompareBool(boxed, value, Py_EQ); Py_DECREF(boxed); if (cmp != 0) return cmp; // 1 if equal, -1 on error } return 0; } VEC v = ((VEC_OBJECT *)self)->vec; for (Py_ssize_t i = 0; i < v.len; i++) { if (v.items[i] == x) return 1; } return 0; } static Py_ssize_t vec_length(PyObject *o) { return ((VEC_OBJECT *)o)->vec.len; } static PyObject *vec_richcompare(PyObject *self, PyObject *other, int op) { int cmp = 1; PyObject *res; if (op == Py_EQ || op == Py_NE) { if (other->ob_type != &VEC_TYPE) cmp = 0; else { VEC x = ((VEC_OBJECT *)self)->vec; VEC y = ((VEC_OBJECT *)other)->vec; if (x.len != y.len) { cmp = 0; } else { for (Py_ssize_t i = 0; i < x.len; i++) { if (x.items[i] != y.items[i]) { cmp = 0; break; } } } } if (op == Py_NE) cmp = cmp ^ 1; res = cmp ? Py_True : Py_False; } else res = Py_NotImplemented; Py_INCREF(res); return res; } // Append item to 'vec', stealing 'vec'. Return 'vec' with item appended. VEC FUNC(Append)(VEC vec, ITEM_C_TYPE x) { if (vec.items && vec.len < VEC_CAP(vec)) { vec.items[vec.len] = x; vec.len++; return vec; } else { Py_ssize_t cap = vec.items ? VEC_CAP(vec) : 0; Py_ssize_t new_size = Vec_GrowCapacity(cap); VEC new = vec_alloc(new_size); if (VEC_IS_ERROR(new)) { // The input v is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(vec); return vec_error(); } new.len = vec.len + 1; if (vec.len > 0) memcpy(new.items, vec.items, sizeof(ITEM_C_TYPE) * vec.len); new.items[vec.len] = x; VEC_DECREF(vec); return new; } } inline static int vec_memory_overlaps(const void *p1, Py_ssize_t len1, const void *p2, Py_ssize_t len2) { if (len1 <= 0 || len2 <= 0) return 0; uintptr_t a = (uintptr_t)p1, b = (uintptr_t)p2; if (a <= b) return b - a < (uintptr_t)len1; return a - b < (uintptr_t)len2; } // Extend 'dst' by appending 'n' items from 'items', stealing 'dst'. // Caller guarantees n > 0 and that 'items' remains valid for the call. // If force_alloc is true, always allocate a new buffer even when dst has capacity. inline static VEC vec_extend_items( VEC dst, const ITEM_C_TYPE *items, Py_ssize_t n, int force_alloc ) { if (unlikely(n > PY_SSIZE_T_MAX - dst.len)) { PyErr_NoMemory(); VEC_DECREF(dst); return vec_error(); } Py_ssize_t new_len = dst.len + n; Py_ssize_t cap = dst.items ? VEC_CAP(dst) : 0; if (!force_alloc && new_len <= cap) { memcpy(dst.items + dst.len, items, sizeof(ITEM_C_TYPE) * n); dst.len = new_len; return dst; } Py_ssize_t new_cap = Vec_GrowCapacityTo(cap, new_len); VEC new = vec_alloc(new_cap); if (VEC_IS_ERROR(new)) { VEC_DECREF(dst); return vec_error(); } if (dst.len > 0) memcpy(new.items, dst.items, sizeof(ITEM_C_TYPE) * dst.len); memcpy(new.items + dst.len, items, sizeof(ITEM_C_TYPE) * n); new.len = new_len; VEC_DECREF(dst); return new; } // Extend 'vec' with items from 'iterable', stealing 'vec'. // Return extended 'vec', or error vec on failure. VEC FUNC(Extend)(VEC vec, PyObject *iterable) { if (Py_TYPE(iterable) == &VEC_TYPE) { return FUNC(ExtendVec)(vec, ((VEC_OBJECT *)iterable)->vec); } if (ITEM_TYPE_MAGIC == VEC_ITEM_TYPE_U8 && PyBytes_CheckExact(iterable)) { Py_ssize_t n = PyBytes_GET_SIZE(iterable); if (n > 0) return vec_extend_items(vec, (const ITEM_C_TYPE *)PyBytes_AS_STRING(iterable), n, 0); return vec; } #ifdef BUFFER_FORMAT_CHAR_OK Py_buffer view; int buf_ok = vec_get_buffer(iterable, &view); if (buf_ok < 0) { VEC_DECREF(vec); return vec_error(); } if (buf_ok) { Py_ssize_t n = view.len / (Py_ssize_t)sizeof(ITEM_C_TYPE); if (n > 0) { Py_ssize_t dst_bytes = n * (Py_ssize_t)sizeof(ITEM_C_TYPE); int force_alloc = vec.items != NULL && n <= VEC_CAP(vec) - vec.len && vec_memory_overlaps(view.buf, view.len, vec.items + vec.len, dst_bytes); vec = vec_extend_items(vec, (const ITEM_C_TYPE *)view.buf, n, force_alloc); } PyBuffer_Release(&view); return vec; } #endif PyObject *iter = PyObject_GetIter(iterable); if (iter == NULL) { VEC_DECREF(vec); return vec_error(); } PyObject *item; while ((item = PyIter_Next(iter)) != NULL) { ITEM_C_TYPE x = UNBOX_ITEM(item); Py_DECREF(item); if (IS_UNBOX_ERROR(x)) { Py_DECREF(iter); VEC_DECREF(vec); return vec_error(); } vec = FUNC(Append)(vec, x); if (VEC_IS_ERROR(vec)) { Py_DECREF(iter); return vec_error(); } } Py_DECREF(iter); if (PyErr_Occurred()) { VEC_DECREF(vec); return vec_error(); } return vec; } // Extend 'dst' with items from 'src' vec, stealing 'dst', borrowing 'src'. // Return extended vec, or error vec on failure. VEC FUNC(ExtendVec)(VEC dst, VEC src) { if (src.len == 0) return dst; return vec_extend_items(dst, src.items, src.len, dst.items == src.items); } // Convert vec to list, stealing 'v'. PyObject *FUNC(ToList)(VEC v) { Py_ssize_t n = v.len; PyObject *list = PyList_New(n); if (list == NULL) { VEC_DECREF(v); return NULL; } for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = BOX_ITEM(v.items[i]); if (item == NULL) { Py_DECREF(list); VEC_DECREF(v); return NULL; } PyList_SET_ITEM(list, i, item); } VEC_DECREF(v); return list; } // Convert vec to tuple, stealing 'v'. PyObject *FUNC(ToTuple)(VEC v) { Py_ssize_t n = v.len; PyObject *tuple = PyTuple_New(n); if (tuple == NULL) { VEC_DECREF(v); return NULL; } for (Py_ssize_t i = 0; i < n; i++) { PyObject *item = BOX_ITEM(v.items[i]); if (item == NULL) { Py_DECREF(tuple); VEC_DECREF(v); return NULL; } PyTuple_SET_ITEM(tuple, i, item); } VEC_DECREF(v); return tuple; } // Remove item from 'vec', stealing 'vec'. Return 'vec' with item removed. VEC FUNC(Remove)(VEC v, ITEM_C_TYPE x) { for (Py_ssize_t i = 0; i < v.len; i++) { if (v.items[i] == x) { for (; i < v.len - 1; i++) { v.items[i] = v.items[i + 1]; } v.len--; // Return the stolen reference without INCREF return v; } } PyErr_SetString(PyExc_ValueError, "vec.remove(x): x not in vec"); // The input v is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(v); return vec_error(); } // Pop item from 'vec', stealing 'vec'. Return struct with modified 'vec' and the popped item. NAME(PopResult) FUNC(Pop)(VEC v, Py_ssize_t index) { NAME(PopResult) result; if (index < 0) index += v.len; if (index < 0 || index >= v.len) { PyErr_SetString(PyExc_IndexError, "index out of range"); // The input v is being consumed/stolen by this function, so on error // we must decref it to avoid leaking the buffer. VEC_DECREF(v); result.f0 = vec_error(); result.f1 = 0; return result; } result.f1 = v.items[index]; for (Py_ssize_t i = index; i < v.len - 1; i++) { v.items[i] = v.items[i + 1]; } v.len--; // Return the stolen reference without INCREF result.f0 = v; return result; } static PyMappingMethods vec_mapping_methods = { .mp_length = vec_length, .mp_subscript = vec_subscript, }; #ifdef BUFFER_FORMAT static int vec_getbuffer(VEC_OBJECT *self, Py_buffer *view, int flags) { if (view == NULL) { PyErr_SetString(PyExc_BufferError, "vec_getbuffer: view==NULL argument is obsolete"); return -1; } if ((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) { PyErr_SetString(PyExc_BufferError, "Object is not writable"); view->obj = NULL; return -1; } view->obj = (PyObject *)self; Py_INCREF(self); view->buf = (void *)self->vec.items; view->len = self->vec.len * (Py_ssize_t)sizeof(ITEM_C_TYPE); view->readonly = 1; view->itemsize = sizeof(ITEM_C_TYPE); view->format = NULL; if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) view->format = BUFFER_FORMAT; view->ndim = 1; view->shape = NULL; if ((flags & PyBUF_ND) == PyBUF_ND) view->shape = &self->vec.len; view->strides = NULL; if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) view->strides = &view->itemsize; view->suboffsets = NULL; view->internal = NULL; return 0; } static PyBufferProcs vec_buffer_procs = { .bf_getbuffer = (getbufferproc)vec_getbuffer, }; #endif static PySequenceMethods vec_sequence_methods = { .sq_item = vec_get_item, .sq_ass_item = vec_ass_item, .sq_contains = vec_contains, }; static PyMethodDef vec_methods[] = { {NULL, NULL, 0, NULL}, /* Sentinel */ }; // Iterator type for specialized vec types typedef struct { PyObject_HEAD VEC vec; // Unboxed vec (keeps buffer alive via items reference) Py_ssize_t index; // Current iteration index } NAME(IterObject); PyTypeObject NAME(IterType); static PyObject *vec_iter(PyObject *self) { NAME(IterObject) *it = PyObject_New(NAME(IterObject), &NAME(IterType)); if (it == NULL) return NULL; it->vec = ((VEC_OBJECT *)self)->vec; VEC_INCREF(it->vec); it->index = 0; return (PyObject *)it; } static void vec_iter_dealloc(NAME(IterObject) *self) { VEC_DECREF(self->vec); PyObject_Del(self); } static PyObject *vec_iter_next(NAME(IterObject) *self) { if (self->vec.items == NULL) return NULL; if (self->index < self->vec.len) { PyObject *item = BOX_ITEM(self->vec.items[self->index]); if (item == NULL) return NULL; self->index++; return item; } VEC_DECREF(self->vec); self->vec.items = NULL; return NULL; // StopIteration } static PyObject *vec_iter_len(NAME(IterObject) *self, PyObject *Py_UNUSED(ignored)) { if (self->vec.items == NULL) return PyLong_FromSsize_t(0); Py_ssize_t remaining = self->vec.len - self->index; if (remaining < 0) remaining = 0; return PyLong_FromSsize_t(remaining); } static PyMethodDef vec_iter_methods[] = { {"__length_hint__", (PyCFunction)vec_iter_len, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL}, }; PyTypeObject NAME(IterType) = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec_iterator[" ITEM_TYPE_STR "]", .tp_basicsize = sizeof(NAME(IterObject)), .tp_itemsize = 0, .tp_flags = Py_TPFLAGS_DEFAULT, .tp_dealloc = (destructor)vec_iter_dealloc, .tp_iter = PyObject_SelfIter, .tp_iternext = (iternextfunc)vec_iter_next, .tp_methods = vec_iter_methods, }; PyTypeObject BUF_TYPE = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vecbuf[" ITEM_TYPE_STR "]", .tp_doc = "Internal data buffer used by vec objects", .tp_basicsize = sizeof(BUF_OBJECT) - sizeof(ITEM_C_TYPE), .tp_itemsize = sizeof(ITEM_C_TYPE), .tp_flags = Py_TPFLAGS_DEFAULT, //.tp_new = ?? .tp_free = PyObject_Del, }; PyTypeObject VEC_TYPE = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "vec[" ITEM_TYPE_STR "]", .tp_doc = "Mutable sequence-like container optimized for compilation with mypyc", .tp_basicsize = sizeof(VEC_OBJECT), .tp_itemsize = 0, .tp_base = &VecType, // Inherit from base vec type for isinstance() support .tp_flags = Py_TPFLAGS_DEFAULT, .tp_new = vec_new, //.tp_free = PyObject_Del, .tp_dealloc = (destructor)vec_dealloc, .tp_repr = (reprfunc)vec_repr, .tp_iter = vec_iter, .tp_as_sequence = &vec_sequence_methods, .tp_as_mapping = &vec_mapping_methods, #ifdef BUFFER_FORMAT .tp_as_buffer = &vec_buffer_procs, #endif .tp_richcompare = vec_richcompare, .tp_methods = vec_methods, }; NAME(API) FEATURES = { &VEC_TYPE, &BUF_TYPE, FUNC(New), FUNC(Box), FUNC(Unbox), FUNC(ConvertFromNested), FUNC(Append), FUNC(Pop), FUNC(Remove), FUNC(Slice), FUNC(FromIterable), FUNC(Extend), FUNC(ExtendVec), FUNC(ToList), FUNC(ToTuple), }; #undef VEC_BUF #undef VEC_CAP #undef VEC_INCREF #undef VEC_DECREF ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vec_u8.c0000644000175100017510000000105415200142331014637 0ustar00runnerrunner#define VEC VecU8 #define VEC_TYPE VecU8Type #define VEC_OBJECT VecU8Object #define BUF_OBJECT VecU8BufObject #define BUF_TYPE VecU8BufType #define NAME(suffix) VecU8##suffix #define FUNC(suffix) VecU8_##suffix #define ITEM_TYPE_STR "u8" #define ITEM_TYPE_MAGIC VEC_ITEM_TYPE_U8 #define ITEM_C_TYPE uint8_t #define FEATURES Vec_U8API #define BOX_ITEM VecU8_BoxItem #define UNBOX_ITEM VecU8_UnboxItem #define IS_UNBOX_ERROR VecU8_IsUnboxError #define BUFFER_FORMAT_CHAR_OK(c) ((c) == 'B' || (c) == 'c') #define BUFFER_FORMAT "B" #include "vec_template.c" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs/vecs_internal.h0000644000175100017510000000033415200142331016307 0ustar00runnerrunner#ifndef VECS_INTERNAL_H_INCL #define VECS_INTERNAL_H_INCL // Internal header for mypyc/lib-rt/vecs implementation #include // The base vec type extern PyTypeObject VecType; #endif // VECS_INTERNAL_H_INCL ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs_extra_ops.c0000644000175100017510000000036215200142331015533 0ustar00runnerrunner// Primitives related to librt.vecs that get linked statically // with compiled modules, instead of being called via a capsule. #include "vecs_extra_ops.h" // All operations are currently implemented as inline functions in vecs_extra_ops.h ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1778435289.0 librt-0.11.0/vecs_extra_ops.h0000644000175100017510000000071215200142331015537 0ustar00runnerrunner#ifndef VECS_EXTRA_OPS_H #define VECS_EXTRA_OPS_H #include "vecs/librt_vecs_api.h" // Check if obj is an instance of vec (any vec type) static inline int CPyVec_Check(PyObject *obj) { return PyObject_TypeCheck(obj, VecApi->get_vec_type()); } static inline PyObject *CPyVecU8_ToBytes(VecU8 v) { if (v.len == 0) { return PyBytes_FromStringAndSize(NULL, 0); } return PyBytes_FromStringAndSize((const char *)v.items, v.len); } #endif