Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Doc/library/stdtypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4140,6 +4140,15 @@ copying.
.. versionchanged:: 3.5
The source format is no longer restricted when casting to a byte view.

.. method:: index(value, start=0, stop=sys.maxsize, /)

Return the index of the first occurrence of *value* (at or after
index *start* and before index *stop*).

Raises a :exc:`ValueError` if *value* cannot be found.

.. versionadded:: 3.14

There are also several readonly attributes available:

.. attribute:: obj
Expand Down
26 changes: 26 additions & 0 deletions Lib/test/test_memoryview.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import pickle
import struct

from itertools import product
from test.support import import_helper


Expand Down Expand Up @@ -58,6 +59,31 @@ def test_getitem(self):
for tp in self._types:
self.check_getitem_with_type(tp)

def test_index(self):
for tp in self._types:
b = tp(self._source)
m = self._view(b) # may be a sub-view
l = m.tolist()
k = 2 * len(self._source)

for chi in self._source:
if chi in l:
self.assertEqual(m.index(chi), l.index(chi))
else:
self.assertRaises(ValueError, m.index, chi)

for start, stop in product(range(-k, k), range(-k, k)):
index = -1
try:
index = l.index(chi, start, stop)
except ValueError:
pass

if index == -1:
self.assertRaises(ValueError, m.index, chi, start, stop)
else:
self.assertEqual(m.index(chi, start, stop), index)

def test_iter(self):
for tp in self._types:
b = tp(self._source)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add :meth:`memoryview.index` to :class:`memoryview` objects. Patch by
Bénédikt Tran.
48 changes: 47 additions & 1 deletion Objects/clinic/memoryobject.c.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

72 changes: 72 additions & 0 deletions Objects/memoryobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -2748,6 +2748,77 @@ static PySequenceMethods memory_as_sequence = {
};


/**************************************************************************/
/* Lookup */
/**************************************************************************/

/*[clinic input]
memoryview.index

value: object
start: slice_index(accept={int}) = 0
stop: slice_index(accept={int}, c_default="PY_SSIZE_T_MAX") = sys.maxsize
/

Return the index of the first occurrence of a value.

Raises ValueError if the value is not present.
[clinic start generated code]*/

static PyObject *
memoryview_index_impl(PyMemoryViewObject *self, PyObject *value,
Py_ssize_t start, Py_ssize_t stop)
/*[clinic end generated code: output=e0185e3819e549df input=0697a0165bf90b5a]*/
{
Py_buffer *view = &(self->view);
CHECK_RELEASED(self);

if (view->ndim == 0) {
PyErr_SetString(PyExc_TypeError, "invalid indexing of 0-dim memory");
return NULL;
}

if (view->ndim == 1) {
Py_ssize_t n = view->shape[0];

if (start < 0) {
start = Py_MAX(start + n, 0);
}

if (stop < 0) {
stop = Py_MAX(stop + n, 0);
}

stop = Py_MIN(stop, n);
start = Py_MIN(start, stop);

for (Py_ssize_t index = start; index < stop; index++) {
PyObject *item = memory_item((PyObject *)self, index);
if (item == NULL) {
return NULL;
}
int contained = PyObject_RichCompareBool(item, value, Py_EQ);
Py_DECREF(item);
if (contained > 0) {
return PyLong_FromSsize_t(index);
}
else if (contained < 0) {
return NULL;
}
}

PyErr_SetString(PyExc_ValueError,
"memoryview.index(x): x not in list");
return NULL;
}

PyErr_SetString(PyExc_NotImplementedError,
"multi-dimensional lookup is not implemented");
return NULL;

}


/**************************************************************************/
/* Comparisons */
/**************************************************************************/
Expand Down Expand Up @@ -3284,6 +3355,7 @@ static PyMethodDef memory_methods[] = {
MEMORYVIEW_CAST_METHODDEF
MEMORYVIEW_TOREADONLY_METHODDEF
MEMORYVIEW__FROM_FLAGS_METHODDEF
MEMORYVIEW_INDEX_METHODDEF
{"__enter__", memory_enter, METH_NOARGS, NULL},
{"__exit__", memory_exit, METH_VARARGS, memory_exit_doc},
{NULL, NULL}
Expand Down
Loading