/* -*- c -*- */ #define PY_SSIZE_T_CLEAN #include #include #define NPY_NO_DEPRECATED_API NPY_API_VERSION #ifndef _MULTIARRAYMODULE #define _MULTIARRAYMODULE #endif #include "numpy/arrayobject.h" #include "numpy/npy_math.h" #include "numpy/halffloat.h" #include "numpy/arrayscalars.h" #include "npy_pycompat.h" #include "arraytypes.h" #include "npy_config.h" #include "mapping.h" #include "ctors.h" #include "dtypemeta.h" #include "usertypes.h" #include "number.h" #include "numpyos.h" #include "can_cast_table.h" #include "common.h" #include "conversion_utils.h" #include "flagsobject.h" #include "scalartypes.h" #include "_datetime.h" #include "datetime_strings.h" #include "alloc.h" #include "npy_import.h" #include "dragon4.h" #include "npy_longdouble.h" #include "npy_buffer.h" #include "npy_static_data.h" #include "multiarraymodule.h" #include "array_api_standard.h" #include #include "binop_override.h" /* * used for allocating a single scalar, so use the default numpy * memory allocators instead of the (maybe) user overrides */ NPY_NO_EXPORT void * npy_alloc_cache_zero(size_t nmemb, size_t size); NPY_NO_EXPORT void npy_free_cache(void * p, npy_uintp sz); NPY_NO_EXPORT PyBoolScalarObject _PyArrayScalar_BoolValues[] = { {PyObject_HEAD_INIT(&PyBoolArrType_Type) 0}, {PyObject_HEAD_INIT(&PyBoolArrType_Type) 1}, }; /* TimeInteger is deleted, but still here to fill the API slot */ NPY_NO_EXPORT PyTypeObject PyTimeIntegerArrType_Type; /* * Inheritance is established later when tp_bases is set (or tp_base for * single inheritance) */ /**begin repeat * #name = number, integer, signedinteger, unsignedinteger, inexact, * floating, complexfloating, flexible, character# * #NAME = Number, Integer, SignedInteger, UnsignedInteger, Inexact, * Floating, ComplexFloating, Flexible, Character# */ NPY_NO_EXPORT PyTypeObject Py@NAME@ArrType_Type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "numpy.@name@", .tp_basicsize = sizeof(PyObject), }; /**end repeat**/ static PyObject * gentype_alloc(PyTypeObject *type, Py_ssize_t nitems) { PyObject *obj; const size_t size = _PyObject_VAR_SIZE(type, nitems + 1); obj = (PyObject *)PyObject_Malloc(size); if (obj == NULL) { PyErr_NoMemory(); return NULL; } /* * If we don't need to zero memory, we could use * PyObject_{New, NewVar} for this whole function. */ memset(obj, 0, size); if (type->tp_itemsize == 0) { PyObject_Init(obj, type); } else { (void) PyObject_InitVar((PyVarObject *)obj, type, nitems); } return obj; } static void gentype_dealloc(PyObject *v) { Py_TYPE(v)->tp_free(v); } static void gentype_free(PyObject *v) { /* * have an explicit tp_free to enforce inheritance from it. * PyObject_Free is also the tp_free of PyBaseObject so python does not * COPYSLOT it, instead it takes the next parent PyInt which has a * different allocator */ PyObject_Free(v); } static PyObject * gentype_generic_method(PyObject *self, PyObject *args, PyObject *kwds, char *str) { PyObject *arr, *meth, *ret; arr = PyArray_FromScalar(self, NULL); if (arr == NULL) { return NULL; } meth = PyObject_GetAttrString(arr, str); if (meth == NULL) { Py_DECREF(arr); return NULL; } if (kwds == NULL) { ret = PyObject_CallObject(meth, args); } else { ret = PyObject_Call(meth, args, kwds); } Py_DECREF(meth); Py_DECREF(arr); if (ret && PyArray_Check(ret)) { return PyArray_Return((PyArrayObject *)ret); } else { return ret; } } /* * Helper function to deal with binary operator deferral. Must be passed a * valid self (a generic scalar) and an other item. * May fill self_item and/or other_arr (but not both) with non-NULL values. * * Why this dance? When the other object is a exactly Python scalar something * awkward happens historically in NumPy. * NumPy doesn't define a result, but the ufunc would cast to `astype(object)` * which is the same as `scalar.item()`. And that operation converts e.g. * float32 or float64 to Python floats. * It then retries. And because it is a builtin type now the operation may * succeed. * * This retrying pass only makes sense if the other object is a Python * scalar (otherwise we fill in `other_arr` which can be used to call the * ufunc). * Additionally, if `self.item()` has the same type as `self` we would end up * in an infinite recursion. * * So the result of this function means the following: * - < 0 error return. * - self_op is filled in: Retry the Python operator. * - other_op is filled in: Use the array operator (goes into ufuncs) * (This may be the original generic if it is one.) * - neither is filled in: Return NotImplemented. * * It is not possible for both to be filled. If `other` is also a generics, * it is returned. */ static inline int find_binary_operation_path( PyObject *self, PyObject *other, PyObject **self_op, PyObject **other_op) { *other_op = NULL; *self_op = NULL; if (PyArray_IsScalar(other, Generic) || PyLong_CheckExact(other) || PyFloat_CheckExact(other) || PyComplex_CheckExact(other) || PyBool_Check(other) || PyArray_Check(other)) { /* * The other operand is ready for the operation already. Must pass on * on float/long/complex mainly for weak promotion (NEP 50). */ *other_op = Py_NewRef(other); return 0; } /* * If other has __array_ufunc__ always use ufunc. If array-ufunc was None * we already deferred. And any custom object with array-ufunc cannot call * our ufuncs without preventing recursion. * It may be nice to avoid double lookup in `BINOP_GIVE_UP_IF_NEEDED`. */ PyObject *attr; if (PyArray_LookupSpecial(other, npy_interned_str.array_ufunc, &attr) < 0) { PyErr_Clear(); /* TODO[gh-14801]: propagate crashes during attribute access? */ } else if (attr != NULL) { Py_DECREF(attr); *other_op = Py_NewRef(other); return 0; } /* * Now check `other`. We want to know whether it is an object scalar * and the easiest way is by converting to an array here. */ int was_scalar; PyArrayObject *arr = (PyArrayObject *)PyArray_FromAny_int( other, NULL, NULL, 0, 0, 0, NULL, &was_scalar); if (arr == NULL) { return -1; } if (!was_scalar || PyArray_DESCR(arr)->type_num != NPY_OBJECT) { /* * The array is OK for usage and we can simply forward it. There * is a theoretical subtlety here: If the other object implements * `__array_wrap__`, we may ignore that. However, this only matters * if the other object has the identical `__array_priority__` and * additionally already deferred back to us. * (`obj + scalar` and `scalar + obj` are not symmetric.) * * NOTE: Future NumPy may need to distinguish scalars here, one option * could be marking the array. */ *other_op = (PyObject *)arr; return 0; } Py_DECREF(arr); /* * If we are here, we need to operate on Python scalars. In general * that would just fails since NumPy doesn't know the other object! * * However, NumPy (historically) made this often work magically because * ufuncs for object dtype end up casting to object with `.item()`. This in * turn often returns a Python type (e.g. float for float32, float64)! * Retrying then succeeds. So if (and only if) `self.item()` returns a new * type, we can safely attempt the operation (again) with that. */ PyObject *self_item = PyObject_CallMethodNoArgs(self, npy_interned_str.item); if (self_item == NULL) { return -1; } if (Py_TYPE(self_item) != Py_TYPE(self)) { /* self_item can be used to retry the operation */ *self_op = self_item; return 0; } /* The operation can't work and we will return NotImplemented */ Py_DECREF(self_item); return 0; } /* * These are defined below as they require special handling, we still define * a _gen version here. `power` is special as it has three arguments. */ static PyObject * gentype_add(PyObject *m1, PyObject *m2); static PyObject * gentype_multiply(PyObject *m1, PyObject *m2); /**begin repeat * * #name = add, multiply, subtract, remainder, divmod, * lshift, rshift, and, xor, or, floor_divide, true_divide# * #ufunc = add, multiply, subtract, remainder, divmod, * left_shift, right_shift, bitwise_and, bitwise_xor, bitwise_or, * floor_divide, true_divide# * #func = Add, Multiply, Subtract, Remainder, Divmod, * Lshift, Rshift, And, Xor, Or, FloorDivide, TrueDivide# * #suff = _gen, _gen,,,,,,,,,,# */ /* NOTE: We suffix the name for functions requiring special handling first. */ static PyObject * gentype_@name@@suff@(PyObject *m1, PyObject *m2) { BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_@name@, gentype_@name@); PyObject *self = NULL; PyObject *other = NULL; PyObject *self_op, *other_op; if (!PyArray_IsScalar(m2, Generic)) { self = m1; other = m2; } else { self = m2; other = m1; } if (find_binary_operation_path(self, other, &self_op, &other_op) < 0) { return NULL; } if (self_op != NULL) { PyObject *res; if (self == m1) { res = PyNumber_@func@(self_op, m2); } else { res = PyNumber_@func@(m1, self_op); } Py_DECREF(self_op); return res; } else if (other_op != NULL) { /* Call the corresponding ufunc (with the array) */ PyObject *res; if (self == m1) { res = PyArray_GenericBinaryFunction(m1, other_op, n_ops.@ufunc@); } else { res = PyArray_GenericBinaryFunction(other_op, m2, n_ops.@ufunc@); } Py_DECREF(other_op); return res; } else { assert(other_op == NULL); Py_RETURN_NOTIMPLEMENTED; } } /**end repeat**/ /* * The following operators use the above, but require specialization. */ static PyObject * gentype_add(PyObject *m1, PyObject *m2) { /* special case str.__radd__, which should not call array_add */ if (PyBytes_Check(m1) || PyUnicode_Check(m1)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } return gentype_add_gen(m1, m2); } /* Get a nested slot, or NULL if absent (for multiply implementation) */ #define GET_NESTED_SLOT(type, group, slot) \ ((type)->group == NULL ? NULL : (type)->group->slot) static PyObject * gentype_multiply(PyObject *m1, PyObject *m2) { /* * If the other object supports sequence repeat and not number multiply * we fall back on the python builtin to invoke the sequence repeat, rather * than promoting both arguments to ndarray. * This covers a list repeat by numpy scalars. * A python defined class will always only have the nb_multiply slot and * some classes may have neither defined. For the latter we want need * to give the normal case a chance to convert the object to ndarray. * Probably no class has both defined, but if they do, prefer number. */ if (!PyArray_IsScalar(m1, Generic) && GET_NESTED_SLOT(Py_TYPE(m1), tp_as_sequence, sq_repeat) != NULL && GET_NESTED_SLOT(Py_TYPE(m1), tp_as_number, nb_multiply) == NULL) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } if (!PyArray_IsScalar(m2, Generic) && GET_NESTED_SLOT(Py_TYPE(m2), tp_as_sequence, sq_repeat) != NULL && GET_NESTED_SLOT(Py_TYPE(m2), tp_as_number, nb_multiply) == NULL) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } return gentype_multiply_gen(m1, m2); } /* * NOTE: The three argument nature of power requires code duplication here. */ static PyObject * gentype_power(PyObject *m1, PyObject *m2, PyObject *modulo) { if (modulo != Py_None) { /* modular exponentiation is not implemented (gh-8804) */ Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } BINOP_GIVE_UP_IF_NEEDED(m1, m2, nb_power, gentype_power); PyObject *self = NULL; PyObject *other = NULL; PyObject *self_op, *other_op; if (!PyArray_IsScalar(m2, Generic)) { self = m1; other = m2; } else { self = m2; other = m1; } if (find_binary_operation_path(self, other, &self_op, &other_op) < 0) { return NULL; } if (self_op != NULL) { PyObject *res; if (self == m1) { res = PyNumber_Power(self_op, m2, Py_None); } else { res = PyNumber_Power(m1, self_op, Py_None); } Py_DECREF(self_op); return res; } else if (other_op != NULL) { /* Call the corresponding ufunc (with the array) * NOTE: As of NumPy 2.0 there are inconsistencies in array_power * calling it would fail a (niche) test because an array is * returned in one of the fast-paths. * (once NumPy propagates 0-D arrays, this is irrelevant) */ PyObject *res; if (self == m1) { res = PyArray_GenericBinaryFunction(m1, other_op, n_ops.power); } else { res = PyArray_GenericBinaryFunction(other_op, m2, n_ops.power); } Py_DECREF(other_op); return res; } else { assert(other_op == NULL); Py_RETURN_NOTIMPLEMENTED; } } /**begin repeat * #TYPE = BYTE, UBYTE, SHORT, USHORT, INT, UINT, * LONG, ULONG, LONGLONG, ULONGLONG# * #type = npy_byte, npy_ubyte, npy_short, npy_ushort, npy_int, npy_uint, * npy_long, npy_ulong, npy_longlong, npy_ulonglong# * #c = hh, uhh, h, uh,, u, l, ul, ll, ull# * #Name = Byte, UByte, Short, UShort, Int, UInt, * Long, ULong, LongLong, ULongLong# * #convert = Long*8, LongLong*2# */ static PyObject * @type@_bit_count(PyObject *self, PyObject *NPY_UNUSED(args)) { @type@ scalar = PyArrayScalar_VAL(self, @Name@); uint8_t count = npy_popcount@c@(scalar); PyObject *result = PyLong_From@convert@(count); return result; } /**end repeat**/ /**begin repeat * * #name = positive, negative, absolute, invert, int, float# */ static PyObject * gentype_@name@(PyObject *m1) { PyObject *arr, *ret; arr = PyArray_FromScalar(m1, NULL); if (arr == NULL) { return NULL; } ret = Py_TYPE(arr)->tp_as_number->nb_@name@(arr); Py_DECREF(arr); return ret; } /**end repeat**/ static int gentype_nonzero_number(PyObject *m1) { PyObject *arr; int ret; arr = PyArray_FromScalar(m1, NULL); if (arr == NULL) { return -1; } ret = Py_TYPE(arr)->tp_as_number->nb_bool(arr); Py_DECREF(arr); return ret; } static PyObject * genint_type_str(PyObject *self) { PyObject *item, *item_str; PyArray_Descr *dtype = PyArray_DescrFromTypeObject((PyObject *)Py_TYPE(self)); void *val = scalar_value(self, dtype); switch (dtype->type_num) { case NPY_BYTE: item = PyLong_FromLong(*(npy_byte *)val); break; case NPY_UBYTE: item = PyLong_FromUnsignedLong(*(npy_ubyte *)val); break; case NPY_SHORT: item = PyLong_FromLong(*(npy_short *)val); break; case NPY_USHORT: item = PyLong_FromUnsignedLong(*(npy_ushort *)val); break; case NPY_INT: item = PyLong_FromLong(*(npy_int *)val); break; case NPY_UINT: item = PyLong_FromUnsignedLong(*(npy_uint *)val); break; case NPY_LONG: item = PyLong_FromLong(*(npy_long *)val); break; case NPY_ULONG: item = PyLong_FromUnsignedLong(*(npy_ulong *)val); break; case NPY_LONGLONG: item = PyLong_FromLongLong(*(npy_longlong *)val); break; case NPY_ULONGLONG: item = PyLong_FromUnsignedLongLong(*(npy_ulonglong *)val); break; default: item = gentype_generic_method(self, NULL, NULL, "item"); break; } Py_DECREF(dtype); if (item == NULL) { return NULL; } item_str = PyObject_Str(item); Py_DECREF(item); return item_str; } static PyObject * genint_type_repr(PyObject *self) { PyObject *value_string = genint_type_str(self); if (value_string == NULL) { return NULL; } int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode <= 125) { return value_string; } int num = _typenum_fromtypeobj((PyObject *)Py_TYPE(self), 0); PyObject *repr; if (num == NPY_NOTYPE) { /* Not a builtin scalar (presumably), just use the name */ repr = PyUnicode_FromFormat("%s(%S)", Py_TYPE(self)->tp_name, value_string); Py_DECREF(value_string); return repr; } PyArray_Descr *descr = PyArray_DescrFromType(num); /* cannot fail */ int bitsize = descr->elsize * 8; Py_DECREF(descr); if (PyTypeNum_ISUNSIGNED(num)) { repr = PyUnicode_FromFormat("np.uint%d(%S)", bitsize, value_string); } else { repr = PyUnicode_FromFormat("np.int%d(%S)", bitsize, value_string); } Py_DECREF(value_string); return repr; } static PyObject * genbool_type_str(PyObject *self) { return PyUnicode_FromString( ((PyBoolScalarObject *)self)->obval ? "True" : "False"); } static PyObject * genbool_type_repr(PyObject *self) { int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode <= 125) { return genbool_type_str(self); } return PyUnicode_FromString( ((PyBoolScalarObject *)self)->obval ? "np.True_" : "np.False_"); } /* * The __format__ method for PEP 3101. */ static PyObject * gentype_format(PyObject *self, PyObject *args) { PyObject *format_spec; PyObject *obj, *ret; if (!PyArg_ParseTuple(args, "U:__format__", &format_spec)) { return NULL; } /* * Convert to an appropriate Python type and call its format. * TODO: For some types, like long double, this isn't right, * because it throws away precision. */ if (Py_TYPE(self) == &PyBoolArrType_Type) { obj = PyBool_FromLong(PyArrayScalar_VAL(self, Bool)); } else if (PyArray_IsScalar(self, Integer) && !PyArray_IsScalar(self, Timedelta)) { obj = Py_TYPE(self)->tp_as_number->nb_int(self); } else if (PyArray_IsScalar(self, Floating)) { obj = Py_TYPE(self)->tp_as_number->nb_float(self); } else if (PyArray_IsScalar(self, ComplexFloating)) { double val[2]; PyArray_Descr *dtype = PyArray_DescrFromScalar(self); if (dtype == NULL) { return NULL; } if (PyArray_CastScalarDirect(self, dtype, &val[0], NPY_CDOUBLE) < 0) { Py_DECREF(dtype); return NULL; } obj = PyComplex_FromDoubles(val[0], val[1]); Py_DECREF(dtype); } else { obj = PyObject_Str(self); } if (obj == NULL) { return NULL; } ret = PyObject_Format(obj, format_spec); Py_DECREF(obj); return ret; } #ifdef FORCE_NO_LONG_DOUBLE_FORMATTING #undef NPY_LONGDOUBLE_FMT #define NPY_LONGDOUBLE_FMT NPY_DOUBLE_FMT #endif /**begin repeat * #name = half, float, double, longdouble# * #Name = Half, Float, Double, LongDouble# * #NAME = HALF, FLOAT, DOUBLE, LONGDOUBLE# * #type = npy_half, npy_float, npy_double, npy_longdouble# * #suff = h, f, d, l# */ NPY_NO_EXPORT PyObject * format_@name@(@type@ val, npy_bool scientific, int precision, int sign, TrimMode trim, int pad_left, int pad_right, int exp_digits) { if (scientific) { return Dragon4_Scientific_@Name@(&val, DigitMode_Unique, precision, -1, sign, trim, pad_left, exp_digits); } else { return Dragon4_Positional_@Name@(&val, DigitMode_Unique, CutoffMode_TotalLength, precision, -1, sign, trim, pad_left, pad_right); } } /**end repeat**/ /* * Over-ride repr and str of array-scalar byte strings to remove NULL bytes and * then call the corresponding functions of PyBytes_Type to generate the string */ /**begin repeat * #form = repr, str# */ #define IS_@form@ static PyObject * stringtype_@form@(PyObject *self) { const npy_char *dptr, *ip; Py_ssize_t len; PyObject *new; PyObject *ret; ip = PyBytes_AS_STRING(self); len = PyBytes_GET_SIZE(self); for(dptr = ip + len - 1; len > 0 && *dptr == 0; len--, dptr--); new = PyBytes_FromStringAndSize(ip, len); if (new == NULL) { return NULL; } ret = PyBytes_Type.tp_@form@(new); Py_DECREF(new); #ifdef IS_repr if (ret == NULL) { return NULL; } int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { Py_SETREF(ret, PyUnicode_FromFormat("np.bytes_(%S)", ret)); } #endif /* IS_repr */ return ret; } #undef IS_@form@ /**end repeat**/ /* * Over-ride repr and str of array-scalar strings to remove NULL code points and * then call the corresponding functions of PyUnicode_Type to generate the string */ /**begin repeat * #form = repr, str# */ #define IS_@form@ static PyObject * unicodetype_@form@(PyObject *self) { Py_UCS4 *dptr, *ip; Py_ssize_t len; PyObject *new; PyObject *ret; /* PyUnicode_READY is called by PyUnicode_GetLength */ len = PyUnicode_GetLength(self); ip = PyUnicode_AsUCS4Copy(self); if (ip == NULL) { return NULL; } for(dptr = ip + len - 1; len > 0 && *dptr == 0; len--, dptr--); new = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, ip, len); if (new == NULL) { PyMem_Free(ip); return NULL; } ret = PyUnicode_Type.tp_@form@(new); Py_DECREF(new); PyMem_Free(ip); #ifdef IS_repr if (ret == NULL) { return NULL; } int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { Py_SETREF(ret, PyUnicode_FromFormat("np.str_(%S)", ret)); } #endif /* IS_repr */ return ret; } #undef IS_@form@ /**end repeat**/ /* * Convert array of bytes to a string representation much like bytes.__repr__, * but convert all bytes (including ASCII) to the `\x00` notation with * uppercase hex codes (FF not ff). * * Largely copied from _Py_strhex_impl in CPython implementation */ static inline PyObject * _void_to_hex(const char* argbuf, const Py_ssize_t arglen, const char *schars, const char *bprefix, const char *echars) { PyObject *retval; int extrachars, slen; char *retbuf; Py_ssize_t i, j; char const *hexdigits = "0123456789ABCDEF"; extrachars = strlen(schars) + strlen(echars); slen = extrachars + arglen*(2 + strlen(bprefix)); if (arglen > (PY_SSIZE_T_MAX / 2) - extrachars) { return PyErr_NoMemory(); } retbuf = (char *)PyMem_Malloc(slen); if (!retbuf) { return PyErr_NoMemory(); } memcpy(retbuf, schars, strlen(schars)); j = strlen(schars); for (i = 0; i < arglen; i++) { unsigned char c; memcpy(&retbuf[j], bprefix, strlen(bprefix)); j += strlen(bprefix); c = (argbuf[i] >> 4) & 0xf; retbuf[j++] = hexdigits[c]; c = argbuf[i] & 0xf; retbuf[j++] = hexdigits[c]; } memcpy(&retbuf[j], echars, strlen(echars)); retval = PyUnicode_FromStringAndSize(retbuf, slen); PyMem_Free(retbuf); return retval; } static PyObject * _void_scalar_to_string(PyObject *obj, int repr) { if (npy_cache_import_runtime( "numpy._core.arrayprint", "_void_scalar_to_string", &npy_runtime_imports._void_scalar_to_string) == -1) { return NULL; } PyObject *is_repr = repr ? Py_True : Py_False; return PyObject_CallFunctionObjArgs( npy_runtime_imports._void_scalar_to_string, obj, is_repr, NULL); } static PyObject * voidtype_repr(PyObject *self) { PyVoidScalarObject *s = (PyVoidScalarObject*) self; if (PyDataType_HASFIELDS(s->descr)) { /* Python helper checks for the legacy mode printing */ return _void_scalar_to_string(self, 1); } int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { return _void_to_hex(s->obval, s->descr->elsize, "np.void(b'", "\\x", "')"); } else { return _void_to_hex(s->obval, s->descr->elsize, "void(b'", "\\x", "')"); } } static PyObject * voidtype_str(PyObject *self) { PyVoidScalarObject *s = (PyVoidScalarObject*) self; if (PyDataType_HASFIELDS(s->descr)) { return _void_scalar_to_string(self, 0); } return _void_to_hex(s->obval, s->descr->elsize, "b'", "\\x", "'"); } static PyObject * datetimetype_repr(PyObject *self) { PyDatetimeScalarObject *scal; npy_datetimestruct dts; PyObject *ret; char iso[NPY_DATETIME_MAX_ISO8601_STRLEN]; NPY_DATETIMEUNIT unit; if (!PyArray_IsScalar(self, Datetime)) { PyErr_SetString(PyExc_RuntimeError, "Called NumPy datetime repr on a non-datetime type"); return NULL; } scal = (PyDatetimeScalarObject *)self; if (NpyDatetime_ConvertDatetime64ToDatetimeStruct(&scal->obmeta, scal->obval, &dts) < 0) { return NULL; } unit = scal->obmeta.base; if (NpyDatetime_MakeISO8601Datetime(&dts, iso, sizeof(iso), 0, 0, unit, -1, NPY_SAFE_CASTING) < 0) { return NULL; } /* * For straight units or generic units, the unit will be deduced * from the string, so it's not necessary to specify it. */ if ((scal->obmeta.num == 1 && scal->obmeta.base != NPY_FR_h) || scal->obmeta.base == NPY_FR_GENERIC) { int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { ret = PyUnicode_FromFormat("np.datetime64('%s')", iso); } else { ret = PyUnicode_FromFormat("numpy.datetime64('%s')", iso); } } else { PyObject *meta = metastr_to_unicode(&scal->obmeta, 1); if (meta == NULL) { return NULL; } int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { ret = PyUnicode_FromFormat("np.datetime64('%s','%S')", iso, meta); } else { ret = PyUnicode_FromFormat("numpy.datetime64('%s','%S')", iso, meta); } Py_DECREF(meta); } return ret; } static PyObject * timedeltatype_repr(PyObject *self) { PyTimedeltaScalarObject *scal; PyObject *val, *ret; if (!PyArray_IsScalar(self, Timedelta)) { PyErr_SetString(PyExc_RuntimeError, "Called NumPy timedelta repr on a non-datetime type"); return NULL; } scal = (PyTimedeltaScalarObject *)self; /* The value */ if (scal->obval == NPY_DATETIME_NAT) { val = PyUnicode_FromString("'NaT'"); } else { /* Can't use "%lld" if HAVE_LONG_LONG is not defined */ #if defined(HAVE_LONG_LONG) val = PyUnicode_FromFormat("%lld", (long long)scal->obval); #else val = PyUnicode_FromFormat("%ld", (long)scal->obval); #endif } if (val == NULL) { return NULL; } /* The metadata unit */ if (scal->obmeta.base == NPY_FR_GENERIC) { int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { ret = PyUnicode_FromFormat("np.timedelta64(%S)", val); } else { ret = PyUnicode_FromFormat("numpy.timedelta64(%S)", val); } } else { PyObject *meta = metastr_to_unicode(&scal->obmeta, 1); if (meta == NULL) { Py_DECREF(val); return NULL; } int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { ret = PyUnicode_FromFormat("np.timedelta64(%S,'%S')", val, meta); } else { ret = PyUnicode_FromFormat("numpy.timedelta64(%S,'%S')", val, meta); } Py_DECREF(meta); } Py_DECREF(val); return ret; } static PyObject * datetimetype_str(PyObject *self) { PyDatetimeScalarObject *scal; npy_datetimestruct dts; char iso[NPY_DATETIME_MAX_ISO8601_STRLEN]; NPY_DATETIMEUNIT unit; if (!PyArray_IsScalar(self, Datetime)) { PyErr_SetString(PyExc_RuntimeError, "Called NumPy datetime str on a non-datetime type"); return NULL; } scal = (PyDatetimeScalarObject *)self; if (NpyDatetime_ConvertDatetime64ToDatetimeStruct(&scal->obmeta, scal->obval, &dts) < 0) { return NULL; } unit = scal->obmeta.base; if (NpyDatetime_MakeISO8601Datetime(&dts, iso, sizeof(iso), 0, 0, unit, -1, NPY_SAFE_CASTING) < 0) { return NULL; } return PyUnicode_FromString(iso); } static char *_datetime_verbose_strings[NPY_DATETIME_NUMUNITS] = { "years", "months", "weeks", "", "days", "hours", "minutes", "seconds", "milliseconds", "microseconds", "nanoseconds", "picoseconds", "femtoseconds", "attoseconds", "generic time units" }; static PyObject * timedeltatype_str(PyObject *self) { PyTimedeltaScalarObject *scal; PyObject *ret; char *basestr = "invalid"; if (!PyArray_IsScalar(self, Timedelta)) { PyErr_SetString(PyExc_RuntimeError, "Called NumPy timedelta str on a non-datetime type"); return NULL; } scal = (PyTimedeltaScalarObject *)self; if (scal->obmeta.base >= 0 && scal->obmeta.base < NPY_DATETIME_NUMUNITS) { basestr = _datetime_verbose_strings[scal->obmeta.base]; } else { PyErr_SetString(PyExc_RuntimeError, "NumPy datetime metadata is corrupted"); return NULL; } if (scal->obval == NPY_DATETIME_NAT) { ret = PyUnicode_FromString("NaT"); } else { /* * Can't use "%lld" if HAVE_LONG_LONG is not defined */ #if defined(HAVE_LONG_LONG) ret = PyUnicode_FromFormat("%lld %s", (long long)(scal->obval * scal->obmeta.num), basestr); #else ret = PyUnicode_FromFormat("%ld %s", (long)(scal->obval * scal->obmeta.num), basestr); #endif } return ret; } /* * float type str and repr * * These functions will return NULL if PyString creation fails. */ /* * *** BEGIN LEGACY PRINTING MODE CODE *** * * This code is legacy code needed to reproduce the printing behavior of * scalars in numpy 1.13. One day we hope to remove it. */ #define HALFPREC_REPR 5 #define HALFPREC_STR 5 #define FLOATPREC_REPR 8 #define FLOATPREC_STR 6 #define DOUBLEPREC_REPR 17 #define DOUBLEPREC_STR 12 #if NPY_SIZEOF_LONGDOUBLE == NPY_SIZEOF_DOUBLE #define LONGDOUBLEPREC_REPR DOUBLEPREC_REPR #define LONGDOUBLEPREC_STR DOUBLEPREC_STR #else /* More than probably needed on Intel FP */ #define LONGDOUBLEPREC_REPR 20 #define LONGDOUBLEPREC_STR 12 #endif /**begin repeat * #kind = str, repr# * #KIND = STR, REPR# */ /**begin repeat1 * #name = cfloat, cdouble, clongdouble# * #NAME = FLOAT, DOUBLE, LONGDOUBLE# * #TYPE = CFLOAT, CDOUBLE, CLONGDOUBLE# * #type = npy_cfloat, npy_cdouble, npy_clongdouble# * #t = f, , l# * #suff = f, d, l# */ #define _FMT1 "%%.%i" NPY_@NAME@_FMT #define _FMT2 "%%+.%i" NPY_@NAME@_FMT static PyObject* legacy_@name@_format@kind@(@type@ val) { /* XXX: Find a correct size here for format string */ char format[64], buf[100], *res; /* * Ideally, we should handle this nan/inf stuff in NumpyOS_ascii_format* */ if (npy_creal@t@(val) == 0.0 && npy_signbit(npy_creal@t@(val)) == 0) { PyOS_snprintf(format, sizeof(format), _FMT1, @NAME@PREC_@KIND@); res = NumPyOS_ascii_format@suff@(buf, sizeof(buf) - 1, format, npy_cimag@t@(val), 0); if (res == NULL) { PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); return NULL; } if (!npy_isfinite(npy_cimag@t@(val))) { strncat(buf, "*", sizeof(buf) - strlen(buf) - 1); } strncat(buf, "j", sizeof(buf) - strlen(buf) - 1); } else { char re[64], im[64]; if (npy_isfinite(npy_creal@t@(val))) { PyOS_snprintf(format, sizeof(format), _FMT1, @NAME@PREC_@KIND@); res = NumPyOS_ascii_format@suff@(re, sizeof(re), format, npy_creal@t@(val), 0); if (res == NULL) { PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); return NULL; } } else { if (npy_isnan(npy_creal@t@(val))) { strcpy(re, "nan"); } else if (npy_creal@t@(val) > 0){ strcpy(re, "inf"); } else { strcpy(re, "-inf"); } } if (npy_isfinite(npy_cimag@t@(val))) { PyOS_snprintf(format, sizeof(format), _FMT2, @NAME@PREC_@KIND@); res = NumPyOS_ascii_format@suff@(im, sizeof(im), format, npy_cimag@t@(val), 0); if (res == NULL) { PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); return NULL; } } else { if (npy_isnan(npy_cimag@t@(val))) { strcpy(im, "+nan"); } else if (npy_cimag@t@(val) > 0){ strcpy(im, "+inf"); } else { strcpy(im, "-inf"); } if (!npy_isfinite(npy_cimag@t@(val))) { strncat(im, "*", sizeof(im) - strlen(im) - 1); } } PyOS_snprintf(buf, sizeof(buf), "(%s%sj)", re, im); } return PyUnicode_FromString(buf); } #undef _FMT1 #undef _FMT2 /**end repeat1**/ /**begin repeat1 * #name = float, double, longdouble# * #Name = Float, Double, LongDouble# * #NAME = FLOAT, DOUBLE, LONGDOUBLE# * #suff = f, d, l# */ #define _FMT1 "%%.%i" NPY_@NAME@_FMT static PyObject * legacy_@name@_format@kind@(npy_@name@ val){ /* XXX: Find a correct size here for format string */ char format[64], buf[100], *res; size_t i, cnt; PyOS_snprintf(format, sizeof(format), _FMT1, @NAME@PREC_@KIND@); res = NumPyOS_ascii_format@suff@(buf, sizeof(buf), format, val, 0); if (res == NULL) { PyErr_SetString(PyExc_RuntimeError, "Error while formatting"); return NULL; } /* If nothing but digits after sign, append ".0" */ cnt = strlen(buf); for (i = (buf[0] == '-') ? 1 : 0; i < cnt; ++i) { if (!isdigit(Py_CHARMASK(buf[i]))) { break; } } if (i == cnt && sizeof(buf) >= cnt + 3) { strcpy(&buf[cnt],".0"); } return PyUnicode_FromString(buf); } #undef _FMT1 /**end repeat1**/ /**end repeat**/ /* * *** END LEGACY PRINTING MODE CODE *** */ /**begin repeat * #kind = str, repr# */ #define IS_@kind@ /**begin repeat1 * #name = float, double, longdouble# * #max_positional = 1.e6L, 1.e16L, 1.e16L# * #Name = Float, Double, LongDouble# * #NAME = FLOAT, DOUBLE, LONGDOUBLE# * #n = f, , l# * #repr_format = np.float32(%S), np.float64(%S), np.longdouble('%S')# * #crepr_imag_format = np.complex64(%Sj), np.complex128(%Sj), * np.clongdouble('%Sj')# * #crepr_format = np.complex64(%S%Sj), np.complex128(%S%Sj), * np.clongdouble('%S%Sj')# */ /* helper function choose scientific of fractional output, based on a cutoff */ static PyObject * @name@type_@kind@_either(npy_@name@ val, TrimMode trim_pos, TrimMode trim_sci, npy_bool sign) { int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode <= 113) { return legacy_@name@_format@kind@(val); } long double max_positional; if (legacy_print_mode <= 202) { max_positional = 1.e16L; } else { max_positional = @max_positional@; } int use_positional; if (npy_isnan(val) || val == 0) { use_positional = 1; } else { npy_@name@ absval = val < 0 ? -val : val; use_positional = absval < max_positional && absval >= 1.e-4L; } if (use_positional) { return format_@name@(val, 0, -1, sign, trim_pos, -1, -1, -1); } return format_@name@(val, 1, -1, sign, trim_sci, -1, -1, -1); } static PyObject * @name@type_@kind@(PyObject *self) { PyObject *string; string = @name@type_@kind@_either( PyArrayScalar_VAL(self, @Name@), TrimMode_LeaveOneZero, TrimMode_DptZeros, 0); #ifdef IS_repr if (string == NULL) { return NULL; } int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { Py_SETREF(string, PyUnicode_FromFormat("@repr_format@", string)); } #endif /* IS_repr */ return string; } static PyObject * c@name@type_@kind@(PyObject *self) { PyObject *rstr, *istr; npy_c@name@ val = PyArrayScalar_VAL(self, C@Name@); TrimMode trim = TrimMode_DptZeros; int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode <= 113) { return legacy_c@name@_format@kind@(val); } if (npy_creal@n@(val) == 0.0 && npy_signbit(npy_creal@n@(val)) == 0) { istr = @name@type_@kind@_either(npy_cimag@n@(val), trim, trim, 0); if (istr == NULL) { return NULL; } PyObject *ret; #ifdef IS_str ret = PyUnicode_FromFormat("%Sj", istr); #else /* IS_repr */ int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode <= 125) { ret = PyUnicode_FromFormat("%Sj", istr); } else { ret = PyUnicode_FromFormat("@crepr_imag_format@", istr); } #endif /* IS_repr */ Py_DECREF(istr); return ret; } if (npy_isfinite(npy_creal@n@(val))) { rstr = @name@type_@kind@_either(npy_creal@n@(val), trim, trim, 0); } else if (npy_isnan(npy_creal@n@(val))) { rstr = PyUnicode_FromString("nan"); } else if (npy_creal@n@(val) > 0){ rstr = PyUnicode_FromString("inf"); } else { rstr = PyUnicode_FromString("-inf"); } if (rstr == NULL) { return NULL; } if (npy_isfinite(npy_cimag@n@(val))) { istr = @name@type_@kind@_either(npy_cimag@n@(val), trim, trim, 1); } else if (npy_isnan(npy_cimag@n@(val))) { istr = PyUnicode_FromString("+nan"); } else if (npy_cimag@n@(val) > 0){ istr = PyUnicode_FromString("+inf"); } else { istr = PyUnicode_FromString("-inf"); } if (istr == NULL) { Py_DECREF(rstr); return NULL; } PyObject *string; #ifdef IS_str string = PyUnicode_FromFormat("(%S%Sj)", rstr, istr); #else /* IS_repr */ legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode > 125) { string = PyUnicode_FromFormat("@crepr_format@", rstr, istr); } else { string = PyUnicode_FromFormat("(%S%Sj)", rstr, istr); } #endif /* IS_repr */ Py_DECREF(rstr); Py_DECREF(istr); return string; } #undef PREC /**end repeat1**/ static PyObject * halftype_@kind@(PyObject *self) { npy_half val = PyArrayScalar_VAL(self, Half); float floatval = npy_half_to_float(val); float absval; int legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (legacy_print_mode <= 113) { return legacy_float_format@kind@(floatval); } long double max_positional; if (legacy_print_mode <= 202) { max_positional = 1.e16L; } else { max_positional = 1.e3L; } absval = floatval < 0 ? -floatval : floatval; PyObject *string; if (absval == 0 || (absval < max_positional && absval >= 1.e-4) ) { string = format_half(val, 0, -1, 0, TrimMode_LeaveOneZero, -1, -1, -1); } else { string = format_half(val, 1, -1, 0, TrimMode_DptZeros, -1, -1, -1); } #ifdef IS_str return string; #else legacy_print_mode = get_legacy_print_mode(); if (legacy_print_mode == -1) { return NULL; } if (string == NULL || legacy_print_mode <= 125) { return string; } PyObject *res = PyUnicode_FromFormat("np.float16(%S)", string); Py_DECREF(string); return res; #endif } #undef IS_@kind@ /**end repeat**/ static PyObject * longdoubletype_float(PyObject *self) { npy_longdouble val = PyArrayScalar_VAL(self, LongDouble); return PyFloat_FromDouble((double) val); } static PyObject * longdoubletype_long(PyObject *self) { npy_longdouble val = PyArrayScalar_VAL(self, LongDouble); return npy_longdouble_to_PyLong(val); } static PyObject * clongdoubletype_float(PyObject *self) { npy_longdouble val = npy_creall(PyArrayScalar_VAL(self, CLongDouble)); return PyFloat_FromDouble((double) val); } static PyObject * clongdoubletype_long(PyObject *self) { npy_longdouble val = npy_creall(PyArrayScalar_VAL(self, CLongDouble)); return npy_longdouble_to_PyLong(val); } static PyNumberMethods gentype_as_number = { .nb_add = (binaryfunc)gentype_add, .nb_subtract = (binaryfunc)gentype_subtract, .nb_multiply = (binaryfunc)gentype_multiply, .nb_remainder = (binaryfunc)gentype_remainder, .nb_divmod = (binaryfunc)gentype_divmod, .nb_power = (ternaryfunc)gentype_power, .nb_negative = (unaryfunc)gentype_negative, .nb_positive = (unaryfunc)gentype_positive, .nb_absolute = (unaryfunc)gentype_absolute, .nb_bool = (inquiry)gentype_nonzero_number, .nb_invert = (unaryfunc)gentype_invert, .nb_lshift = (binaryfunc)gentype_lshift, .nb_rshift = (binaryfunc)gentype_rshift, .nb_and = (binaryfunc)gentype_and, .nb_xor = (binaryfunc)gentype_xor, .nb_or = (binaryfunc)gentype_or, .nb_int = (unaryfunc)gentype_int, .nb_float = (unaryfunc)gentype_float, .nb_floor_divide = (binaryfunc)gentype_floor_divide, .nb_true_divide = (binaryfunc)gentype_true_divide, }; static PyObject * gentype_richcompare(PyObject *self, PyObject *other, int cmp_op) { /* * If the other object is None, False is always right. This avoids * the array None comparison, at least until deprecation it is fixed. * After that, this may be removed and numpy false would be returned. * * NOTE: np.equal(NaT, None) evaluates to TRUE! This is an * an inconsistency, which may has to be considered * when the deprecation is finished. */ if (other == Py_None) { if (cmp_op == Py_EQ) { Py_RETURN_FALSE; } if (cmp_op == Py_NE) { Py_RETURN_TRUE; } } RICHCMP_GIVE_UP_IF_NEEDED(self, other); PyObject *self_op; PyObject *other_op; if (find_binary_operation_path(self, other, &self_op, &other_op) < 0) { return NULL; } /* We can always just call RichCompare again */ if (other_op != NULL) { /* If we use richcompare again, need to ensure that one op is array */ self_op = PyArray_FromScalar(self, NULL); if (self_op == NULL) { Py_DECREF(other_op); return NULL; } PyObject *res = PyObject_RichCompare(self_op, other_op, cmp_op); Py_DECREF(self_op); Py_DECREF(other_op); return res; } else if (self_op != NULL) { /* Try again, since other is an object scalar and this one mutated */ PyObject *res = PyObject_RichCompare(self_op, other, cmp_op); Py_DECREF(self_op); return res; } else { /* Comparison with arbitrary objects cannot be defined. */ Py_RETURN_NOTIMPLEMENTED; } } static PyObject * gentype_ndim_get(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { return PyLong_FromLong(0); } static PyObject * gentype_flags_get(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { return PyArray_NewFlagsObject(NULL); } static PyObject * voidtype_flags_get(PyVoidScalarObject *self, void *NPY_UNUSED(ignored)) { PyObject *flagobj; flagobj = PyArrayFlags_Type.tp_alloc(&PyArrayFlags_Type, 0); if (flagobj == NULL) { return NULL; } ((PyArrayFlagsObject *)flagobj)->arr = NULL; ((PyArrayFlagsObject *)flagobj)->flags = self->flags; return flagobj; } static PyObject * voidtype_dtypedescr_get(PyVoidScalarObject *self, void *NPY_UNUSED(ignored)) { Py_INCREF(self->descr); return (PyObject *)self->descr; } static PyObject * inttype_numerator_get(PyObject *self, void *NPY_UNUSED(ignored)) { Py_INCREF(self); return self; } static PyObject * inttype_denominator_get(PyObject *self, void *NPY_UNUSED(ignored)) { return PyLong_FromLong(1); } static PyObject * gentype_data_get(PyObject *self, void *NPY_UNUSED(ignored)) { return PyMemoryView_FromObject(self); } static PyObject * gentype_itemsize_get(PyObject *self, void *NPY_UNUSED(ignored)) { PyArray_Descr *typecode; PyObject *ret; int elsize; typecode = PyArray_DescrFromScalar(self); elsize = typecode->elsize; ret = PyLong_FromLong((long) elsize); Py_DECREF(typecode); return ret; } static PyObject * gentype_size_get(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { return PyLong_FromLong(1); } static PyObject * gentype_sizeof(PyObject *self, PyObject *NPY_UNUSED(args)) { Py_ssize_t nbytes; PyObject * isz = gentype_itemsize_get(self, NULL); if (isz == NULL) { return NULL; } nbytes = PyLong_AsLong(isz) + Py_TYPE(self)->tp_basicsize + Py_SIZE(self) * Py_TYPE(self)->tp_itemsize; Py_DECREF(isz); return PyLong_FromSsize_t(nbytes); } NPY_NO_EXPORT void gentype_struct_free(PyObject *ptr) { PyArrayInterface *arrif = (PyArrayInterface*)PyCapsule_GetPointer(ptr, NULL); if (arrif == NULL) { PyErr_WriteUnraisable(ptr); return; } PyObject *context = (PyObject *)PyCapsule_GetContext(ptr); if (context == NULL && PyErr_Occurred()) { PyErr_WriteUnraisable(ptr); } Py_XDECREF(context); Py_XDECREF(arrif->descr); PyArray_free(arrif->shape); PyArray_free(arrif); } static PyObject * gentype_struct_get(PyObject *self, void *NPY_UNUSED(ignored)) { PyArrayObject *arr; PyArrayInterface *inter; PyObject *ret; arr = (PyArrayObject *)PyArray_FromScalar(self, NULL); inter = (PyArrayInterface *)PyArray_malloc(sizeof(PyArrayInterface)); inter->two = 2; inter->nd = 0; inter->flags = PyArray_FLAGS(arr); inter->flags &= ~(NPY_ARRAY_WRITEBACKIFCOPY | NPY_ARRAY_OWNDATA); inter->flags |= NPY_ARRAY_NOTSWAPPED; inter->typekind = PyArray_DESCR(arr)->kind; inter->itemsize = PyArray_ITEMSIZE(arr); inter->strides = NULL; inter->shape = NULL; inter->data = PyArray_DATA(arr); inter->descr = NULL; ret = NpyCapsule_FromVoidPtrAndDesc(inter, arr, gentype_struct_free); return ret; } static PyObject * gentype_priority_get(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { return PyFloat_FromDouble(NPY_SCALAR_PRIORITY); } static PyObject * gentype_shape_get(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { return PyTuple_New(0); } static PyObject * gentype_interface_get(PyObject *self, void *NPY_UNUSED(ignored)) { PyArrayObject *arr; PyObject *inter; arr = (PyArrayObject *)PyArray_FromScalar(self, NULL); if (arr == NULL) { return NULL; } inter = PyObject_GetAttrString((PyObject *)arr, "__array_interface__"); if (inter != NULL) { PyDict_SetItemString(inter, "__ref", (PyObject *)arr); } Py_DECREF(arr); return inter; } static PyObject * gentype_typedescr_get(PyObject *self, void *NPY_UNUSED(ignored)) { return (PyObject *)PyArray_DescrFromScalar(self); } static PyObject * gentype_base_get(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { Py_RETURN_NONE; } static PyObject * voidtype_base_get(PyVoidScalarObject *self, void *NPY_UNUSED(ignored)) { if (self->base == NULL) { Py_RETURN_NONE; } else { Py_INCREF(self->base); return self->base; } } static PyArray_Descr * _realdescr_fromcomplexscalar(PyObject *self, int *typenum) { if (PyArray_IsScalar(self, CDouble)) { *typenum = NPY_CDOUBLE; return PyArray_DescrFromType(NPY_DOUBLE); } if (PyArray_IsScalar(self, CFloat)) { *typenum = NPY_CFLOAT; return PyArray_DescrFromType(NPY_FLOAT); } if (PyArray_IsScalar(self, CLongDouble)) { *typenum = NPY_CLONGDOUBLE; return PyArray_DescrFromType(NPY_LONGDOUBLE); } return NULL; } static PyObject * gentype_real_get(PyObject *self, void *NPY_UNUSED(ignored)) { PyArray_Descr *typecode; PyObject *ret; int typenum; if (PyArray_IsScalar(self, ComplexFloating)) { void *ptr; typecode = _realdescr_fromcomplexscalar(self, &typenum); ptr = scalar_value(self, NULL); ret = PyArray_Scalar(ptr, typecode, NULL); Py_DECREF(typecode); return ret; } else if (PyArray_IsScalar(self, Object)) { PyObject *obj = PyArrayScalar_VAL(self, Object); ret = PyObject_GetAttrString(obj, "real"); if (ret != NULL) { return ret; } PyErr_Clear(); } Py_INCREF(self); return (PyObject *)self; } static PyObject * gentype_imag_get(PyObject *self, void *NPY_UNUSED(ignored)) { PyArray_Descr *typecode=NULL; PyObject *ret; int typenum; if (PyArray_IsScalar(self, ComplexFloating)) { char *ptr; typecode = _realdescr_fromcomplexscalar(self, &typenum); ptr = (char *)scalar_value(self, NULL); ret = PyArray_Scalar(ptr + typecode->elsize, typecode, NULL); } else if (PyArray_IsScalar(self, Object)) { PyObject *obj = PyArrayScalar_VAL(self, Object); PyArray_Descr *newtype; ret = PyObject_GetAttrString(obj, "imag"); if (ret == NULL) { PyErr_Clear(); obj = PyLong_FromLong(0); newtype = PyArray_DescrFromType(NPY_OBJECT); ret = PyArray_Scalar((char *)&obj, newtype, NULL); Py_DECREF(newtype); Py_DECREF(obj); } } else { char *temp; int elsize; typecode = PyArray_DescrFromScalar(self); elsize = typecode->elsize; temp = npy_alloc_cache_zero(1, elsize); ret = PyArray_Scalar(temp, typecode, NULL); npy_free_cache(temp, elsize); } Py_XDECREF(typecode); return ret; } static PyObject * gentype_flat_get(PyObject *self, void *NPY_UNUSED(ignored)) { PyObject *ret, *arr; arr = PyArray_FromScalar(self, NULL); if (arr == NULL) { return NULL; } ret = PyArray_IterNew(arr); Py_DECREF(arr); return ret; } static PyObject * gentype_transpose_get(PyObject *self, void *NPY_UNUSED(ignored)) { Py_INCREF(self); return self; } static PyObject * gentype_newbyteorder(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { PyErr_SetString(PyExc_AttributeError, "`newbyteorder` was removed from scalar types in NumPy 2.0. " "Use `sc.view(sc.dtype.newbyteorder(order))` instead."); return NULL; } static PyObject * gentype_itemset(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { PyErr_SetString(PyExc_AttributeError, "`itemset` was removed from scalar types in NumPy 2.0 " "because scalars are immutable."); return NULL; } static PyObject * gentype_ptp(PyObject *NPY_UNUSED(self), void *NPY_UNUSED(ignored)) { PyErr_SetString(PyExc_AttributeError, "`ptp` was removed from scalar types in NumPy 2.0. " "For a scalar, the range of values always equals 0."); return NULL; } static PyGetSetDef gentype_getsets[] = { {"ndim", (getter)gentype_ndim_get, (setter) 0, NULL, NULL}, {"flags", (getter)gentype_flags_get, (setter)0, NULL, NULL}, {"shape", (getter)gentype_shape_get, (setter)0, NULL, NULL}, {"strides", (getter)gentype_shape_get, (setter) 0, NULL, NULL}, {"data", (getter)gentype_data_get, (setter) 0, NULL, NULL}, {"itemsize", (getter)gentype_itemsize_get, (setter)0, NULL, NULL}, {"size", (getter)gentype_size_get, (setter)0, NULL, NULL}, {"nbytes", (getter)gentype_itemsize_get, (setter)0, NULL, NULL}, {"base", (getter)gentype_base_get, (setter)0, NULL, NULL}, {"dtype", (getter)gentype_typedescr_get, NULL, NULL, NULL}, {"real", (getter)gentype_real_get, (setter)0, NULL, NULL}, {"imag", (getter)gentype_imag_get, (setter)0, NULL, NULL}, {"flat", (getter)gentype_flat_get, (setter)0, NULL, NULL}, {"T", (getter)gentype_transpose_get, (setter)0, NULL, NULL}, {"newbyteorder", (getter)gentype_newbyteorder, (setter)0, NULL, NULL}, {"itemset", (getter)gentype_itemset, (setter)0, NULL, NULL}, {"ptp", (getter)gentype_ptp, (setter)0, NULL, NULL}, {"device", (getter)array_device, (setter)0, NULL, NULL}, {"__array_interface__", (getter)gentype_interface_get, NULL, "Array protocol: Python side", NULL}, {"__array_struct__", (getter)gentype_struct_get, NULL, "Array protocol: struct", NULL}, {"__array_priority__", (getter)gentype_priority_get, NULL, "Array priority.", NULL}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ }; /* 0-dim array from scalar object */ static char doc_getarray[] = "sc.__array__(dtype) return 0-dim array from " "scalar with specified dtype"; static PyObject * gentype_getarray(PyObject *scalar, PyObject *args) { PyArray_Descr *outcode=NULL; PyObject *ret; if (!PyArg_ParseTuple(args, "|O&:__array__", &PyArray_DescrConverter, &outcode)) { Py_XDECREF(outcode); return NULL; } ret = PyArray_FromScalar(scalar, outcode); return ret; } static char doc_sc_wraparray[] = "__array_wrap__ implementation for scalar types"; /* * __array_wrap__ for scalars, returning a scalar if possible. * (note that NumPy itself may well never call this itself). */ static PyObject * gentype_wraparray(PyObject *NPY_UNUSED(scalar), PyObject *args) { PyArrayObject *arr; PyObject *UNUSED = NULL; /* for the context argument */ /* return_scalar should be passed, but we're scalar, so return scalar by default */ int return_scalar = 1; if (!PyArg_ParseTuple(args, "O!|OO&:__array_wrap__", &PyArray_Type, &arr, &UNUSED, &PyArray_OptionalBoolConverter, &return_scalar)) { return NULL; } Py_INCREF(arr); if (!return_scalar) { return (PyObject *)arr; } else { return PyArray_Return(arr); } } /* * These gentype_* functions do not take keyword arguments. * The proper flag is METH_VARARGS. */ /**begin repeat * * #name = tolist, item, __deepcopy__, __copy__, * swapaxes, conj, conjugate, nonzero, * fill, transpose# */ static PyObject * gentype_@name@(PyObject *self, PyObject *args) { return gentype_generic_method(self, args, NULL, "@name@"); } /**end repeat**/ static PyObject * gentype_byteswap(PyObject *self, PyObject *args, PyObject *kwds) { npy_bool inplace = NPY_FALSE; static char *kwlist[] = {"inplace", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&:byteswap", kwlist, PyArray_BoolConverter, &inplace)) { return NULL; } if (inplace) { PyErr_SetString(PyExc_ValueError, "cannot byteswap a scalar in-place"); return NULL; } else { /* get the data, copyswap it and pass it to a new Array scalar */ char *data; PyArray_Descr *descr; PyObject *new; char *newmem; descr = PyArray_DescrFromScalar(self); data = (void *)scalar_value(self, descr); newmem = PyObject_Malloc(descr->elsize); if (newmem == NULL) { Py_DECREF(descr); return PyErr_NoMemory(); } else { PyDataType_GetArrFuncs(descr)->copyswap(newmem, data, 1, NULL); } new = PyArray_Scalar(newmem, descr, NULL); PyObject_Free(newmem); Py_DECREF(descr); return new; } } /* * These gentype_* functions take keyword arguments. * The proper flag is METH_VARARGS | METH_KEYWORDS. */ /**begin repeat * * #name = take, getfield, put, repeat, tofile, mean, trace, diagonal, clip, * std, var, sum, cumsum, prod, cumprod, compress, sort, argsort, * round, argmax, argmin, max, min, any, all, astype, resize, * reshape, choose, tostring, tobytes, copy, searchsorted, view, * flatten, ravel, squeeze# */ static PyObject * gentype_@name@(PyObject *self, PyObject *args, PyObject *kwds) { return gentype_generic_method(self, args, kwds, "@name@"); } /**end repeat**/ /**begin repeat * #name = integer, floating# */ static PyObject * @name@type_dunder_round(PyObject *self, PyObject *args, PyObject *kwds) { static char *kwlist[] = {"ndigits", NULL}; PyObject *ndigits = Py_None; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:__round__", kwlist, &ndigits)) { return NULL; } PyObject *tup; if (ndigits == Py_None) { tup = PyTuple_Pack(0); } else { tup = PyTuple_Pack(1, ndigits); } if (tup == NULL) { return NULL; } PyObject *obj = gentype_round(self, tup, NULL); Py_DECREF(tup); if (obj == NULL) { return NULL; } if (ndigits == Py_None) { PyObject *ret = PyNumber_Long(obj); Py_DECREF(obj); return ret; } return obj; } /**end repeat**/ static PyObject * voidtype_getfield(PyVoidScalarObject *self, PyObject *args, PyObject *kwds) { /* Use ndarray's getfield to obtain the field safely */ return gentype_generic_method((PyObject *)self, args, kwds, "getfield"); } static PyObject * gentype_setfield(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds)) { PyErr_SetString(PyExc_TypeError, "Can't set fields in a non-void array scalar."); return NULL; } static PyObject * voidtype_setfield(PyVoidScalarObject *self, PyObject *args, PyObject *kwds) { /* * We would like to use ndarray's setfield because it performs safety * checks on the field datatypes and because it broadcasts properly. * However, as a special case, void-scalar assignment broadcasts * differently from ndarrays when assigning to an object field: Assignment * to an ndarray object field broadcasts, but assignment to a void-scalar * object-field should not, in order to allow nested ndarrays. * These lines should then behave identically: * * b = np.zeros(1, dtype=[('x', 'O')]) * b[0]['x'] = arange(3) # uses voidtype_setfield * b['x'][0] = arange(3) # uses ndarray setitem * * Ndarray's setfield would try to broadcast the lhs. Instead we use * ndarray getfield to get the field safely, then setitem with an empty * tuple to set the value without broadcast. Note we also want subarrays to * be set properly, ie * * a = np.zeros(1, dtype=[('x', 'i', 5)]) * a[0]['x'] = 1 * * sets all values to 1. "getfield + setitem with empty tuple" takes * care of both object arrays and subarrays. */ PyObject *getfield_args, *value, *arr, *meth, *arr_field, *emptytuple; value = PyTuple_GetItem(args, 0); if (value == NULL) { return NULL; } getfield_args = PyTuple_GetSlice(args, 1, 3); if (getfield_args == NULL) { return NULL; } /* 1. Convert to 0-d array and use getfield */ arr = PyArray_FromScalar((PyObject*)self, NULL); if (arr == NULL) { Py_DECREF(getfield_args); return NULL; } meth = PyObject_GetAttrString(arr, "getfield"); if (meth == NULL) { Py_DECREF(getfield_args); Py_DECREF(arr); return NULL; } if (kwds == NULL) { arr_field = PyObject_CallObject(meth, getfield_args); } else { arr_field = PyObject_Call(meth, getfield_args, kwds); } Py_DECREF(getfield_args); Py_DECREF(meth); Py_DECREF(arr); if(arr_field == NULL){ return NULL; } /* 2. Assign the value using setitem with empty tuple. */ emptytuple = PyTuple_New(0); if (PyObject_SetItem(arr_field, emptytuple, value) < 0) { Py_DECREF(arr_field); Py_DECREF(emptytuple); return NULL; } Py_DECREF(emptytuple); Py_DECREF(arr_field); Py_RETURN_NONE; } static PyObject * gentype_reduce(PyObject *self, PyObject *NPY_UNUSED(args)) { PyObject *ret = NULL, *obj = NULL, *mod = NULL; Py_buffer view; const char *buffer; Py_ssize_t buflen; /* Return a tuple of (callable object, arguments) */ ret = PyTuple_New(2); if (ret == NULL) { return NULL; } if (PyObject_GetBuffer(self, &view, PyBUF_SIMPLE) >= 0) { buffer = view.buf; buflen = view.len; /* * Both of the deprecated functions PyObject_AsWriteBuffer and * PyObject_AsReadBuffer that this code replaces release the buffer. It is * up to the object that supplies the buffer to guarantee that the buffer * sticks around after the release. */ PyBuffer_Release(&view); } else { Py_DECREF(ret); return NULL; } mod = PyImport_ImportModule("numpy._core._multiarray_umath"); if (mod == NULL) { Py_DECREF(ret); return NULL; } obj = PyObject_GetAttrString(mod, "scalar"); Py_DECREF(mod); if (obj == NULL) { Py_DECREF(ret); return NULL; } PyTuple_SET_ITEM(ret, 0, obj); obj = PyObject_GetAttrString((PyObject *)self, "dtype"); if (PyArray_IsScalar(self, Object)) { PyObject *val = PyArrayScalar_VAL(self, Object); PyObject *tup = Py_BuildValue("NO", obj, val); if (tup == NULL) { Py_DECREF(ret); return NULL; } PyTuple_SET_ITEM(ret, 1, tup); } else if (obj && PyDataType_FLAGCHK((PyArray_Descr *)obj, NPY_LIST_PICKLE)) { /* a structured dtype with an object in a field */ PyArrayObject *arr = (PyArrayObject *)PyArray_FromScalar(self, NULL); if (arr == NULL) { Py_DECREF(ret); return NULL; } /* Use the whole array which handles structured void correctly */ PyObject *tup = Py_BuildValue("NN", obj, arr); if (tup == NULL) { Py_DECREF(ret); return NULL; } PyTuple_SET_ITEM(ret, 1, tup); } else { mod = PyBytes_FromStringAndSize(buffer, buflen); if (mod == NULL) { Py_DECREF(ret); return NULL; } PyTuple_SET_ITEM(ret, 1, Py_BuildValue("NN", obj, mod)); } return ret; } /* ignores everything */ static PyObject * gentype_setstate(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args)) { Py_RETURN_NONE; } static PyObject * gentype_dump(PyObject *self, PyObject *args) { PyObject *file = NULL; int ret; if (!PyArg_ParseTuple(args, "O:dump", &file)) { return NULL; } ret = PyArray_Dump(self, file, 2); if (ret < 0) { return NULL; } Py_RETURN_NONE; } static PyObject * gentype_dumps(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, "")) { return NULL; } return PyArray_Dumps(self, 2); } /* setting flags cannot be done for scalars */ static PyObject * gentype_setflags(PyObject *NPY_UNUSED(self), PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds)) { Py_RETURN_NONE; } static PyObject * numbertype_class_getitem_abc(PyObject *cls, PyObject *args) { const Py_ssize_t args_len = PyTuple_Check(args) ? PyTuple_Size(args) : 1; int args_len_expected; /* complexfloating should take 2 parameters, all others take 1 */ if (PyType_IsSubtype((PyTypeObject *)cls, &PyComplexFloatingArrType_Type)) { args_len_expected = 2; } else { args_len_expected = 1; } if ((args_len > args_len_expected) || (args_len == 0)) { return PyErr_Format(PyExc_TypeError, "Too %s arguments for %s", args_len > args_len_expected ? "many" : "few", ((PyTypeObject *)cls)->tp_name); } return Py_GenericAlias(cls, args); } /* * Use for concrete np.number subclasses, making them act as if they * were subtyped from e.g. np.signedinteger[object], thus lacking any * free subscription parameters. Requires python >= 3.9. */ static PyObject * numbertype_class_getitem(PyObject *cls, PyObject *args) { PyErr_Format(PyExc_TypeError, "There are no type variables left in %s", ((PyTypeObject *)cls)->tp_name); return NULL; } /* * casting complex numbers (that don't inherit from Python complex) * to Python complex */ /**begin repeat * #name = cfloat, clongdouble# * #Name = CFloat, CLongDouble# * #NAME = CFLOAT, CLONGDOUBLE# * #n = f, l# */ static PyObject * @name@_complex(PyObject *self, PyObject *NPY_UNUSED(args), PyObject *NPY_UNUSED(kwds)) { return PyComplex_FromDoubles(npy_creal@n@(PyArrayScalar_VAL(self, @Name@)), npy_cimag@n@(PyArrayScalar_VAL(self, @Name@))); } /**end repeat**/ /**begin repeat * #name = half, float, double, longdouble# * #Name = Half, Float, Double, LongDouble# * #is_half = 1,0,0,0# * #c = f, f, , l# * #convert = PyLong_FromDouble, PyLong_FromDouble, PyLong_FromDouble, * npy_longdouble_to_PyLong# * # */ /* Heavily copied from the builtin float.as_integer_ratio */ static PyObject * @name@_as_integer_ratio(PyObject *self, PyObject *NPY_UNUSED(args)) { #if @is_half@ npy_double val = npy_half_to_double(PyArrayScalar_VAL(self, @Name@)); npy_double frac; #else npy_@name@ val = PyArrayScalar_VAL(self, @Name@); npy_@name@ frac; #endif int exponent; PyObject *py_exponent = NULL; PyObject *numerator = NULL; PyObject *denominator = NULL; PyObject *result_pair = NULL; PyNumberMethods *long_methods = PyLong_Type.tp_as_number; if (npy_isnan(val)) { PyErr_SetString(PyExc_ValueError, "cannot convert NaN to integer ratio"); return NULL; } if (!npy_isfinite(val)) { PyErr_SetString(PyExc_OverflowError, "cannot convert Infinity to integer ratio"); return NULL; } frac = npy_frexp@c@(val, &exponent); /* val == frac * 2**exponent exactly */ /* This relies on the floating point type being base 2 to converge */ while (frac != npy_floor@c@(frac)) { frac *= 2.0; exponent--; } /* self == frac * 2**exponent exactly and frac is integral. */ numerator = @convert@(frac); if (numerator == NULL) goto error; denominator = PyLong_FromLong(1); if (denominator == NULL) goto error; py_exponent = PyLong_FromLong(exponent < 0 ? -exponent : exponent); if (py_exponent == NULL) goto error; /* fold in 2**exponent */ if (exponent > 0) { PyObject *temp = long_methods->nb_lshift(numerator, py_exponent); if (temp == NULL) goto error; Py_DECREF(numerator); numerator = temp; } else { PyObject *temp = long_methods->nb_lshift(denominator, py_exponent); if (temp == NULL) goto error; Py_DECREF(denominator); denominator = temp; } result_pair = PyTuple_Pack(2, numerator, denominator); error: Py_XDECREF(py_exponent); Py_XDECREF(denominator); Py_XDECREF(numerator); return result_pair; } /**end repeat**/ /**begin repeat * #name = half, float, double, longdouble# * #Name = Half, Float, Double, LongDouble# * #is_half = 1,0,0,0# * #c = f, f, , l# */ static PyObject * @name@_is_integer(PyObject *self, PyObject *NPY_UNUSED(args)) { #if @is_half@ npy_double val = npy_half_to_double(PyArrayScalar_VAL(self, @Name@)); #else npy_@name@ val = PyArrayScalar_VAL(self, @Name@); #endif PyObject *ret; if (npy_isnan(val)) { Py_RETURN_FALSE; } if (!npy_isfinite(val)) { Py_RETURN_FALSE; } ret = (npy_floor@c@(val) == val) ? Py_True : Py_False; Py_INCREF(ret); return ret; } /**end repeat**/ static PyObject * integer_is_integer(PyObject *self, PyObject *NPY_UNUSED(args)) { Py_RETURN_TRUE; } /* * need to fill in doc-strings for these methods on import -- copy from * array docstrings */ static PyMethodDef gentype_methods[] = { {"tolist", (PyCFunction)gentype_tolist, METH_VARARGS, NULL}, {"item", (PyCFunction)gentype_item, METH_VARARGS, NULL}, {"tobytes", (PyCFunction)gentype_tobytes, METH_VARARGS | METH_KEYWORDS, NULL}, {"tofile", (PyCFunction)gentype_tofile, METH_VARARGS | METH_KEYWORDS, NULL}, {"tostring", (PyCFunction)gentype_tostring, METH_VARARGS | METH_KEYWORDS, NULL}, {"byteswap", (PyCFunction)gentype_byteswap, METH_VARARGS | METH_KEYWORDS, NULL}, {"astype", (PyCFunction)gentype_astype, METH_VARARGS | METH_KEYWORDS, NULL}, {"getfield", (PyCFunction)gentype_getfield, METH_VARARGS | METH_KEYWORDS, NULL}, {"setfield", (PyCFunction)gentype_setfield, METH_VARARGS | METH_KEYWORDS, NULL}, {"copy", (PyCFunction)gentype_copy, METH_VARARGS | METH_KEYWORDS, NULL}, {"resize", (PyCFunction)gentype_resize, METH_VARARGS | METH_KEYWORDS, NULL}, {"__array__", (PyCFunction)gentype_getarray, METH_VARARGS, doc_getarray}, {"__array_wrap__", (PyCFunction)gentype_wraparray, METH_VARARGS, doc_sc_wraparray}, /* for the sys module */ {"__sizeof__", (PyCFunction)gentype_sizeof, METH_NOARGS, NULL}, /* for the copy module */ {"__copy__", (PyCFunction)gentype___copy__, METH_VARARGS, NULL}, {"__deepcopy__", (PyCFunction)gentype___deepcopy__, METH_VARARGS, NULL}, {"__reduce__", (PyCFunction) gentype_reduce, METH_VARARGS, NULL}, /* For consistency does nothing */ {"__setstate__", (PyCFunction) gentype_setstate, METH_VARARGS, NULL}, {"dumps", (PyCFunction) gentype_dumps, METH_VARARGS, NULL}, {"dump", (PyCFunction) gentype_dump, METH_VARARGS, NULL}, /* Methods for array */ {"fill", (PyCFunction)gentype_fill, METH_VARARGS, NULL}, {"transpose", (PyCFunction)gentype_transpose, METH_VARARGS, NULL}, {"take", (PyCFunction)gentype_take, METH_VARARGS | METH_KEYWORDS, NULL}, {"put", (PyCFunction)gentype_put, METH_VARARGS | METH_KEYWORDS, NULL}, {"repeat", (PyCFunction)gentype_repeat, METH_VARARGS | METH_KEYWORDS, NULL}, {"choose", (PyCFunction)gentype_choose, METH_VARARGS | METH_KEYWORDS, NULL}, {"sort", (PyCFunction)gentype_sort, METH_VARARGS | METH_KEYWORDS, NULL}, {"argsort", (PyCFunction)gentype_argsort, METH_VARARGS | METH_KEYWORDS, NULL}, {"searchsorted", (PyCFunction)gentype_searchsorted, METH_VARARGS | METH_KEYWORDS, NULL}, {"argmax", (PyCFunction)gentype_argmax, METH_VARARGS | METH_KEYWORDS, NULL}, {"argmin", (PyCFunction)gentype_argmin, METH_VARARGS | METH_KEYWORDS, NULL}, {"reshape", (PyCFunction)gentype_reshape, METH_VARARGS | METH_KEYWORDS, NULL}, {"squeeze", (PyCFunction)gentype_squeeze, METH_VARARGS | METH_KEYWORDS, NULL}, {"view", (PyCFunction)gentype_view, METH_VARARGS | METH_KEYWORDS, NULL}, {"swapaxes", (PyCFunction)gentype_swapaxes, METH_VARARGS, NULL}, {"max", (PyCFunction)gentype_max, METH_VARARGS | METH_KEYWORDS, NULL}, {"min", (PyCFunction)gentype_min, METH_VARARGS | METH_KEYWORDS, NULL}, {"mean", (PyCFunction)gentype_mean, METH_VARARGS | METH_KEYWORDS, NULL}, {"trace", (PyCFunction)gentype_trace, METH_VARARGS | METH_KEYWORDS, NULL}, {"diagonal", (PyCFunction)gentype_diagonal, METH_VARARGS | METH_KEYWORDS, NULL}, {"clip", (PyCFunction)gentype_clip, METH_VARARGS | METH_KEYWORDS, NULL}, {"conj", (PyCFunction)gentype_conj, METH_VARARGS, NULL}, {"conjugate", (PyCFunction)gentype_conjugate, METH_VARARGS, NULL}, {"nonzero", (PyCFunction)gentype_nonzero, METH_VARARGS, NULL}, {"std", (PyCFunction)gentype_std, METH_VARARGS | METH_KEYWORDS, NULL}, {"var", (PyCFunction)gentype_var, METH_VARARGS | METH_KEYWORDS, NULL}, {"sum", (PyCFunction)gentype_sum, METH_VARARGS | METH_KEYWORDS, NULL}, {"cumsum", (PyCFunction)gentype_cumsum, METH_VARARGS | METH_KEYWORDS, NULL}, {"prod", (PyCFunction)gentype_prod, METH_VARARGS | METH_KEYWORDS, NULL}, {"cumprod", (PyCFunction)gentype_cumprod, METH_VARARGS | METH_KEYWORDS, NULL}, {"all", (PyCFunction)gentype_all, METH_VARARGS | METH_KEYWORDS, NULL}, {"any", (PyCFunction)gentype_any, METH_VARARGS | METH_KEYWORDS, NULL}, {"compress", (PyCFunction)gentype_compress, METH_VARARGS | METH_KEYWORDS, NULL}, {"flatten", (PyCFunction)gentype_flatten, METH_VARARGS | METH_KEYWORDS, NULL}, {"ravel", (PyCFunction)gentype_ravel, METH_VARARGS | METH_KEYWORDS, NULL}, {"round", (PyCFunction)gentype_round, METH_VARARGS | METH_KEYWORDS, NULL}, /* For the format function */ {"__format__", gentype_format, METH_VARARGS, "NumPy array scalar formatter"}, {"setflags", (PyCFunction)gentype_setflags, METH_VARARGS | METH_KEYWORDS, NULL}, /* For Array API compatibility */ {"__array_namespace__", (PyCFunction)array_array_namespace, METH_VARARGS | METH_KEYWORDS, NULL}, {"to_device", (PyCFunction)array_to_device, METH_VARARGS | METH_KEYWORDS, NULL}, {NULL, NULL, 0, NULL} /* sentinel */ }; static PyGetSetDef voidtype_getsets[] = { {"flags", (getter)voidtype_flags_get, (setter)0, "integer value of flags", NULL}, {"dtype", (getter)voidtype_dtypedescr_get, (setter)0, "dtype object", NULL}, {"base", (getter)voidtype_base_get, (setter)0, "base object", NULL}, {NULL, NULL, NULL, NULL, NULL} }; static PyMethodDef voidtype_methods[] = { {"getfield", (PyCFunction)voidtype_getfield, METH_VARARGS | METH_KEYWORDS, NULL}, {"setfield", (PyCFunction)voidtype_setfield, METH_VARARGS | METH_KEYWORDS, NULL}, {NULL, NULL, 0, NULL} }; static PyGetSetDef inttype_getsets[] = { {"numerator", (getter)inttype_numerator_get, (setter)0, "numerator of value (the value itself)", NULL}, {"denominator", (getter)inttype_denominator_get, (setter)0, "denominator of value (1)", NULL}, {NULL, NULL, NULL, NULL, NULL} }; static PyMethodDef numbertype_methods[] = { /* for typing */ {"__class_getitem__", (PyCFunction)numbertype_class_getitem_abc, METH_CLASS | METH_O, NULL}, {NULL, NULL, 0, NULL} /* sentinel */ }; /**begin repeat * #name = cfloat,clongdouble# */ static PyMethodDef @name@type_methods[] = { {"__complex__", (PyCFunction)@name@_complex, METH_VARARGS | METH_KEYWORDS, NULL}, /* for typing */ {"__class_getitem__", (PyCFunction)numbertype_class_getitem, METH_CLASS | METH_O, NULL}, {NULL, NULL, 0, NULL} }; /**end repeat**/ static PyMethodDef floatingtype_methods[] = { /* Hook for the round() builtin */ {"__round__", (PyCFunction)floatingtype_dunder_round, METH_VARARGS | METH_KEYWORDS, NULL}, {NULL, NULL, 0, NULL} /* sentinel */ }; static PyMethodDef integertype_methods[] = { /* Hook for the round() builtin */ {"__round__", (PyCFunction)integertype_dunder_round, METH_VARARGS | METH_KEYWORDS, NULL}, {"is_integer", (PyCFunction)integer_is_integer, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} /* sentinel */ }; /**begin repeat * #name = half,float,double,longdouble# */ static PyMethodDef @name@type_methods[] = { {"as_integer_ratio", (PyCFunction)@name@_as_integer_ratio, METH_NOARGS, NULL}, {"is_integer", (PyCFunction)@name@_is_integer, METH_NOARGS, NULL}, /* for typing */ {"__class_getitem__", (PyCFunction)numbertype_class_getitem, METH_CLASS | METH_O, NULL}, {NULL, NULL, 0, NULL} }; /**end repeat**/ /**begin repeat * #name = timedelta, cdouble# */ static PyMethodDef @name@type_methods[] = { /* for typing */ {"__class_getitem__", (PyCFunction)numbertype_class_getitem, METH_CLASS | METH_O, NULL}, {NULL, NULL, 0, NULL} }; /**end repeat**/ /**begin repeat * #name = byte, ubyte, short, ushort, int, uint, * long, ulong, longlong, ulonglong# */ static PyMethodDef @name@type_methods[] = { /* for typing */ {"__class_getitem__", (PyCFunction)numbertype_class_getitem, METH_CLASS | METH_O, NULL}, {"bit_count", (PyCFunction)npy_@name@_bit_count, METH_NOARGS, NULL}, {NULL, NULL, 0, NULL} /* sentinel */ }; /**end repeat**/ /************* As_mapping functions for void array scalar ************/ static Py_ssize_t voidtype_length(PyVoidScalarObject *self) { if (!PyDataType_HASFIELDS(self->descr)) { return 0; } else { /* return the number of fields */ return (Py_ssize_t) PyTuple_GET_SIZE(self->descr->names); } } static PyObject * voidtype_subscript(PyVoidScalarObject *self, PyObject *ind); static PyObject * voidtype_item(PyVoidScalarObject *self, Py_ssize_t n) { npy_intp m; PyObject *flist=NULL; if (!(PyDataType_HASFIELDS(self->descr))) { PyErr_SetString(PyExc_IndexError, "can't index void scalar without fields"); return NULL; } flist = self->descr->names; m = PyTuple_GET_SIZE(flist); if (n < 0) { n += m; } if (n < 0 || n >= m) { PyErr_Format(PyExc_IndexError, "invalid index (%d)", (int) n); return NULL; } return voidtype_subscript(self, PyTuple_GetItem(flist, n)); } /* get field by name or number */ static PyObject * voidtype_subscript(PyVoidScalarObject *self, PyObject *ind) { npy_intp n; PyObject *ret, *res; /* structured voids will accept an integer index */ if (PyDataType_HASFIELDS(self->descr)) { n = PyArray_PyIntAsIntp(ind); if (!error_converting(n)) { return voidtype_item(self, (Py_ssize_t)n); } PyErr_Clear(); } res = PyArray_FromScalar((PyObject*)self, NULL); /* ellipsis should return 0d array */ if(ind == Py_Ellipsis){ return res; } /* * other cases (field names, empty tuple) will return either * scalar or non-0d array. Compute this using ndarray subscript. */ ret = array_subscript((PyArrayObject *)res, ind); Py_DECREF(res); return PyArray_Return((PyArrayObject*)ret); } static int voidtype_ass_subscript(PyVoidScalarObject *self, PyObject *ind, PyObject *val); static int voidtype_ass_item(PyVoidScalarObject *self, Py_ssize_t n, PyObject *val) { npy_intp m; PyObject *flist=NULL; if (!(PyDataType_HASFIELDS(self->descr))) { PyErr_SetString(PyExc_IndexError, "can't index void scalar without fields"); return -1; } flist = self->descr->names; m = PyTuple_GET_SIZE(flist); if (n < 0) { n += m; } if (n < 0 || n >= m) { PyErr_Format(PyExc_IndexError, "invalid index (%d)", (int) n); return -1; } return voidtype_ass_subscript(self, PyTuple_GetItem(flist, n), val); } static int voidtype_ass_subscript(PyVoidScalarObject *self, PyObject *ind, PyObject *val) { npy_intp n; char *msg = "invalid index"; PyObject *args; if (!PyDataType_HASFIELDS(self->descr)) { PyErr_SetString(PyExc_IndexError, "can't index void scalar without fields"); return -1; } if (!val) { PyErr_SetString(PyExc_ValueError, "cannot delete scalar field"); return -1; } if (PyUnicode_Check(ind)) { /* * Much like in voidtype_setfield, we cannot simply use ndarray's * __setitem__ since assignment to void scalars should not broadcast * the lhs. Instead we get a view through __getitem__ and then assign * the value using setitem with an empty tuple (which treats both * object arrays and subarrays properly). * * Also we do not want to use voidtype_setfield here, since we do * not need to do the (slow) view safety checks, since we already * know the dtype/offset are safe. */ PyObject *arr, *arr_field, *meth, *emptytuple; /* 1. Convert to 0-d array and use getitem */ arr = PyArray_FromScalar((PyObject*)self, NULL); if (arr == NULL) { return -1; } meth = PyObject_GetAttrString(arr, "__getitem__"); if (meth == NULL) { Py_DECREF(arr); return -1; } args = Py_BuildValue("(O)", ind); arr_field = PyObject_CallObject(meth, args); Py_DECREF(meth); Py_DECREF(arr); Py_DECREF(args); if(arr_field == NULL){ return -1; } /* 2. Assign the value using setitem with empty tuple. */ emptytuple = PyTuple_New(0); if (PyObject_SetItem(arr_field, emptytuple, val) < 0) { Py_DECREF(arr_field); Py_DECREF(emptytuple); return -1; } Py_DECREF(emptytuple); Py_DECREF(arr_field); return 0; } /* try to convert it to a number */ n = PyArray_PyIntAsIntp(ind); if (error_converting(n)) { goto fail; } return voidtype_ass_item(self, (Py_ssize_t)n, val); fail: PyErr_SetString(PyExc_IndexError, msg); return -1; } static PyMappingMethods voidtype_as_mapping = { .mp_length = (lenfunc)voidtype_length, .mp_subscript = (binaryfunc)voidtype_subscript, .mp_ass_subscript = (objobjargproc)voidtype_ass_subscript, }; static PySequenceMethods voidtype_as_sequence = { .sq_length = (lenfunc)voidtype_length, .sq_item = (ssizeargfunc)voidtype_item, .sq_ass_item = (ssizeobjargproc)voidtype_ass_item, }; /* * This function implements simple buffer export for user defined subclasses * of `np.generic`. All other scalar types override the buffer export. */ static int gentype_arrtype_getbuffer(PyObject *self, Py_buffer *view, int flags) { if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) { PyErr_Format(PyExc_TypeError, "NumPy scalar %R can only exported as a buffer without format.", self); return -1; } if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); return -1; } PyArray_Descr *descr = PyArray_DescrFromScalar(self); if (descr == NULL) { return -1; } if (!PyDataType_ISUSERDEF(descr)) { /* This path would also reject the (hopefully) impossible "object" */ PyErr_Format(PyExc_TypeError, "user-defined scalar %R registered for built-in dtype %S? " "This should be impossible.", self, descr); Py_DECREF(descr); return -1; } view->ndim = 0; view->len = descr->elsize; view->itemsize = descr->elsize; view->shape = NULL; view->strides = NULL; view->suboffsets = NULL; view->readonly = 1; /* assume general (user) scalars are readonly. */ Py_INCREF(self); view->obj = self; view->buf = scalar_value(self, descr); Py_DECREF(descr); view->format = NULL; return 0; } static PyBufferProcs gentype_arrtype_as_buffer = { .bf_getbuffer = (getbufferproc)gentype_arrtype_getbuffer, }; /**begin repeat * #name = bool, byte, short, int, long, longlong, ubyte, ushort, uint, ulong, * ulonglong, half, float, double, longdouble, cfloat, cdouble, * clongdouble# * #Name = Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, * ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, * CLongDouble# * #NAME = BOOL, BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG, * ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, * CLONGDOUBLE# * #fmt = ?, b, h, i, l, q, B, H, I, L, Q, e, f, d, g, Zf, Zd, Zg# */ static int @name@_getbuffer(PyObject *self, Py_buffer *view, int flags) { if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); return -1; } Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self; static char fmt[3] = "@fmt@"; view->ndim = 0; view->len = sizeof(scalar->obval); view->itemsize = sizeof(scalar->obval); view->shape = NULL; view->strides = NULL; view->suboffsets = NULL; view->readonly = 1; Py_INCREF(self); view->obj = self; view->buf = &(scalar->obval); if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) { /* It is unnecessary to find the correct format */ view->format = NULL; return 0; } view->format = fmt; return 0; } static PyBufferProcs @name@_arrtype_as_buffer = { .bf_getbuffer = @name@_getbuffer, /* No need to release the buffer */ }; /**end repeat**/ static int unicode_getbuffer(PyObject *self, Py_buffer *view, int flags) { if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); return -1; } PyUnicodeScalarObject *scalar = (PyUnicodeScalarObject *)self; Py_ssize_t length = PyUnicode_GetLength(self); view->ndim = 0; view->len = length * 4; view->itemsize = length * 4; view->shape = NULL; view->strides = NULL; view->suboffsets = NULL; view->readonly = 1; Py_INCREF(self); view->obj = self; if (scalar->obval == NULL) { /* * Unicode may not have the representation available, `scalar_value` * ensures materialization. */ PyArray_Descr *descr = PyArray_DescrFromType(NPY_UNICODE); scalar_value(self, descr); Py_DECREF(descr); if (scalar->obval == NULL) { /* allocating memory failed */ Py_SETREF(view->obj, NULL); return -1; } } view->buf = scalar->obval; if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) { /* It is unnecessary to find the correct format */ view->format = NULL; return 0; } if (scalar->buffer_fmt != NULL) { view->format = scalar->buffer_fmt; } else { scalar->buffer_fmt = PyMem_Malloc(22); if (scalar->buffer_fmt == NULL) { Py_SETREF(view->obj, NULL); return -1; } PyOS_snprintf(scalar->buffer_fmt, 22, "%" NPY_INTP_FMT "w", length); view->format = scalar->buffer_fmt; } return 0; } static PyBufferProcs unicode_arrtype_as_buffer = { .bf_getbuffer = unicode_getbuffer, /* No need to release the buffer */ }; /**begin repeat * #name = datetime, timedelta# * #Name = Datetime, Timedelta# */ static int @name@_getbuffer(PyObject *self, Py_buffer *view, int flags) { if ((flags & PyBUF_WRITEABLE) == PyBUF_WRITEABLE) { PyErr_SetString(PyExc_BufferError, "scalar buffer is readonly"); return -1; } Py@Name@ScalarObject *scalar = (Py@Name@ScalarObject *)self; view->ndim = 1; view->len = 8; view->itemsize = 1; static Py_ssize_t length = 8; view->shape = &length; view->strides = NULL; view->suboffsets = NULL; view->readonly = 1; Py_INCREF(self); view->obj = self; view->buf = &(scalar->obval); if ((flags & PyBUF_FORMAT) != PyBUF_FORMAT) { /* It is unnecessary to find the correct format */ view->format = NULL; return 0; } /* export datetime scalars as bytes (although arrays are not exported) */ view->format = "B"; return 0; } static PyBufferProcs @name@_arrtype_as_buffer = { .bf_getbuffer = @name@_getbuffer, /* No need to release the buffer */ }; /**end repeat**/ static PyBufferProcs void_arrtype_as_buffer = { .bf_getbuffer = void_getbuffer, /* defined in buffer.c */ /* No need to release the buffer */ }; #define BASEFLAGS Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE #define LEAFFLAGS Py_TPFLAGS_DEFAULT NPY_NO_EXPORT PyTypeObject PyGenericArrType_Type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "numpy.generic", .tp_basicsize = sizeof(PyObject), }; static void void_dealloc(PyVoidScalarObject *v) { if (v->flags & NPY_ARRAY_OWNDATA) { npy_free_cache(v->obval, Py_SIZE(v)); } Py_XDECREF(v->descr); Py_XDECREF(v->base); if (_buffer_info_free(v->_buffer_info, (PyObject *)v) < 0) { PyErr_WriteUnraisable(NULL); } Py_TYPE(v)->tp_free(v); } static PyObject * object_arrtype_alloc(PyTypeObject *type, Py_ssize_t items) { /* * Object scalars should not actually exist, if they exist we should * consider it to be a bug. */ if (PyErr_WarnEx(npy_static_pydata.VisibleDeprecationWarning, "Creating a NumPy object scalar. NumPy object scalars should " "never be created. If you see this message please inform the " "NumPy developers. Since this message should never be shown " "this will raise a TypeError in the future.", 1) < 0) { return NULL; } return gentype_alloc(type, items); } static void object_arrtype_dealloc(PyObject *v) { Py_XDECREF(PyArrayScalar_VAL(v, Object)); Py_TYPE(v)->tp_free(v); } static void unicode_arrtype_dealloc(PyObject *v) { /* note: may be null if it was never requested */ PyMem_Free(PyArrayScalar_VAL(v, Unicode)); PyMem_Free(((PyUnicodeScalarObject *)v)->buffer_fmt); /* delegate to the base class */ PyUnicode_Type.tp_dealloc(v); } /**begin repeat * #name = byte, short, int, long, longlong, ubyte, ushort, uint, ulong, * ulonglong, half, float, double, longdouble, cfloat, cdouble, * clongdouble, string, unicode# * #Name = Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, ULong, * ULongLong, Half, Float, Double, LongDouble, CFloat, CDouble, * CLongDouble, String, Unicode# * #TYPE = BYTE, SHORT, INT, LONG, LONGLONG, UBYTE, USHORT, UINT, ULONG, * ULONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, * CLONGDOUBLE, STRING, UNICODE# */ /* used as a pattern for testing token equality */ #define _@TYPE@_IS_@TYPE@ static PyObject * @name@_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { /* allow base-class (if any) to do conversion */ #if defined(_@TYPE@_IS_UNICODE) PyObject *from_superclass = PyUnicode_Type.tp_new(type, args, kwds); #elif defined(_@TYPE@_IS_STRING) PyObject *from_superclass = PyBytes_Type.tp_new(type, args, kwds); #elif defined(_@TYPE@_IS_DOUBLE) PyObject *from_superclass = PyFloat_Type.tp_new(type, args, kwds); #endif #if defined(_@TYPE@_IS_UNICODE) || defined(_@TYPE@_IS_STRING) || defined(_@TYPE@_IS_DOUBLE) if (from_superclass == NULL) { /* don't clear the exception unless numpy can handle the arguments */ if (PyTuple_GET_SIZE(args) != 1 || (kwds && PyDict_Size(kwds) != 0)) { return NULL; } PyErr_Clear(); } else { #if defined(_@TYPE@_IS_UNICODE) PyArrayScalar_VAL(from_superclass, Unicode) = NULL; #endif return from_superclass; } #endif /* TODO: include type name in error message, which is not @name@ */ PyObject *obj = NULL; #if defined(_@TYPE@_IS_CDOUBLE) || defined(_@TYPE@_IS_CFLOAT) static char *kwnames[] = {"", "", NULL}; /* positional-only */ static char *parse_error = "Could not convert arguments into a complex scalar. '%R' given."; PyObject *real_obj = NULL; PyObject *imag_obj = NULL; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwnames, &real_obj, &imag_obj)) { return NULL; } if (!((imag_obj == NULL) || ((PyNumber_Check(real_obj) && PyNumber_Check(imag_obj)) && !(PyComplex_Check(real_obj) || PyComplex_Check(imag_obj))))) { PyErr_Format(PyExc_TypeError, parse_error, args); return NULL; } if (imag_obj == NULL) { obj = real_obj; Py_XINCREF(obj); } else { obj = PyObject_CallObject((PyObject *)&PyComplex_Type, args); if (obj == NULL) { return NULL; } } #else static char *kwnames[] = {"", NULL}; /* positional-only */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwnames, &obj)) { return NULL; } #endif // getting the typecode like this cannot fail PyArray_Descr *typecode = PyArray_DescrFromType(NPY_@TYPE@); if (obj == NULL) { PyObject *robj = PyArray_Scalar(NULL, typecode, NULL); Py_DECREF(typecode); if (robj == NULL) { return NULL; } #if !defined(_@TYPE@_IS_STRING) && !defined(_@TYPE@_IS_UNICODE) memset(&PyArrayScalar_VAL(robj, @Name@), 0, sizeof(npy_@name@)); #endif return robj; } /* PyArray_FromAny steals a reference, reclaim it before it's gone */ Py_INCREF(typecode); PyArrayObject *arr = (PyArrayObject *)PyArray_FromAny( obj, typecode, 0, 0, NPY_ARRAY_FORCECAST, NULL); #if defined(_@TYPE@_IS_CDOUBLE) || defined(_@TYPE@_IS_CFLOAT) Py_DECREF(obj); #endif if (arr == NULL) { Py_DECREF(typecode); return NULL; } if (PyArray_NDIM(arr) > 0) { Py_DECREF(typecode); return (PyObject *)arr; } /* Convert the 0-d array to a scalar*/ PyObject *robj = PyArray_ToScalar(PyArray_DATA(arr), arr); Py_DECREF(arr); if (robj == NULL || Py_TYPE(robj) == type) { Py_DECREF(typecode); return robj; } /* * `typecode` does not contain any subclass information, as it was thrown * out by the call to `PyArray_DescrFromType` - we need to add this back. * * FIXME[gh-15467]: This branch is also hit for the "shadowed" builtin * types like `longdouble` (which on platforms where they are the same size * is shadowed by `double`), because `PyArray_FromAny` returns the * shadowing type rather than the requested one. */ /* Need to allocate new type and copy data-area over */ int itemsize; if (type->tp_itemsize) { itemsize = PyBytes_GET_SIZE(robj); } else { itemsize = 0; } PyObject *new_obj = type->tp_alloc(type, itemsize); if (new_obj == NULL) { Py_DECREF(robj); Py_DECREF(typecode); return NULL; } void *dest = scalar_value(new_obj, typecode); void *src = scalar_value(robj, typecode); Py_DECREF(typecode); #if defined(_@TYPE@_IS_STRING) || defined(_@TYPE@_IS_UNICODE) if (itemsize == 0) { /* unicode */ itemsize = PyUnicode_GetLength(robj) * PyUnicode_KIND(robj); } memcpy(dest, src, itemsize); #else *((npy_@name@ *)dest) = *((npy_@name@ *)src); #endif Py_DECREF(robj); return new_obj; } #undef _@TYPE@_IS_@TYPE@ /**end repeat**/ static PyObject * object_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *kwds) { PyObject *obj = Py_None; static char *kwnames[] = {"", NULL}; /* positional-only */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:object_", kwnames, &obj)) { return NULL; } PyArray_Descr *typecode = PyArray_DescrFromType(NPY_OBJECT); if (typecode == NULL) { return NULL; } PyArrayObject *arr = (PyArrayObject *)PyArray_FromAny(obj, typecode, 0, 0, NPY_ARRAY_FORCECAST, NULL); return PyArray_Return(arr); } /**begin repeat * #name = datetime, timedelta# * #Name = Datetime, Timedelta# * #NAME = DATETIME, TIMEDELTA# * #is_datetime = 1, 0# */ static PyObject * @name@_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *obj = NULL, *meta_obj = NULL; Py@Name@ScalarObject *ret; static char *kwnames[] = {"", "", NULL}; /* positional-only */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwnames, &obj, &meta_obj)) { return NULL; } /* Allocate the return scalar */ ret = (Py@Name@ScalarObject *)Py@Name@ArrType_Type.tp_alloc( &Py@Name@ArrType_Type, 0); if (ret == NULL) { return NULL; } /* Incorporate the metadata if its provided */ if (meta_obj != NULL) { /* Parse the provided metadata input */ if (convert_pyobject_to_datetime_metadata(meta_obj, &ret->obmeta) < 0) { Py_DECREF(ret); return NULL; } } else { /* * A unit of -1 signals that convert_pyobject_to_datetime * should populate. */ ret->obmeta.base = -1; } if (obj == NULL) { if (ret->obmeta.base == -1) { ret->obmeta.base = NPY_DATETIME_DEFAULTUNIT; ret->obmeta.num = 1; } /* Make datetime default to NaT, timedelta default to zero */ #if @is_datetime@ ret->obval = NPY_DATETIME_NAT; #else ret->obval = 0; #endif } else if (convert_pyobject_to_@name@(&ret->obmeta, obj, NPY_SAME_KIND_CASTING, &ret->obval) < 0) { Py_DECREF(ret); return NULL; } return (PyObject *)ret; } /**end repeat**/ /* bool->tp_new only returns Py_True or Py_False */ static PyObject * bool_arrtype_new(PyTypeObject *NPY_UNUSED(type), PyObject *args, PyObject *kwds) { PyObject *obj = NULL; PyArrayObject *arr; static char *kwnames[] = {"", NULL}; /* positional-only */ if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:bool_", kwnames, &obj)) { return NULL; } if (obj == NULL) { PyArrayScalar_RETURN_FALSE; } if (obj == Py_False) { PyArrayScalar_RETURN_FALSE; } if (obj == Py_True) { PyArrayScalar_RETURN_TRUE; } arr = (PyArrayObject *)PyArray_FROM_OTF(obj, NPY_BOOL, NPY_ARRAY_FORCECAST); if (arr && 0 == PyArray_NDIM(arr)) { npy_bool val = *((npy_bool *)PyArray_DATA(arr)); Py_DECREF(arr); PyArrayScalar_RETURN_BOOL_FROM_LONG(val); } return PyArray_Return((PyArrayObject *)arr); } static PyObject * bool_arrtype_and(PyObject *a, PyObject *b) { if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) { PyArrayScalar_RETURN_BOOL_FROM_LONG ((a == PyArrayScalar_True) & (b == PyArrayScalar_True)); } return PyGenericArrType_Type.tp_as_number->nb_and(a, b); } static PyObject * bool_arrtype_or(PyObject *a, PyObject *b) { if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) { PyArrayScalar_RETURN_BOOL_FROM_LONG ((a == PyArrayScalar_True)|(b == PyArrayScalar_True)); } return PyGenericArrType_Type.tp_as_number->nb_or(a, b); } static PyObject * bool_arrtype_xor(PyObject *a, PyObject *b) { if (PyArray_IsScalar(a, Bool) && PyArray_IsScalar(b, Bool)) { PyArrayScalar_RETURN_BOOL_FROM_LONG ((a == PyArrayScalar_True)^(b == PyArrayScalar_True)); } return PyGenericArrType_Type.tp_as_number->nb_xor(a, b); } static int bool_arrtype_nonzero(PyObject *a) { return a == PyArrayScalar_True; } /**begin repeat * #name = byte, short, int, long, ubyte, ushort, longlong, uint, * ulong, ulonglong# * #Name = Byte, Short, Int, Long, UByte, UShort, LongLong, UInt, * ULong, ULongLong# * #type = PyLong_FromLong*6, PyLong_FromLongLong*1, * PyLong_FromUnsignedLong*2, PyLong_FromUnsignedLongLong# */ static PyNumberMethods @name@_arrtype_as_number; static PyObject * @name@_index(PyObject *self) { return @type@(PyArrayScalar_VAL(self, @Name@)); } /**end repeat**/ /**begin repeat * #name = half, float, double, longdouble, * cfloat, cdouble, clongdouble# * #NAME = Half, Float, Double, LongDouble, * CFloat, CDouble, CLongDouble# */ static PyNumberMethods @name@_arrtype_as_number; /**end repeat**/ /* Arithmetic methods -- only so we can override &, |, ^. */ NPY_NO_EXPORT PyNumberMethods bool_arrtype_as_number = { .nb_bool = (inquiry)bool_arrtype_nonzero, .nb_and = (binaryfunc)bool_arrtype_and, .nb_xor = (binaryfunc)bool_arrtype_xor, .nb_or = (binaryfunc)bool_arrtype_or, }; static PyObject * void_arrtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *obj, *arr; PyArray_Descr *descr = NULL; static char *kwnames[] = {"", "dtype", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|O&:void", kwnames, &obj, &PyArray_DescrConverter2, &descr)) { return NULL; } /* * For a VOID scalar first see if obj is an integer or long * and create new memory of that size (filled with 0) for the scalar */ if (descr == NULL && ( PyLong_Check(obj) || PyArray_IsScalar(obj, Integer) || (PyArray_Check(obj) && PyArray_NDIM((PyArrayObject *)obj)==0 && PyArray_ISINTEGER((PyArrayObject *)obj)))) { PyObject *length = Py_TYPE(obj)->tp_as_number->nb_int(obj); if (length == NULL) { return NULL; } PyObject *ret; char *destptr; npy_ulonglong memu = PyLong_AsUnsignedLongLong(length); Py_DECREF(length); if (PyErr_Occurred() || (memu > NPY_MAX_INT)) { PyErr_Clear(); PyErr_Format(PyExc_OverflowError, "size must be non-negative and not greater than %d", (int) NPY_MAX_INT); return NULL; } if (memu == 0) { memu = 1; } destptr = npy_alloc_cache_zero(memu, 1); if (destptr == NULL) { return PyErr_NoMemory(); } ret = type->tp_alloc(type, 0); if (ret == NULL) { npy_free_cache(destptr, memu); return PyErr_NoMemory(); } ((PyVoidScalarObject *)ret)->obval = destptr; Py_SET_SIZE((PyVoidScalarObject *)ret, (int) memu); ((PyVoidScalarObject *)ret)->flags = NPY_ARRAY_BEHAVED | NPY_ARRAY_OWNDATA; ((PyVoidScalarObject *)ret)->base = NULL; ((PyVoidScalarObject *)ret)->descr = (_PyArray_LegacyDescr *)PyArray_DescrNewFromType(NPY_VOID); if (((PyVoidScalarObject *)ret)->descr == NULL) { Py_DECREF(ret); return NULL; } ((PyVoidScalarObject *)ret)->descr->elsize = (int) memu; return ret; } if (descr == NULL) { /* Use the "size-less" void dtype to discover the size. */ descr = PyArray_DescrNewFromType(NPY_VOID); if (descr == NULL) { return NULL; } } else if (descr->type_num != NPY_VOID || PyDataType_HASSUBARRAY(descr)) { /* we reject subarrays, since subarray scalars do not exist. */ PyErr_Format(PyExc_TypeError, "void: descr must be a `void` dtype that is not " "a subarray dtype (structured or unstructured). " "Got '%.100R'.", descr); Py_DECREF(descr); return NULL; } arr = PyArray_FromAny(obj, descr, 0, 0, NPY_ARRAY_FORCECAST, NULL); return PyArray_Return((PyArrayObject *)arr); } /**************** Define Hash functions ********************/ /**begin repeat * #lname = bool, ubyte, ushort# * #name = Bool,UByte, UShort# */ static npy_hash_t @lname@_arrtype_hash(PyObject *obj) { return (npy_hash_t)(PyArrayScalar_VAL(obj, @name@)); } /**end repeat**/ /**begin repeat * #lname = byte, short, uint# * #name = Byte, Short, UInt# */ static npy_hash_t @lname@_arrtype_hash(PyObject *obj) { npy_hash_t x = (npy_hash_t)(PyArrayScalar_VAL(obj, @name@)); if (x == -1) { x = -2; } return x; } /**end repeat**/ static npy_hash_t ulong_arrtype_hash(PyObject *obj) { PyObject * l = PyLong_FromUnsignedLong(PyArrayScalar_VAL(obj, ULong)); npy_hash_t x = PyObject_Hash(l); Py_DECREF(l); return x; } static npy_hash_t int_arrtype_hash(PyObject *obj) { npy_hash_t x = (npy_hash_t)(PyArrayScalar_VAL(obj, Int)); if (x == -1) { x = -2; } return x; } static npy_hash_t long_arrtype_hash(PyObject *obj) { PyObject * l = PyLong_FromLong(PyArrayScalar_VAL(obj, Long)); npy_hash_t x = PyObject_Hash(l); Py_DECREF(l); return x; } /**begin repeat * #char = ,u# * #Char = ,U# * #Word = ,Unsigned# */ static inline npy_hash_t @char@longlong_arrtype_hash(PyObject *obj) { PyObject * l = PyLong_From@Word@LongLong( PyArrayScalar_VAL(obj, @Char@LongLong)); npy_hash_t x = PyObject_Hash(l); Py_DECREF(l); return x; } /**end repeat**/ /**begin repeat * #lname = datetime, timedelta# * #name = Datetime, Timedelta# */ static npy_hash_t @lname@_arrtype_hash(PyObject *obj) { PyArray_DatetimeMetaData *meta; PyArray_Descr *dtype; npy_@lname@ val = PyArrayScalar_VAL(obj, @name@); if (val == NPY_DATETIME_NAT) { /* Use identity, similar to NaN */ return PyBaseObject_Type.tp_hash(obj); } dtype = PyArray_DescrFromScalar(obj); meta = get_datetime_metadata_from_dtype(dtype); return @lname@_hash(meta, val); } /**end repeat**/ /* Wrong thing to do for longdouble, but....*/ /**begin repeat * #lname = float, longdouble# * #name = Float, LongDouble# * #NAME = FLOAT, LONGDOUBLE# * #n = f, l# */ static npy_hash_t @lname@_arrtype_hash(PyObject *obj) { return Npy_HashDouble(obj, (double)PyArrayScalar_VAL(obj, @name@)); } /* borrowed from complex_hash */ static npy_hash_t c@lname@_arrtype_hash(PyObject *obj) { npy_hash_t hashreal, hashimag, combined; hashreal = Npy_HashDouble( obj, (double)npy_creal@n@(PyArrayScalar_VAL(obj, C@name@))); if (hashreal == -1) { return -1; } hashimag = Npy_HashDouble( obj, (double)npy_cimag@n@(PyArrayScalar_VAL(obj, C@name@))); if (hashimag == -1) { return -1; } combined = hashreal + 1000003 * hashimag; if (combined == -1) { combined = -2; } return combined; } /**end repeat**/ static npy_hash_t half_arrtype_hash(PyObject *obj) { return Npy_HashDouble( obj, npy_half_to_double(PyArrayScalar_VAL(obj, Half))); } static npy_hash_t object_arrtype_hash(PyObject *obj) { return PyObject_Hash(PyArrayScalar_VAL(obj, Object)); } /* we used to just hash the pointer */ /* now use tuplehash algorithm using voidtype_item to get the object */ static npy_hash_t void_arrtype_hash(PyObject *obj) { npy_hash_t x, y; Py_ssize_t len, n; PyVoidScalarObject *p; PyObject *element; npy_hash_t mult = 1000003L; x = 0x345678L; p = (PyVoidScalarObject *)obj; /* Cannot hash mutable void scalars */ if (p->flags & NPY_ARRAY_WRITEABLE) { PyErr_SetString(PyExc_TypeError, "unhashable type: 'writeable void-scalar'"); return -1; } len = voidtype_length(p); for (n=0; n < len; n++) { element = voidtype_item(p, n); y = PyObject_Hash(element); Py_DECREF(element); if (y == -1) return -1; x = (x ^ y) * mult; mult += (npy_hash_t)(82520L + len + len); } x += 97531L; if (x == -1) x = -2; return x; } /*object arrtype getattro and setattro */ static PyObject * object_arrtype_getattro(PyObjectScalarObject *obj, PyObject *attr) { PyObject *res; /* first look in object and then hand off to generic type */ res = PyObject_GenericGetAttr(obj->obval, attr); if (res) { return res; } PyErr_Clear(); return PyObject_GenericGetAttr((PyObject *)obj, attr); } static int object_arrtype_setattro(PyObjectScalarObject *obj, PyObject *attr, PyObject *val) { int res; /* first look in object and then hand off to generic type */ res = PyObject_GenericSetAttr(obj->obval, attr, val); if (res >= 0) { return res; } PyErr_Clear(); return PyObject_GenericSetAttr((PyObject *)obj, attr, val); } static PyObject * object_arrtype_concat(PyObjectScalarObject *self, PyObject *other) { return PySequence_Concat(self->obval, other); } static Py_ssize_t object_arrtype_length(PyObjectScalarObject *self) { return PyObject_Length(self->obval); } static PyObject * object_arrtype_repeat(PyObjectScalarObject *self, Py_ssize_t count) { return PySequence_Repeat(self->obval, count); } static PyObject * object_arrtype_subscript(PyObjectScalarObject *self, PyObject *key) { return PyObject_GetItem(self->obval, key); } static int object_arrtype_ass_subscript(PyObjectScalarObject *self, PyObject *key, PyObject *value) { return PyObject_SetItem(self->obval, key, value); } static int object_arrtype_contains(PyObjectScalarObject *self, PyObject *ob) { return PySequence_Contains(self->obval, ob); } static PyObject * object_arrtype_inplace_concat(PyObjectScalarObject *self, PyObject *o) { return PySequence_InPlaceConcat(self->obval, o); } static PyObject * object_arrtype_inplace_repeat(PyObjectScalarObject *self, Py_ssize_t count) { return PySequence_InPlaceRepeat(self->obval, count); } static PySequenceMethods object_arrtype_as_sequence = { .sq_length = (lenfunc)object_arrtype_length, .sq_concat = (binaryfunc)object_arrtype_concat, .sq_repeat = (ssizeargfunc)object_arrtype_repeat, .sq_contains = (objobjproc)object_arrtype_contains, .sq_inplace_concat = (binaryfunc)object_arrtype_inplace_concat, .sq_inplace_repeat = (ssizeargfunc)object_arrtype_inplace_repeat, }; static PyMappingMethods object_arrtype_as_mapping = { .mp_length = (lenfunc)object_arrtype_length, .mp_subscript = (binaryfunc)object_arrtype_subscript, .mp_ass_subscript = (objobjargproc)object_arrtype_ass_subscript, }; static int object_arrtype_getbuffer(PyObjectScalarObject *self, Py_buffer *view, int flags) { PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; if (pb == NULL || pb->bf_getbuffer == NULL) { PyErr_SetString(PyExc_TypeError, "expected a readable buffer object"); return -1; } return (*pb->bf_getbuffer)(self->obval, view, flags); } static void object_arrtype_releasebuffer(PyObjectScalarObject *self, Py_buffer *view) { PyBufferProcs *pb = Py_TYPE(self->obval)->tp_as_buffer; if (pb == NULL) { PyErr_SetString(PyExc_TypeError, "expected a readable buffer object"); return; } if (pb->bf_releasebuffer != NULL) { (*pb->bf_releasebuffer)(self->obval, view); } } static PyBufferProcs object_arrtype_as_buffer = { .bf_getbuffer = (getbufferproc)object_arrtype_getbuffer, .bf_releasebuffer = (releasebufferproc)object_arrtype_releasebuffer, }; static PyObject * object_arrtype_call(PyObjectScalarObject *obj, PyObject *args, PyObject *kwds) { return PyObject_Call(obj->obval, args, kwds); } NPY_NO_EXPORT PyTypeObject PyObjectArrType_Type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "numpy." NPY_OBJECT_name, .tp_basicsize = sizeof(PyObjectScalarObject), .tp_dealloc = (destructor)object_arrtype_dealloc, .tp_as_sequence = &object_arrtype_as_sequence, .tp_as_mapping = &object_arrtype_as_mapping, .tp_call = (ternaryfunc)object_arrtype_call, .tp_getattro = (getattrofunc)object_arrtype_getattro, .tp_setattro = (setattrofunc)object_arrtype_setattro, .tp_as_buffer = &object_arrtype_as_buffer, .tp_alloc = object_arrtype_alloc, }; static PyObject * gen_arrtype_subscript(PyObject *self, PyObject *key) { /* * Only [...], [...,], [, ...], * is allowed for indexing a scalar * * These return a new N-d array with a copy of * the data where N is the number of None's in . */ PyObject *res, *ret; res = PyArray_FromScalar(self, NULL); ret = array_subscript((PyArrayObject *)res, key); Py_DECREF(res); if (ret == NULL) { PyErr_SetString(PyExc_IndexError, "invalid index to scalar variable."); } return ret; } /**begin repeat * #Name = Bool, * Byte, Short, Int, Long, LongLong, * UByte, UShort, UInt, ULong, ULongLong, * Half, Float, Double, LongDouble, * CFloat, CDouble, CLongDouble, * String, Unicode, Void, * Datetime, Timedelta# * #NAME = BOOL, * BYTE, SHORT, INT, LONG, LONGLONG, * UBYTE, USHORT, UINT, ULONG, ULONGLONG, * HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE, * STRING, UNICODE, VOID, * DATETIME, TIMEDELTA# */ NPY_NO_EXPORT PyTypeObject Py@Name@ArrType_Type = { PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "numpy." NPY_@NAME@_name, .tp_basicsize = sizeof(Py@Name@ScalarObject), }; /**end repeat**/ static PyMappingMethods gentype_as_mapping = { .mp_subscript = (binaryfunc)gen_arrtype_subscript, }; /* * This table maps the built-in type numbers to their scalar * type numbers. Note that signed integers are mapped to INTNEG_SCALAR, * which is different than what PyArray_ScalarKind returns. */ NPY_NO_EXPORT signed char _npy_scalar_kinds_table[NPY_NTYPES_LEGACY]; /* * This table maps a scalar kind (excluding NPY_NOSCALAR) * to the smallest type number of that kind. */ NPY_NO_EXPORT signed char _npy_smallest_type_of_kind_table[NPY_NSCALARKINDS]; /* * This table gives the type of the same kind, but next in the sequence * of sizes. */ NPY_NO_EXPORT signed char _npy_next_larger_type_table[NPY_NTYPES_LEGACY]; /* * This table gives the smallest-size and smallest-kind type to which * the input types may be safely cast, according to _npy_can_cast_safely. */ NPY_NO_EXPORT signed char _npy_type_promotion_table[NPY_NTYPES_LEGACY][NPY_NTYPES_LEGACY]; NPY_NO_EXPORT void initialize_casting_tables(void) { int i, j; _npy_smallest_type_of_kind_table[NPY_BOOL_SCALAR] = NPY_BOOL; _npy_smallest_type_of_kind_table[NPY_INTPOS_SCALAR] = NPY_UBYTE; _npy_smallest_type_of_kind_table[NPY_INTNEG_SCALAR] = NPY_BYTE; _npy_smallest_type_of_kind_table[NPY_FLOAT_SCALAR] = NPY_HALF; _npy_smallest_type_of_kind_table[NPY_COMPLEX_SCALAR] = NPY_CFLOAT; _npy_smallest_type_of_kind_table[NPY_OBJECT_SCALAR] = NPY_OBJECT; /* Default for built-in types is object scalar */ memset(_npy_scalar_kinds_table, NPY_OBJECT_SCALAR, sizeof(_npy_scalar_kinds_table)); /* Default for next largest type is -1, signalling no bigger */ memset(_npy_next_larger_type_table, -1, sizeof(_npy_next_larger_type_table)); /* Compile-time loop of scalar kinds */ /**begin repeat * #NAME = BOOL, * BYTE, UBYTE, SHORT, USHORT, INT, UINT, * LONG, ULONG, LONGLONG, ULONGLONG, * HALF, FLOAT, DOUBLE, LONGDOUBLE, * CFLOAT, CDOUBLE, CLONGDOUBLE# * #BIGGERTYPE = -1, * NPY_SHORT, NPY_USHORT, NPY_INT, NPY_UINT, NPY_LONG, NPY_ULONG, * NPY_LONGLONG, NPY_ULONGLONG, -1, -1, * NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE, -1, * NPY_CDOUBLE, NPY_CLONGDOUBLE, -1# * #SCKIND = BOOL, * (INTNEG, INTPOS)*5, * FLOAT*4, * COMPLEX*3# */ _npy_scalar_kinds_table[NPY_@NAME@] = NPY_@SCKIND@_SCALAR; _npy_next_larger_type_table[NPY_@NAME@] = @BIGGERTYPE@; /**end repeat**/ #undef _TO_NUM #undef _TO_BSIZE /**end repeat1**/ #undef _FROM_NUM #undef _FROM_BSIZE /**end repeat**/ /* * Now that the _can_cast_safely table is finished, we can * use it to build the _type_promotion table */ for (i = 0; i < NPY_NTYPES_LEGACY; ++i) { _npy_type_promotion_table[i][i] = i; /* Don't let number promote to string/unicode/void/datetime/timedelta */ if (i == NPY_STRING || i == NPY_UNICODE || i == NPY_VOID || i == NPY_DATETIME || i == NPY_TIMEDELTA) { /* Promoting these types requires examining their contents */ _npy_type_promotion_table[i][i] = -1; for (j = i + 1; j < NPY_NTYPES_LEGACY; ++j) { _npy_type_promotion_table[i][j] = -1; _npy_type_promotion_table[j][i] = -1; } /* Except they can convert to OBJECT */ _npy_type_promotion_table[i][NPY_OBJECT] = NPY_OBJECT; _npy_type_promotion_table[NPY_OBJECT][i] = NPY_OBJECT; } else { for (j = i + 1; j < NPY_NTYPES_LEGACY; ++j) { /* Don't let number promote to string/unicode/void */ if (j == NPY_STRING || j == NPY_UNICODE || j == NPY_VOID) { _npy_type_promotion_table[i][j] = -1; _npy_type_promotion_table[j][i] = -1; } else if (_npy_can_cast_safely_table[i][j]) { _npy_type_promotion_table[i][j] = j; _npy_type_promotion_table[j][i] = j; } else if (_npy_can_cast_safely_table[j][i]) { _npy_type_promotion_table[i][j] = i; _npy_type_promotion_table[j][i] = i; } else { int k, iskind, jskind, skind; iskind = _npy_scalar_kinds_table[i]; jskind = _npy_scalar_kinds_table[j]; /* If there's no kind (void/string/etc) */ if (iskind == NPY_NOSCALAR || jskind == NPY_NOSCALAR) { k = -1; } else { /* Start with the type of larger kind */ if (iskind > jskind) { skind = iskind; k = i; } else { skind = jskind; k = j; } for (;;) { /* Try the next larger type of this kind */ k = _npy_next_larger_type_table[k]; /* If there is no larger, try a larger kind */ if (k < 0) { ++skind; /* Use -1 to signal no promoted type found */ if (skind < NPY_NSCALARKINDS) { k = _npy_smallest_type_of_kind_table[skind]; } else { k = -1; break; } } if (_npy_can_cast_safely_table[i][k] && _npy_can_cast_safely_table[j][k]) { break; } } } _npy_type_promotion_table[i][j] = k; _npy_type_promotion_table[j][i] = k; } } } } } static PyNumberMethods longdoubletype_as_number; static PyNumberMethods clongdoubletype_as_number; static void init_basetypes(void); NPY_NO_EXPORT void initialize_numeric_types(void) { init_basetypes(); PyGenericArrType_Type.tp_dealloc = (destructor)gentype_dealloc; PyGenericArrType_Type.tp_as_number = &gentype_as_number; PyGenericArrType_Type.tp_as_mapping = &gentype_as_mapping; PyGenericArrType_Type.tp_flags = BASEFLAGS; PyGenericArrType_Type.tp_methods = gentype_methods; PyGenericArrType_Type.tp_getset = gentype_getsets; PyGenericArrType_Type.tp_new = NULL; PyGenericArrType_Type.tp_alloc = gentype_alloc; PyGenericArrType_Type.tp_free = (freefunc)gentype_free; PyGenericArrType_Type.tp_richcompare = gentype_richcompare; PyGenericArrType_Type.tp_as_buffer = &gentype_arrtype_as_buffer; PyBoolArrType_Type.tp_as_number = &bool_arrtype_as_number; /* * need to add dummy versions with filled-in nb_index * in-order for PyType_Ready to fill in .__index__() method * also fill array_type_as_number struct with reasonable defaults */ /**begin repeat * #name = byte, short, int, long, longlong, ubyte, ushort, * uint, ulong, ulonglong# * #NAME = Byte, Short, Int, Long, LongLong, UByte, UShort, * UInt, ULong, ULongLong# */ @name@_arrtype_as_number = gentype_as_number; Py@NAME@ArrType_Type.tp_as_number = &@name@_arrtype_as_number; Py@NAME@ArrType_Type.tp_as_number->nb_index = (unaryfunc)@name@_index; /**end repeat**/ /**begin repeat * #name = half, float, double, longdouble, * cfloat, cdouble, clongdouble# * #NAME = Half, Float, Double, LongDouble, * CFloat, CDouble, CLongDouble# */ @name@_arrtype_as_number = gentype_as_number; Py@NAME@ArrType_Type.tp_as_number = &@name@_arrtype_as_number; /**end repeat**/ PyStringArrType_Type.tp_alloc = NULL; PyStringArrType_Type.tp_free = NULL; PyStringArrType_Type.tp_repr = stringtype_repr; PyStringArrType_Type.tp_str = stringtype_str; PyUnicodeArrType_Type.tp_repr = unicodetype_repr; PyUnicodeArrType_Type.tp_str = unicodetype_str; PyVoidArrType_Type.tp_methods = voidtype_methods; PyVoidArrType_Type.tp_getset = voidtype_getsets; PyVoidArrType_Type.tp_as_mapping = &voidtype_as_mapping; PyVoidArrType_Type.tp_as_sequence = &voidtype_as_sequence; PyVoidArrType_Type.tp_repr = voidtype_repr; PyVoidArrType_Type.tp_str = voidtype_str; PyIntegerArrType_Type.tp_getset = inttype_getsets; PyNumberArrType_Type.tp_methods = numbertype_methods; /**begin repeat * #NAME= Number, Integer, SignedInteger, UnsignedInteger, Inexact, * Floating, ComplexFloating, Character# */ Py@NAME@ArrType_Type.tp_flags = BASEFLAGS; /**end repeat**/ /**begin repeat * #name = bool, byte, short, int, long, longlong, ubyte, ushort, uint, * ulong, ulonglong, half, float, double, longdouble, cfloat, * cdouble, clongdouble, string, unicode, void, object, datetime, * timedelta# * #NAME = Bool, Byte, Short, Int, Long, LongLong, UByte, UShort, UInt, * ULong, ULongLong, Half, Float, Double, LongDouble, CFloat, * CDouble, CLongDouble, String, Unicode, Void, Object, Datetime, * Timedelta# */ Py@NAME@ArrType_Type.tp_flags = BASEFLAGS; Py@NAME@ArrType_Type.tp_new = @name@_arrtype_new; Py@NAME@ArrType_Type.tp_richcompare = gentype_richcompare; #define _IS_@NAME@ /* inherit string buffer */ #if !defined(_IS_String) Py@NAME@ArrType_Type.tp_as_buffer = &@name@_arrtype_as_buffer; #endif #undef _IS_@NAME@ /**end repeat**/ PyUnicodeArrType_Type.tp_dealloc = unicode_arrtype_dealloc; /**begin repeat * #name = bool, byte, short, ubyte, ushort, uint, ulong, ulonglong, * half, float, longdouble, cfloat, clongdouble, void, object, * datetime, timedelta# * #NAME = Bool, Byte, Short, UByte, UShort, UInt, ULong, ULongLong, * Half, Float, LongDouble, CFloat, CLongDouble, Void, Object, * Datetime, Timedelta# */ Py@NAME@ArrType_Type.tp_hash = @name@_arrtype_hash; /**end repeat**/ /**begin repeat * #name = cfloat, clongdouble, floating, integer# * #NAME = CFloat, CLongDouble, Floating, Integer# */ Py@NAME@ArrType_Type.tp_methods = @name@type_methods; /**end repeat**/ /**begin repeat * #name = byte, short, int, long, longlong, * ubyte, ushort, uint, ulong, ulonglong# * #Name = Byte, Short, Int, Long, LongLong, * UByte, UShort, UInt, ULong, ULongLong# */ Py@Name@ArrType_Type.tp_methods = @name@type_methods; /**end repeat**/ /**begin repeat * #name = half, float, double, longdouble# * #Name = Half, Float, Double, LongDouble# */ Py@Name@ArrType_Type.tp_methods = @name@type_methods; /**end repeat**/ /**begin repeat * #name = byte, short, int, long, longlong, ubyte, ushort, * uint, ulong, ulonglong, timedelta, cdouble# * #Name = Byte, Short, Int, Long, LongLong, UByte, UShort, * UInt, ULong, ULongLong, Timedelta, CDouble# */ Py@Name@ArrType_Type.tp_methods = @name@type_methods; /**end repeat**/ /* We won't be inheriting from Python Int type. */ PyIntArrType_Type.tp_hash = int_arrtype_hash; /* We won't be inheriting from Python Int type. */ PyLongArrType_Type.tp_hash = long_arrtype_hash; /* We won't be inheriting from Python Int type. */ PyLongLongArrType_Type.tp_hash = longlong_arrtype_hash; /**begin repeat * #name = repr, str# */ PyHalfArrType_Type.tp_@name@ = halftype_@name@; PyFloatArrType_Type.tp_@name@ = floattype_@name@; PyCFloatArrType_Type.tp_@name@ = cfloattype_@name@; PyDoubleArrType_Type.tp_@name@ = doubletype_@name@; PyCDoubleArrType_Type.tp_@name@ = cdoubletype_@name@; PyDatetimeArrType_Type.tp_@name@ = datetimetype_@name@; PyTimedeltaArrType_Type.tp_@name@ = timedeltatype_@name@; /**end repeat**/ /**begin repeat * #Type = Byte, UByte, Short, UShort, Int, UInt, Long, * ULong, LongLong, ULongLong# */ Py@Type@ArrType_Type.tp_str = genint_type_str; Py@Type@ArrType_Type.tp_repr = genint_type_repr; /**end repeat**/ PyBoolArrType_Type.tp_str = genbool_type_str; PyBoolArrType_Type.tp_repr = genbool_type_repr; /**begin repeat * #char = ,c# * #CHAR = ,C# */ /* * These need to be coded specially because longdouble/clongdouble getitem * does not return a normal Python type */ @char@longdoubletype_as_number.nb_float = @char@longdoubletype_float; @char@longdoubletype_as_number.nb_int = @char@longdoubletype_long; Py@CHAR@LongDoubleArrType_Type.tp_as_number = &@char@longdoubletype_as_number; Py@CHAR@LongDoubleArrType_Type.tp_repr = @char@longdoubletype_repr; Py@CHAR@LongDoubleArrType_Type.tp_str = @char@longdoubletype_str; /**end repeat**/ PyStringArrType_Type.tp_itemsize = sizeof(char); PyVoidArrType_Type.tp_dealloc = (destructor) void_dealloc; PyArrayIter_Type.tp_iter = PyObject_SelfIter; PyArrayMapIter_Type.tp_iter = PyObject_SelfIter; } typedef struct { PyTypeObject * type; int typenum; } scalar_type; static scalar_type typeobjects[] = { {&PyBoolArrType_Type, NPY_BOOL}, {&PyByteArrType_Type, NPY_BYTE}, {&PyUByteArrType_Type, NPY_UBYTE}, {&PyShortArrType_Type, NPY_SHORT}, {&PyUShortArrType_Type, NPY_USHORT}, {&PyIntArrType_Type, NPY_INT}, {&PyUIntArrType_Type, NPY_UINT}, {&PyLongArrType_Type, NPY_LONG}, {&PyULongArrType_Type, NPY_ULONG}, {&PyLongLongArrType_Type, NPY_LONGLONG}, {&PyULongLongArrType_Type, NPY_ULONGLONG}, {&PyFloatArrType_Type, NPY_FLOAT}, {&PyDoubleArrType_Type, NPY_DOUBLE}, {&PyLongDoubleArrType_Type, NPY_LONGDOUBLE}, {&PyCFloatArrType_Type, NPY_CFLOAT}, {&PyCDoubleArrType_Type, NPY_CDOUBLE}, {&PyCLongDoubleArrType_Type, NPY_CLONGDOUBLE}, {&PyObjectArrType_Type, NPY_OBJECT}, {&PyStringArrType_Type, NPY_STRING}, {&PyUnicodeArrType_Type, NPY_UNICODE}, {&PyVoidArrType_Type, NPY_VOID}, {&PyDatetimeArrType_Type, NPY_DATETIME}, {&PyTimedeltaArrType_Type, NPY_TIMEDELTA}, {&PyHalfArrType_Type, NPY_HALF} }; static int compare_types(const void * a_, const void * b_) { const PyTypeObject * a = ((const scalar_type *)a_)->type; const PyTypeObject * b = ((const scalar_type *)b_)->type; if (a < b) { return -1; } else if (a > b) { return 1; } return 0; } static void init_basetypes(void) { qsort(typeobjects, sizeof(typeobjects) / sizeof(typeobjects[0]), sizeof(typeobjects[0]), compare_types); } NPY_NO_EXPORT int get_typeobj_idx(PyTypeObject * obj) { npy_intp imin = 0, imax = sizeof(typeobjects) / sizeof(typeobjects[0]) - 1; while (imax >= imin) { npy_intp imid = ((imax - imin) / 2) + imin; if(typeobjects[imid].type == obj) { return imid; } else if (typeobjects[imid].type < obj) { imin = imid + 1; } else { imax = imid - 1; } } return -1; } NPY_NO_EXPORT int is_anyscalar_exact(PyObject *obj) { return get_typeobj_idx(Py_TYPE(obj)) >= 0; } NPY_NO_EXPORT int _typenum_fromtypeobj(PyObject *type, int user) { int typenum, i; typenum = NPY_NOTYPE; i = get_typeobj_idx((PyTypeObject*)type); if (i >= 0) { typenum = typeobjects[i].typenum; } if (!user) { return typenum; } /* Search any registered types */ i = 0; while (i < NPY_NUMUSERTYPES) { if (type == (PyObject *)(userdescrs[i]->typeobj)) { typenum = i + NPY_USERDEF; break; } i++; } return typenum; }