cpython/Objects/abstract.c

/* Abstract Object Interface (many thanks to Jim Fulton) */

#include "Python.h"
#include "pycore_abstract.h"      // _PyIndex_Check()
#include "pycore_pybuffer.h"
#include "pycore_call.h"          // _PyObject_CallNoArgs()
#include "pycore_ceval.h"         // _Py_EnterRecursiveCallTstate()
#include "pycore_crossinterp.h"   // _Py_CallInInterpreter()
#include "pycore_object.h"        // _Py_CheckSlotResult()
#include "pycore_long.h"          // _Py_IsNegative
#include "pycore_pyerrors.h"      // _PyErr_Occurred()
#include "pycore_pystate.h"       // _PyThreadState_GET()
#include "pycore_unionobject.h"   // _PyUnion_Check()

#include <stddef.h>               // offsetof()


/* Shorthands to return certain errors */

static PyObject *
type_error(const char *msg, PyObject *obj)
{}

static PyObject *
null_error(void)
{}

/* Operations on any object */

PyObject *
PyObject_Type(PyObject *o)
{}

Py_ssize_t
PyObject_Size(PyObject *o)
{}

#undef PyObject_Length
Py_ssize_t
PyObject_Length(PyObject *o)
{}
#define PyObject_Length

int
_PyObject_HasLen(PyObject *o) {}

/* The length hint function returns a non-negative value from o.__len__()
   or o.__length_hint__(). If those methods aren't found the defaultvalue is
   returned.  If one of the calls fails with an exception other than TypeError
   this function returns -1.
*/

Py_ssize_t
PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
{}

PyObject *
PyObject_GetItem(PyObject *o, PyObject *key)
{}

int
PyMapping_GetOptionalItem(PyObject *obj, PyObject *key, PyObject **result)
{}

int
PyObject_SetItem(PyObject *o, PyObject *key, PyObject *value)
{}

int
PyObject_DelItem(PyObject *o, PyObject *key)
{}

int
PyObject_DelItemString(PyObject *o, const char *key)
{}


/* Return 1 if the getbuffer function is available, otherwise return 0. */
int
PyObject_CheckBuffer(PyObject *obj)
{}

// Old buffer protocols (deprecated, abi only)

/* Checks whether an arbitrary object supports the (character, single segment)
   buffer interface.

   Returns 1 on success, 0 on failure.

   We release the buffer right after use of this function which could
   cause issues later on.  Don't use these functions in new code.
 */
PyAPI_FUNC(int) /* abi_only */
PyObject_CheckReadBuffer(PyObject *obj)
{}

static int
as_read_buffer(PyObject *obj, const void **buffer, Py_ssize_t *buffer_len)
{}

/* Takes an arbitrary object which must support the (character, single segment)
   buffer interface and returns a pointer to a read-only memory location
   usable as character based input for subsequent processing.

   Return 0 on success.  buffer and buffer_len are only set in case no error
   occurs. Otherwise, -1 is returned and an exception set. */
PyAPI_FUNC(int) /* abi_only */
PyObject_AsCharBuffer(PyObject *obj,
                      const char **buffer,
                      Py_ssize_t *buffer_len)
{}

/* Same as PyObject_AsCharBuffer() except that this API expects (readable,
   single segment) buffer interface and returns a pointer to a read-only memory
   location which can contain arbitrary data.

   0 is returned on success.  buffer and buffer_len are only set in case no
   error occurs.  Otherwise, -1 is returned and an exception set. */
PyAPI_FUNC(int) /* abi_only */
PyObject_AsReadBuffer(PyObject *obj,
                      const void **buffer,
                      Py_ssize_t *buffer_len)
{}

/* Takes an arbitrary object which must support the (writable, single segment)
   buffer interface and returns a pointer to a writable memory location in
   buffer of size 'buffer_len'.

   Return 0 on success.  buffer and buffer_len are only set in case no error
   occurs. Otherwise, -1 is returned and an exception set. */
