jpayne@69: #ifndef Py_CPYTHON_ABSTRACTOBJECT_H jpayne@69: # error "this header file must not be included directly" jpayne@69: #endif jpayne@69: jpayne@69: #ifdef __cplusplus jpayne@69: extern "C" { jpayne@69: #endif jpayne@69: jpayne@69: /* === Object Protocol ================================================== */ jpayne@69: jpayne@69: #ifdef PY_SSIZE_T_CLEAN jpayne@69: # define _PyObject_CallMethodId _PyObject_CallMethodId_SizeT jpayne@69: #endif jpayne@69: jpayne@69: /* Convert keyword arguments from the FASTCALL (stack: C array, kwnames: tuple) jpayne@69: format to a Python dictionary ("kwargs" dict). jpayne@69: jpayne@69: The type of kwnames keys is not checked. The final function getting jpayne@69: arguments is responsible to check if all keys are strings, for example using jpayne@69: PyArg_ParseTupleAndKeywords() or PyArg_ValidateKeywordArguments(). jpayne@69: jpayne@69: Duplicate keys are merged using the last value. If duplicate keys must raise jpayne@69: an exception, the caller is responsible to implement an explicit keys on jpayne@69: kwnames. */ jpayne@69: PyAPI_FUNC(PyObject *) _PyStack_AsDict( jpayne@69: PyObject *const *values, jpayne@69: PyObject *kwnames); jpayne@69: jpayne@69: /* Convert (args, nargs, kwargs: dict) into a (stack, nargs, kwnames: tuple). jpayne@69: jpayne@69: Return 0 on success, raise an exception and return -1 on error. jpayne@69: jpayne@69: Write the new stack into *p_stack. If *p_stack is differen than args, it jpayne@69: must be released by PyMem_Free(). jpayne@69: jpayne@69: The stack uses borrowed references. jpayne@69: jpayne@69: The type of keyword keys is not checked, these checks should be done jpayne@69: later (ex: _PyArg_ParseStackAndKeywords). */ jpayne@69: PyAPI_FUNC(int) _PyStack_UnpackDict( jpayne@69: PyObject *const *args, jpayne@69: Py_ssize_t nargs, jpayne@69: PyObject *kwargs, jpayne@69: PyObject *const **p_stack, jpayne@69: PyObject **p_kwnames); jpayne@69: jpayne@69: /* Suggested size (number of positional arguments) for arrays of PyObject* jpayne@69: allocated on a C stack to avoid allocating memory on the heap memory. Such jpayne@69: array is used to pass positional arguments to call functions of the jpayne@69: _PyObject_Vectorcall() family. jpayne@69: jpayne@69: The size is chosen to not abuse the C stack and so limit the risk of stack jpayne@69: overflow. The size is also chosen to allow using the small stack for most jpayne@69: function calls of the Python standard library. On 64-bit CPU, it allocates jpayne@69: 40 bytes on the stack. */ jpayne@69: #define _PY_FASTCALL_SMALL_STACK 5 jpayne@69: jpayne@69: PyAPI_FUNC(PyObject *) _Py_CheckFunctionResult(PyObject *callable, jpayne@69: PyObject *result, jpayne@69: const char *where); jpayne@69: jpayne@69: /* === Vectorcall protocol (PEP 590) ============================= */ jpayne@69: jpayne@69: /* Call callable using tp_call. Arguments are like _PyObject_Vectorcall() jpayne@69: or _PyObject_FastCallDict() (both forms are supported), jpayne@69: except that nargs is plainly the number of arguments without flags. */ jpayne@69: PyAPI_FUNC(PyObject *) _PyObject_MakeTpCall( jpayne@69: PyObject *callable, jpayne@69: PyObject *const *args, Py_ssize_t nargs, jpayne@69: PyObject *keywords); jpayne@69: jpayne@69: #define PY_VECTORCALL_ARGUMENTS_OFFSET ((size_t)1 << (8 * sizeof(size_t) - 1)) jpayne@69: jpayne@69: static inline Py_ssize_t jpayne@69: PyVectorcall_NARGS(size_t n) jpayne@69: { jpayne@69: return n & ~PY_VECTORCALL_ARGUMENTS_OFFSET; jpayne@69: } jpayne@69: jpayne@69: static inline vectorcallfunc jpayne@69: _PyVectorcall_Function(PyObject *callable) jpayne@69: { jpayne@69: PyTypeObject *tp = Py_TYPE(callable); jpayne@69: Py_ssize_t offset = tp->tp_vectorcall_offset; jpayne@69: vectorcallfunc *ptr; jpayne@69: if (!PyType_HasFeature(tp, _Py_TPFLAGS_HAVE_VECTORCALL)) { jpayne@69: return NULL; jpayne@69: } jpayne@69: assert(PyCallable_Check(callable)); jpayne@69: assert(offset > 0); jpayne@69: ptr = (vectorcallfunc*)(((char *)callable) + offset); jpayne@69: return *ptr; jpayne@69: } jpayne@69: jpayne@69: /* Call the callable object 'callable' with the "vectorcall" calling jpayne@69: convention. jpayne@69: jpayne@69: args is a C array for positional arguments. jpayne@69: jpayne@69: nargsf is the number of positional arguments plus optionally the flag jpayne@69: PY_VECTORCALL_ARGUMENTS_OFFSET which means that the caller is allowed to jpayne@69: modify args[-1]. jpayne@69: jpayne@69: kwnames is a tuple of keyword names. The values of the keyword arguments jpayne@69: are stored in "args" after the positional arguments (note that the number jpayne@69: of keyword arguments does not change nargsf). kwnames can also be NULL if jpayne@69: there are no keyword arguments. jpayne@69: jpayne@69: keywords must only contains str strings (no subclass), and all keys must jpayne@69: be unique. jpayne@69: jpayne@69: Return the result on success. Raise an exception and return NULL on jpayne@69: error. */ jpayne@69: static inline PyObject * jpayne@69: _PyObject_Vectorcall(PyObject *callable, PyObject *const *args, jpayne@69: size_t nargsf, PyObject *kwnames) jpayne@69: { jpayne@69: PyObject *res; jpayne@69: vectorcallfunc func; jpayne@69: assert(kwnames == NULL || PyTuple_Check(kwnames)); jpayne@69: assert(args != NULL || PyVectorcall_NARGS(nargsf) == 0); jpayne@69: func = _PyVectorcall_Function(callable); jpayne@69: if (func == NULL) { jpayne@69: Py_ssize_t nargs = PyVectorcall_NARGS(nargsf); jpayne@69: return _PyObject_MakeTpCall(callable, args, nargs, kwnames); jpayne@69: } jpayne@69: res = func(callable, args, nargsf, kwnames); jpayne@69: return _Py_CheckFunctionResult(callable, res, NULL); jpayne@69: } jpayne@69: jpayne@69: /* Same as _PyObject_Vectorcall except that keyword arguments are passed as jpayne@69: dict, which may be NULL if there are no keyword arguments. */ jpayne@69: PyAPI_FUNC(PyObject *) _PyObject_FastCallDict( jpayne@69: PyObject *callable, jpayne@69: PyObject *const *args, jpayne@69: size_t nargsf, jpayne@69: PyObject *kwargs); jpayne@69: jpayne@69: /* Call "callable" (which must support vectorcall) with positional arguments jpayne@69: "tuple" and keyword arguments "dict". "dict" may also be NULL */ jpayne@69: PyAPI_FUNC(PyObject *) PyVectorcall_Call(PyObject *callable, PyObject *tuple, PyObject *dict); jpayne@69: jpayne@69: /* Same as _PyObject_Vectorcall except without keyword arguments */ jpayne@69: static inline PyObject * jpayne@69: _PyObject_FastCall(PyObject *func, PyObject *const *args, Py_ssize_t nargs) jpayne@69: { jpayne@69: return _PyObject_Vectorcall(func, args, (size_t)nargs, NULL); jpayne@69: } jpayne@69: jpayne@69: /* Call a callable without any arguments */ jpayne@69: static inline PyObject * jpayne@69: _PyObject_CallNoArg(PyObject *func) { jpayne@69: return _PyObject_Vectorcall(func, NULL, 0, NULL); jpayne@69: } jpayne@69: jpayne@69: PyAPI_FUNC(PyObject *) _PyObject_Call_Prepend( jpayne@69: PyObject *callable, jpayne@69: PyObject *obj, jpayne@69: PyObject *args, jpayne@69: PyObject *kwargs); jpayne@69: jpayne@69: PyAPI_FUNC(PyObject *) _PyObject_FastCall_Prepend( jpayne@69: PyObject *callable, jpayne@69: PyObject *obj, jpayne@69: PyObject *const *args, jpayne@69: Py_ssize_t nargs); jpayne@69: jpayne@69: /* Like PyObject_CallMethod(), but expect a _Py_Identifier* jpayne@69: as the method name. */ jpayne@69: PyAPI_FUNC(PyObject *) _PyObject_CallMethodId(PyObject *obj, jpayne@69: _Py_Identifier *name, jpayne@69: const char *format, ...); jpayne@69: jpayne@69: PyAPI_FUNC(PyObject *) _PyObject_CallMethodId_SizeT(PyObject *obj, jpayne@69: _Py_Identifier *name, jpayne@69: const char *format, jpayne@69: ...); jpayne@69: jpayne@69: PyAPI_FUNC(PyObject *) _PyObject_CallMethodIdObjArgs( jpayne@69: PyObject *obj, jpayne@69: struct _Py_Identifier *name, jpayne@69: ...); jpayne@69: jpayne@69: PyAPI_FUNC(int) _PyObject_HasLen(PyObject *o); jpayne@69: jpayne@69: /* Guess the size of object 'o' using len(o) or o.__length_hint__(). jpayne@69: If neither of those return a non-negative value, then return the default jpayne@69: value. If one of the calls fails, this function returns -1. */ jpayne@69: PyAPI_FUNC(Py_ssize_t) PyObject_LengthHint(PyObject *o, Py_ssize_t); jpayne@69: jpayne@69: /* === New Buffer API ============================================ */ jpayne@69: jpayne@69: /* Return 1 if the getbuffer function is available, otherwise return 0. */ jpayne@69: #define PyObject_CheckBuffer(obj) \ jpayne@69: (((obj)->ob_type->tp_as_buffer != NULL) && \ jpayne@69: ((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL)) jpayne@69: jpayne@69: /* This is a C-API version of the getbuffer function call. It checks jpayne@69: to make sure object has the required function pointer and issues the jpayne@69: call. jpayne@69: jpayne@69: Returns -1 and raises an error on failure and returns 0 on success. */ jpayne@69: PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view, jpayne@69: int flags); jpayne@69: jpayne@69: /* Get the memory area pointed to by the indices for the buffer given. jpayne@69: Note that view->ndim is the assumed size of indices. */ jpayne@69: PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices); jpayne@69: jpayne@69: /* Return the implied itemsize of the data-format area from a jpayne@69: struct-style description. */ jpayne@69: PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *); jpayne@69: jpayne@69: /* Implementation in memoryobject.c */ jpayne@69: PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view, jpayne@69: Py_ssize_t len, char order); jpayne@69: jpayne@69: PyAPI_FUNC(int) PyBuffer_FromContiguous(Py_buffer *view, void *buf, jpayne@69: Py_ssize_t len, char order); jpayne@69: jpayne@69: /* Copy len bytes of data from the contiguous chunk of memory jpayne@69: pointed to by buf into the buffer exported by obj. Return jpayne@69: 0 on success and return -1 and raise a PyBuffer_Error on jpayne@69: error (i.e. the object does not have a buffer interface or jpayne@69: it is not working). jpayne@69: jpayne@69: If fort is 'F', then if the object is multi-dimensional, jpayne@69: then the data will be copied into the array in jpayne@69: Fortran-style (first dimension varies the fastest). If jpayne@69: fort is 'C', then the data will be copied into the array jpayne@69: in C-style (last dimension varies the fastest). If fort jpayne@69: is 'A', then it does not matter and the copy will be made jpayne@69: in whatever way is more efficient. */ jpayne@69: PyAPI_FUNC(int) PyObject_CopyData(PyObject *dest, PyObject *src); jpayne@69: jpayne@69: /* Copy the data from the src buffer to the buffer of destination. */ jpayne@69: PyAPI_FUNC(int) PyBuffer_IsContiguous(const Py_buffer *view, char fort); jpayne@69: jpayne@69: /*Fill the strides array with byte-strides of a contiguous jpayne@69: (Fortran-style if fort is 'F' or C-style otherwise) jpayne@69: array of the given shape with the given number of bytes jpayne@69: per element. */ jpayne@69: PyAPI_FUNC(void) PyBuffer_FillContiguousStrides(int ndims, jpayne@69: Py_ssize_t *shape, jpayne@69: Py_ssize_t *strides, jpayne@69: int itemsize, jpayne@69: char fort); jpayne@69: jpayne@69: /* Fills in a buffer-info structure correctly for an exporter jpayne@69: that can only share a contiguous chunk of memory of jpayne@69: "unsigned bytes" of the given length. jpayne@69: jpayne@69: Returns 0 on success and -1 (with raising an error) on error. */ jpayne@69: PyAPI_FUNC(int) PyBuffer_FillInfo(Py_buffer *view, PyObject *o, void *buf, jpayne@69: Py_ssize_t len, int readonly, jpayne@69: int flags); jpayne@69: jpayne@69: /* Releases a Py_buffer obtained from getbuffer ParseTuple's "s*". */ jpayne@69: PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); jpayne@69: jpayne@69: /* ==== Iterators ================================================ */ jpayne@69: jpayne@69: #define PyIter_Check(obj) \ jpayne@69: ((obj)->ob_type->tp_iternext != NULL && \ jpayne@69: (obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented) jpayne@69: jpayne@69: /* === Number Protocol ================================================== */ jpayne@69: jpayne@69: #define PyIndex_Check(obj) \ jpayne@69: ((obj)->ob_type->tp_as_number != NULL && \ jpayne@69: (obj)->ob_type->tp_as_number->nb_index != NULL) jpayne@69: jpayne@69: /* === Sequence protocol ================================================ */ jpayne@69: jpayne@69: /* Assume tp_as_sequence and sq_item exist and that 'i' does not jpayne@69: need to be corrected for a negative index. */ jpayne@69: #define PySequence_ITEM(o, i)\ jpayne@69: ( Py_TYPE(o)->tp_as_sequence->sq_item(o, i) ) jpayne@69: jpayne@69: #define PY_ITERSEARCH_COUNT 1 jpayne@69: #define PY_ITERSEARCH_INDEX 2 jpayne@69: #define PY_ITERSEARCH_CONTAINS 3 jpayne@69: jpayne@69: /* Iterate over seq. jpayne@69: jpayne@69: Result depends on the operation: jpayne@69: jpayne@69: PY_ITERSEARCH_COUNT: return # of times obj appears in seq; -1 if jpayne@69: error. jpayne@69: PY_ITERSEARCH_INDEX: return 0-based index of first occurrence of jpayne@69: obj in seq; set ValueError and return -1 if none found; jpayne@69: also return -1 on error. jpayne@69: PY_ITERSEARCH_CONTAINS: return 1 if obj in seq, else 0; -1 on jpayne@69: error. */ jpayne@69: PyAPI_FUNC(Py_ssize_t) _PySequence_IterSearch(PyObject *seq, jpayne@69: PyObject *obj, int operation); jpayne@69: jpayne@69: /* === Mapping protocol ================================================= */ jpayne@69: jpayne@69: PyAPI_FUNC(int) _PyObject_RealIsInstance(PyObject *inst, PyObject *cls); jpayne@69: jpayne@69: PyAPI_FUNC(int) _PyObject_RealIsSubclass(PyObject *derived, PyObject *cls); jpayne@69: jpayne@69: PyAPI_FUNC(char *const *) _PySequence_BytesToCharpArray(PyObject* self); jpayne@69: jpayne@69: PyAPI_FUNC(void) _Py_FreeCharPArray(char *const array[]); jpayne@69: jpayne@69: /* For internal use by buffer API functions */ jpayne@69: PyAPI_FUNC(void) _Py_add_one_to_index_F(int nd, Py_ssize_t *index, jpayne@69: const Py_ssize_t *shape); jpayne@69: PyAPI_FUNC(void) _Py_add_one_to_index_C(int nd, Py_ssize_t *index, jpayne@69: const Py_ssize_t *shape); jpayne@69: jpayne@69: /* Convert Python int to Py_ssize_t. Do nothing if the argument is None. */ jpayne@69: PyAPI_FUNC(int) _Py_convert_optional_to_ssize_t(PyObject *, void *); jpayne@69: jpayne@69: #ifdef __cplusplus jpayne@69: } jpayne@69: #endif