btck

bindings/python/src/_slice.c

// Copyright (c) 2025-present The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "_slice.h"
struct Self
{
PyObject_HEAD
PyObject* seq;
Py_ssize_t start;
Py_ssize_t step;
Py_ssize_t length;
};
static void dealloc(struct Self* self)
{
Py_DECREF(self->seq);
Py_TYPE(self)->tp_free((PyObject*)self);
}
static Py_ssize_t length(struct Self const* self)
{
return self->length;
}
static PyObject* item(struct Self const* self, Py_ssize_t idx)
{
if (idx < 0 || idx >= self->length) {
PyErr_SetString(PyExc_IndexError, "index out of range");
return NULL;
}
PySequenceMethods const* seq = Py_TYPE(self->seq)->tp_as_sequence;
return seq->sq_item(self->seq, self->start + (idx * self->step));
}
static PySequenceMethods as_sequence = {
.sq_length = (lenfunc)length,
.sq_item = (ssizeargfunc)item,
};
static PyMappingMethods as_mapping = {
.mp_length = (lenfunc)length,
.mp_subscript = Slice_subscript,
};
PyTypeObject Slice_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "btck._Slice",
.tp_basicsize = sizeof(struct Self),
.tp_dealloc = (destructor)dealloc,
.tp_as_sequence = &as_sequence,
.tp_as_mapping = &as_mapping,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_doc = "Lazy slice view of a sequence",
};
PyObject* Slice_subscript(PyObject* self, PyObject* arg)
{
PySequenceMethods const* seq = Py_TYPE(self)->tp_as_sequence;
if (PyIndex_Check(arg)) {
Py_ssize_t idx = PyNumber_AsSsize_t(arg, PyExc_IndexError);
if (idx == -1 && PyErr_Occurred()) {
return NULL;
}
if (idx < 0) {
idx += seq->sq_length(self);
}
return seq->sq_item(self, idx);
}
if (PySlice_Check(arg)) {
Py_ssize_t start, stop, step; // NOLINT(readability-isolate-declaration)
if (PySlice_Unpack(arg, &start, &stop, &step) < 0) {
return NULL;
}
struct Self* slice = PyObject_New(struct Self, &Slice_Type);
if (slice == NULL) {
return NULL;
}
slice->seq = Py_NewRef(self);
slice->start = start;
slice->step = step;
slice->length = PySlice_AdjustIndices(seq->sq_length(self), &start, &stop, step);
return (PyObject*)slice;
}
return PyErr_Format(PyExc_TypeError, "indices must be integers or slices, not %.200s", Py_TYPE(arg)->tp_name);
}