PyAPI_FUNC(int) /* abi_only */
PyObject_AsWriteBuffer(PyObject *obj,
                       void **buffer,
                       Py_ssize_t *buffer_len)
{}

/* Buffer C-API for Python 3.0 */

int
PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags)
{}

static int
_IsFortranContiguous(const Py_buffer *view)
{}

static int
_IsCContiguous(const Py_buffer *view)
{}

int
PyBuffer_IsContiguous(const Py_buffer *view, char order)
{}


void*
PyBuffer_GetPointer(const Py_buffer *view, const Py_ssize_t *indices)
{}


static void
_Py_add_one_to_index_F(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
{}

static void
_Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
{}

Py_ssize_t
PyBuffer_SizeFromFormat(const char *format)
{}

int
PyBuffer_FromContiguous(const Py_buffer *view, const void *buf, Py_ssize_t len, char fort)
{}

int PyObject_CopyData(PyObject *dest, PyObject *src)
{}

void
PyBuffer_FillContiguousStrides(int nd, Py_ssize_t *shape,
                               Py_ssize_t *strides, int itemsize,
                               char fort)
{}

int
PyBuffer_FillInfo(Py_buffer *view, PyObject *obj, void *buf, Py_ssize_t len,
                  int readonly, int flags)
{}

void
PyBuffer_Release(Py_buffer *view)
{}

static int
_buffer_release_call(void *arg)
{}

int
_PyBuffer_ReleaseInInterpreter(PyInterpreterState *interp,
                               Py_buffer *view)
{}

int
_PyBuffer_ReleaseInInterpreterAndRawFree(PyInterpreterState *interp,
                                         Py_buffer *view)
{}

PyObject *
PyObject_Format(PyObject *obj, PyObject *format_spec)
{}
/* Operations on numbers */

int
PyNumber_Check(PyObject *o)
{}

/* Binary operators */

#define NB_SLOT(x)
#define NB_BINOP(nb_methods, slot)
#define NB_TERNOP(nb_methods, slot)

/*
  Calling scheme used for binary operations:

  Order operations are tried until either a valid result or error:
    w.op(v,w)[*], v.op(v,w), w.op(v,w)

  [*] only when Py_TYPE(v) != Py_TYPE(w) && Py_TYPE(w) is a subclass of
      Py_TYPE(v)
 */

static PyObject *
binary_op1(PyObject *v, PyObject *w, const int op_slot
#ifndef NDEBUG
           , const char *op_name
#endif
           )
{}

#ifdef NDEBUG
#define BINARY_OP1(v, w, op_slot, op_name)
#else
#define BINARY_OP1
#endif

static PyObject *
binop_type_error(PyObject *v, PyObject *w, const char *op_name)
{}

static PyObject *
binary_op(PyObject *v, PyObject *w, const int op_slot, const char *op_name)
{}


/*
  Calling scheme used for ternary operations:

  Order operations are tried until either a valid result or error:
    v.op(v,w,z), w.op(v,w,z), z.op(v,w,z)
 */

static PyObject *
ternary_op(PyObject *v,
           PyObject *w,
           PyObject *z,
           const int op_slot,
           const char *op_name
           )
{}

#define BINARY_FUNC(func, op, op_name)

BINARY_FUNC(PyNumber_Or, nb_or, "|")
BINARY_FUNC(PyNumber_Xor, nb_xor, "^")
BINARY_FUNC(PyNumber_And, nb_and, "&")
BINARY_FUNC(PyNumber_Lshift, nb_lshift, "<<")
BINARY_FUNC(PyNumber_Rshift, nb_rshift, ">>")
BINARY_FUNC(PyNumber_Subtract, nb_subtract, "-")
BINARY_FUNC(PyNumber_Divmod, nb_divmod, "divmod()")

PyObject *
PyNumber_Add(PyObject *v, PyObject *w)
{}

static PyObject *
sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n)
{}

