Source

pypy / pypy / module / cpyext / sliceobject.py

from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.gateway import cpython_api, CANNOT_FAIL
from pypy.module.cpyext.api import (
    cpython_struct, build_type_checkers, bootstrap_function,
    Py_ssize_t, Py_ssize_tP, PyObjectFields)
from pypy.module.cpyext.pyobject import (
    Py_DecRef, PyObject, make_ref, make_typedescr)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.interpreter.error import OperationError
from pypy.objspace.std.sliceobject import W_SliceObject

# Slice objects directly expose their members as PyObject.
# Don't change them!

PySliceObjectStruct = lltype.ForwardReference()
PySliceObject = lltype.Ptr(PySliceObjectStruct)
PySliceObjectFields = PyObjectFields + \
    (("start", PyObject), ("step", PyObject), ("stop", PyObject), )
cpython_struct("PySliceObject", PySliceObjectFields, PySliceObjectStruct)

@bootstrap_function
def init_sliceobject(space):
    "Type description of PySliceObject"
    make_typedescr(W_SliceObject.typedef,
                   basestruct=PySliceObject.TO,
                   attach=slice_attach,
                   dealloc=slice_dealloc)

def slice_attach(space, py_obj, w_obj):
    """
    Fills a newly allocated PySliceObject with the given slice object. The
    fields must not be modified.
    """
    py_slice = rffi.cast(PySliceObject, py_obj)
    assert isinstance(w_obj, W_SliceObject)
    py_slice.c_start = make_ref(space, w_obj.w_start)
    py_slice.c_stop = make_ref(space, w_obj.w_stop)
    py_slice.c_step = make_ref(space, w_obj.w_step)

@cpython_api([PyObject], lltype.Void, external=False)
def slice_dealloc(space, py_obj):
    """Frees allocated PyStringObject resources.
    """
    py_slice = rffi.cast(PySliceObject, py_obj)
    Py_DecRef(space, py_slice.c_start)
    Py_DecRef(space, py_slice.c_stop)
    Py_DecRef(space, py_slice.c_step)
    from pypy.module.cpyext.object import PyObject_dealloc
    PyObject_dealloc(space, py_obj)

PySlice_Check, PySlice_CheckExact = build_type_checkers("Slice")

@cpython_api([PyObject, PyObject, PyObject], PyObject)
def PySlice_New(space, w_start, w_stop, w_step):
    """Return a new slice object with the given values.  The start, stop, and
    step parameters are used as the values of the slice object attributes of
    the same names.  Any of the values may be NULL, in which case the
    None will be used for the corresponding attribute.  Return NULL if
    the new object could not be allocated."""
    if w_start is None:
        w_start = space.w_None
    if w_stop is None:
        w_stop = space.w_None
    if w_step is None:
        w_step = space.w_None
    return W_SliceObject(w_start, w_stop, w_step)

@cpython_api([PySliceObject, Py_ssize_t, Py_ssize_tP, Py_ssize_tP, Py_ssize_tP,
                Py_ssize_tP], rffi.INT_real, error=-1)
def PySlice_GetIndicesEx(space, w_slice, length, start_p, stop_p, step_p,
                         slicelength_p):
    """Usable replacement for PySlice_GetIndices().  Retrieve the start,
    stop, and step indices from the slice object slice assuming a sequence of
    length length, and store the length of the slice in slicelength.  Out
    of bounds indices are clipped in a manner consistent with the handling of
    normal slices.
    
    Returns 0 on success and -1 on error with exception set."""
    if not PySlice_Check(space, w_slice):
        PyErr_BadInternalCall(space)
    assert isinstance(w_slice, W_SliceObject)
    start_p[0], stop_p[0], step_p[0], slicelength_p[0] = \
            w_slice.indices4(space, length)
    return 0