Objects/sliceobject.c
Source:
cpython 3.14 @ ab2d84fe1023/Objects/sliceobject.c
Map
| Lines | Symbol | Purpose |
|---|---|---|
| 1–30 | includes, Py_Ellipsis | module-level singleton setup |
| 31–60 | ellipsis_new, ellipsis_repr | Ellipsis type methods |
| 61–120 | PySlice_New, slice_new | constructor, argument unpacking |
| 121–180 | _PySlice_Unpack | extract (start, stop, step) as C Py_ssize_t |
| 181–260 | _PySlice_AdjustIndices | clamp indices to sequence length |
| 261–320 | PySlice_GetIndicesEx | public wrapper, overflow-safe |
| 321–360 | slice_indices | Python-level slice.indices() method |
| 361–400 | PySlice_Type, slice_repr, slice_richcompare | type object and comparison |
Reading
PySliceObject layout
A slice carries three PyObject* fields. All three are always set; None is stored when the caller omits start, stop, or step.
// CPython: Objects/sliceobject.c:1 PySliceObject
typedef struct {
PyObject_HEAD
PyObject *start;
PyObject *stop;
PyObject *step;
} PySliceObject;
slice_new (called via PySlice_New) validates step is not zero and then calls PyObject_GC_New. The three fields are incref'd individually, so the object owns references to all three.
Unpacking and index clamping
_PySlice_Unpack converts the three PyObject* fields to Py_ssize_t values without any knowledge of the sequence length. It handles None defaults (start defaults to 0 for positive step and PY_SSIZE_T_MAX for negative), and clips each raw integer to [PY_SSIZE_T_MIN+1, PY_SSIZE_T_MAX] before returning.
// CPython: Objects/sliceobject.c:121 _PySlice_Unpack
int
_PySlice_Unpack(PyObject *_r,
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step)
{
PySliceObject *r = (PySliceObject*)_r;
/* ... step cannot be zero ... */
if (r->step == Py_None) {
*step = 1;
} else {
if (!_PyEval_SliceIndex(r->step, step)) return -1;
if (*step == 0) { PyErr_SetString(...); return -1; }
}
/* start/stop default logic follows */
}
_PySlice_AdjustIndices then takes the length of the concrete sequence and clamps the unpacked values:
// CPython: Objects/sliceobject.c:181 _PySlice_AdjustIndices
Py_ssize_t
_PySlice_AdjustIndices(Py_ssize_t length, Py_ssize_t *start,
Py_ssize_t *stop, Py_ssize_t step)
The function returns the number of items the slice selects, which is max(0, (stop - start + step - sign(step)) / step).
PySlice_GetIndicesEx and the Ellipsis singleton
PySlice_GetIndicesEx is the older public API. It calls _PySlice_Unpack followed by _PySlice_AdjustIndices, collapsing the two-step protocol into one call. It is kept for C extension compatibility; new code should call the two primitives directly.
The Ellipsis object is a singleton defined in the same file. ellipsis_new always returns the pre-allocated _Py_EllipsisObject and increments its reference count. PyEllipsis_Type marks it as not instantiable by users.
// CPython: Objects/sliceobject.c:31 ellipsis_new
static PyObject *
ellipsis_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
if (...) { /* disallow subclassing */ }
Py_INCREF(Py_Ellipsis);
return Py_Ellipsis;
}
gopy notes
Status: not yet ported.
Planned package path: objects/ (file slice.go alongside int.go, list.go, etc.).
Priority items for porting:
PySliceObjectstruct withStart,Stop,Stepas*Objectfields.SliceNewmirroringPySlice_Newargument order andNone-defaulting behaviour.SliceUnpackandSliceAdjustIndicesas the two-step index protocol used by the VM'sBUILD_SLICEand sequence subscription opcodes.PySlice_GetIndicesExas a convenience wrapper for C-extension compatibility shims.- The Ellipsis singleton as a package-level
var Ellipsis *Objectinitialised once at startup.