PyObject *
PyNumber_Multiply(PyObject *v, PyObject *w)
{}

BINARY_FUNC(PyNumber_MatrixMultiply, nb_matrix_multiply, "@")
BINARY_FUNC(PyNumber_FloorDivide, nb_floor_divide, "//")
BINARY_FUNC(PyNumber_TrueDivide, nb_true_divide, "/")
BINARY_FUNC(PyNumber_Remainder, nb_remainder, "%")

PyObject *
PyNumber_Power(PyObject *v, PyObject *w, PyObject *z)
{}

PyObject *
_PyNumber_PowerNoMod(PyObject *lhs, PyObject *rhs)
{}

/* Binary in-place operators */

/* The in-place operators are defined to fall back to the 'normal',
   non in-place operations, if the in-place methods are not in place.

   - If the left hand object has the appropriate struct members, and
     they are filled, call the appropriate function and return the
     result.  No coercion is done on the arguments; the left-hand object
     is the one the operation is performed on, and it's up to the
     function to deal with the right-hand object.

   - Otherwise, in-place modification is not supported. Handle it exactly as
     a non in-place operation of the same kind.

   */

static PyObject *
binary_iop1(PyObject *v, PyObject *w, const int iop_slot, const int op_slot
#ifndef NDEBUG
            , const char *op_name
#endif
            )
{}

#ifdef NDEBUG
#define BINARY_IOP1(v, w, iop_slot, op_slot, op_name)
#else
#define BINARY_IOP1
#endif

static PyObject *
binary_iop(PyObject *v, PyObject *w, const int iop_slot, const int op_slot,
                const char *op_name)
{}

static PyObject *
ternary_iop(PyObject *v, PyObject *w, PyObject *z, const int iop_slot, const int op_slot,
                const char *op_name)
{}

#define INPLACE_BINOP(func, iop, op, op_name)

INPLACE_BINOP(PyNumber_InPlaceOr, nb_inplace_or, nb_or, "|=")
INPLACE_BINOP(PyNumber_InPlaceXor, nb_inplace_xor, nb_xor, "^=")
INPLACE_BINOP(PyNumber_InPlaceAnd, nb_inplace_and, nb_and, "&=")
INPLACE_BINOP(PyNumber_InPlaceLshift, nb_inplace_lshift, nb_lshift, "<<=")
INPLACE_BINOP(PyNumber_InPlaceRshift, nb_inplace_rshift, nb_rshift, ">>=")
INPLACE_BINOP(PyNumber_InPlaceSubtract, nb_inplace_subtract, nb_subtract, "-=")
INPLACE_BINOP(PyNumber_InPlaceMatrixMultiply, nb_inplace_matrix_multiply, nb_matrix_multiply, "@=")
INPLACE_BINOP(PyNumber_InPlaceFloorDivide, nb_inplace_floor_divide, nb_floor_divide, "//=")
INPLACE_BINOP(PyNumber_InPlaceTrueDivide, nb_inplace_true_divide, nb_true_divide,  "/=")
INPLACE_BINOP(PyNumber_InPlaceRemainder, nb_inplace_remainder, nb_remainder, "%=")

PyObject *
PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
{}

PyObject *
PyNumber_InPlaceMultiply(PyObject *v, PyObject *w)
{}

PyObject *
PyNumber_InPlacePower(PyObject *v, PyObject *w, PyObject *z)
{}

PyObject *
_PyNumber_InPlacePowerNoMod(PyObject *lhs, PyObject *rhs)
{}


/* Unary operators and functions */

#define UNARY_FUNC(func, op, meth_name, descr)

UNARY_FUNC()
UNARY_FUNC()
UNARY_FUNC()
UNARY_FUNC()


int
PyIndex_Check(PyObject *obj)
{}


