diff --git a/pandas/_libs/index.pyx b/pandas/_libs/index.pyx index 293f067810f27..b7a1471ae5a9e 100644 --- a/pandas/_libs/index.pyx +++ b/pandas/_libs/index.pyx @@ -50,23 +50,7 @@ cpdef get_value_at(ndarray arr, object loc, object tz=None): cpdef object get_value_box(ndarray arr, object loc): - cdef: - Py_ssize_t i, sz - - if util.is_float_object(loc): - casted = int(loc) - if casted == loc: - loc = casted - i = loc - sz = cnp.PyArray_SIZE(arr) - - if i < 0 and sz > 0: - i += sz - - if i >= sz or sz == 0 or i < 0: - raise IndexError('index out of bounds') - - return get_value_at(arr, i, tz=None) + return get_value_at(arr, loc, tz=None) # Don't populate hash tables in monotonic indexes larger than this diff --git a/pandas/_libs/util.pxd b/pandas/_libs/util.pxd index 25d20c930cf08..e78f132ada2ca 100644 --- a/pandas/_libs/util.pxd +++ b/pandas/_libs/util.pxd @@ -72,23 +72,50 @@ cdef inline void set_array_not_contiguous(ndarray ao) nogil: (NPY_ARRAY_C_CONTIGUOUS | NPY_ARRAY_F_CONTIGUOUS)) -cdef inline object get_value_at(ndarray arr, object loc): +cdef inline Py_ssize_t validate_indexer(ndarray arr, object loc) except -1: + """ + Cast the given indexer `loc` to an integer. If it is negative, i.e. a + python-style indexing-from-the-end indexer, translate it to a + from-the-front indexer. Raise if this is not possible. + + Parameters + ---------- + arr : ndarray + loc : object + + Returns + ------- + idx : Py_ssize_t + + Raises + ------ + IndexError + """ cdef: - Py_ssize_t i, sz + Py_ssize_t idx, size int casted if is_float_object(loc): casted = int(loc) if casted == loc: loc = casted - i = loc - sz = cnp.PyArray_SIZE(arr) - if i < 0 and sz > 0: - i += sz - elif i >= sz or sz == 0: + idx = loc + size = cnp.PyArray_SIZE(arr) + + if idx < 0 and size > 0: + idx += size + if idx >= size or size == 0 or idx < 0: raise IndexError('index out of bounds') + return idx + + +cdef inline object get_value_at(ndarray arr, object loc): + cdef: + Py_ssize_t i + + i = validate_indexer(arr, loc) return get_value_1d(arr, i) @@ -99,19 +126,9 @@ cdef inline set_value_at_unsafe(ndarray arr, object loc, object value): flag above the loop and then eschew the check on each iteration. """ cdef: - Py_ssize_t i, sz - if is_float_object(loc): - casted = int(loc) - if casted == loc: - loc = casted - i = loc - sz = cnp.PyArray_SIZE(arr) - - if i < 0: - i += sz - elif i >= sz: - raise IndexError('index out of bounds') + Py_ssize_t i + i = validate_indexer(arr, loc) assign_value_1d(arr, i, value)