/* Return a Python int from the object item.
   Can return an instance of int subclass.
   Raise TypeError if the result is not an int
   or if the object cannot be interpreted as an index.
*/
PyObject *
_PyNumber_Index(PyObject *item)
{}

/* Return an exact Python int from the object item.
   Raise TypeError if the result is not an int
   or if the object cannot be interpreted as an index.
*/
PyObject *
PyNumber_Index(PyObject *item)
{}

/* Return an error on Overflow only if err is not NULL*/

Py_ssize_t
PyNumber_AsSsize_t(PyObject *item, PyObject *err)
{}


PyObject *
PyNumber_Long(PyObject *o)
{}

PyObject *
PyNumber_Float(PyObject *o)
{}


PyObject *
PyNumber_ToBase(PyObject *n, int base)
{}


/* Operations on sequences */

int
PySequence_Check(PyObject *s)
{}

Py_ssize_t
PySequence_Size(PyObject *s)
{}

#undef PySequence_Length
Py_ssize_t
PySequence_Length(PyObject *s)
{}
#define PySequence_Length

PyObject *
PySequence_Concat(PyObject *s, PyObject *o)
{}

PyObject *
PySequence_Repeat(PyObject *o, Py_ssize_t count)
{}

PyObject *
PySequence_InPlaceConcat(PyObject *s, PyObject *o)
{}

PyObject *
PySequence_InPlaceRepeat(PyObject *o, Py_ssize_t count)
{}

PyObject *
PySequence_GetItem(PyObject *s, Py_ssize_t i)
{}

PyObject *
PySequence_GetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2)
{}

int
PySequence_SetItem(PyObject *s, Py_ssize_t i, PyObject *o)
{}

int
PySequence_DelItem(PyObject *s, Py_ssize_t i)
{}

int
PySequence_SetSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2, PyObject *o)
{}

int
PySequence_DelSlice(PyObject *s, Py_ssize_t i1, Py_ssize_t i2)
{}

PyObject *
PySequence_Tuple(PyObject *v)
{}

PyObject *
PySequence_List(PyObject *v)
{}

PyObject *
PySequence_Fast(PyObject *v, const char *m)
{}

/* Iterate over seq.  Result depends on the operation:
   PY_ITERSEARCH_COUNT:  -1 if error, else # of times obj appears in seq.
   PY_ITERSEARCH_INDEX:  0-based index of first occurrence of obj in seq;
    set ValueError and return -1 if none found; also return -1 on error.
   PY_ITERSEARCH_CONTAINS:  return 1 if obj in seq, else 0; -1 on error.
*/
Py_ssize_t
_PySequence_IterSearch(PyObject *seq, PyObject *obj, int operation)
{}

/* Return # of times o appears in s. */
Py_ssize_t
PySequence_Count(PyObject *s, PyObject *o)
{}

/* Return -1 if error; 1 if ob in seq; 0 if ob not in seq.
 * Use sq_contains if possible, else defer to _PySequence_IterSearch().
 */
int
PySequence_Contains(PyObject *seq, PyObject *ob)
{}

/* Backwards compatibility */
#undef PySequence_In
int
PySequence_In(PyObject *w, PyObject *v)
{}

Py_ssize_t
PySequence_Index(PyObject *s, PyObject *o)
{}

/* Operations on mappings */

int
PyMapping_Check(PyObject *o)
{}

Py_ssize_t
PyMapping_Size(PyObject *o)
{}

#undef PyMapping_Length
Py_ssize_t
PyMapping_Length(PyObject *o)
{}
#define PyMapping_Length

PyObject *
PyMapping_GetItemString(PyObject *o, const char *key)
{}

int
PyMapping_GetOptionalItemString(PyObject *obj, const char *key, PyObject **result)
{}

int
PyMapping_SetItemString(PyObject *o, const char *key, PyObject *value)
{}

int
PyMapping_HasKeyStringWithError(PyObject *obj, const char *key)
{}

int
PyMapping_HasKeyWithError(PyObject *obj, PyObject *key)
{}

int
PyMapping_HasKeyString(PyObject *obj, const char *key)
{}

int
PyMapping_HasKey(PyObject *obj, PyObject *key)
{}

/* This function is quite similar to PySequence_Fast(), but specialized to be
   a helper for PyMapping_Keys(), PyMapping_Items() and PyMapping_Values().
 */
static PyObject *
method_output_as_list(PyObject *o, PyObject *meth)
{}

PyObject *
PyMapping_Keys(PyObject *o)
{}

PyObject *
PyMapping_Items(PyObject *o)
{}

PyObject *
PyMapping_Values(PyObject *o)
{}

/* isinstance(), issubclass() */

/* abstract_get_bases() has logically 4 return states:
 *
 * 1. getattr(cls, '__bases__') could raise an AttributeError
 * 2. getattr(cls, '__bases__') could raise some other exception
 * 3. getattr(cls, '__bases__') could return a tuple
 * 4. getattr(cls, '__bases__') could return something other than a tuple
 *
 * Only state #3 is a non-error state and only it returns a non-NULL object
 * (it returns the retrieved tuple).
 *
 * Any raised AttributeErrors are masked by clearing the exception and
 * returning NULL.  If an object other than a tuple comes out of __bases__,
 * then again, the return value is NULL.  So yes, these two situations
 * produce exactly the same results: NULL is returned and no error is set.
 *
 * If some exception other than AttributeError is raised, then NULL is also
 * returned, but the exception is not cleared.  That's because we want the
 * exception to be propagated along.
 *
 * Callers are expected to test for PyErr_Occurred() when the return value
 * is NULL to decide whether a valid exception should be propagated or not.
 * When there's no exception to propagate, it's customary for the caller to
 * set a TypeError.
 */
static PyObject *
abstract_get_bases(PyObject *cls)
{}


static int
abstract_issubclass(PyObject *derived, PyObject *cls)
{}

static int
check_class(PyObject *cls, const char *error)
{}

static int
object_isinstance(PyObject *inst, PyObject *cls)
{}

static int
object_recursive_isinstance(PyThreadState *tstate, PyObject *inst, PyObject *cls)
{}


int
PyObject_IsInstance(PyObject *inst, PyObject *cls)
{}


static  int
recursive_issubclass(PyObject *derived, PyObject *cls)
{}

static int
object_issubclass(PyThreadState *tstate, PyObject *derived, PyObject *cls)
{}


int
PyObject_IsSubclass(PyObject *derived, PyObject *cls)
{}


int
_PyObject_RealIsInstance(PyObject *inst, PyObject *cls)
{}

int
_PyObject_RealIsSubclass(PyObject *derived, PyObject *cls)
{}


PyObject *
PyObject_GetIter(PyObject *o)
{}

PyObject *
PyObject_GetAIter(PyObject *o) {}

int
PyIter_Check(PyObject *obj)
{}

int
PyAIter_Check(PyObject *obj)
{}

static int
iternext(PyObject *iter, PyObject **item)
{}

/* Return 1 and set 'item' to the next item of 'iter' on success.
 * Return 0 and set 'item' to NULL when there are no remaining values.
 * Return -1, set 'item' to NULL and set an exception on error.
 */
int
PyIter_NextItem(PyObject *iter, PyObject **item)
{}

/* Return next item.
 *
 * If an error occurs, return NULL.  PyErr_Occurred() will be true.
 * If the iteration terminates normally, return NULL and clear the
 * PyExc_StopIteration exception (if it was set).  PyErr_Occurred()
 * will be false.
 * Else return the next object.  PyErr_Occurred() will be false.
 */
PyObject *
PyIter_Next(PyObject *iter)
{}

PySendResult
PyIter_Send(PyObject *iter, PyObject *arg, PyObject **result)
{}