* This returns a `Strs` object of a potentially different layout: * - `STRS_U32_TAPE_VIEW` input yields a `STRS_U32_TAPE_VIEW` for `step=1`, `STRS_FRAGMENTED` otherwise. * - `STRS_U64_TAPE_VIEW` input yields a `STRS_U64_TAPE_VIEW` for `step=1`, `STRS_FRAGMENTED` otherwise. * - `STRS_U32_TAPE` input yields a `STRS_U32_TAPE_VIEW` for `step=1`, `STRS_FRAGMENTED` otherwise. * - `STRS_U64_TAP
| 2039 | * - `STRS_FRAGMENTED` input yields a `STRS_FRAGMENTED` output. |
| 2040 | */ |
| 2041 | static PyObject *Strs_subscript(Strs *self, PyObject *key) { |
| 2042 | |
| 2043 | if (PyLong_Check(key)) { return Strs_getitem(self, PyLong_AsSsize_t(key)); } |
| 2044 | |
| 2045 | if (!PySlice_Check(key)) { |
| 2046 | PyErr_SetString(PyExc_TypeError, "Strs indices must be integers or slices"); |
| 2047 | return NULL; |
| 2048 | } |
| 2049 | |
| 2050 | // Sanity checks |
| 2051 | Py_ssize_t count = Strs_len(self); |
| 2052 | Py_ssize_t start, stop, step; |
| 2053 | if (PySlice_Unpack(key, &start, &stop, &step) < 0) return NULL; |
| 2054 | Py_ssize_t result_count = PySlice_AdjustIndices(count, &start, &stop, step); |
| 2055 | if (result_count < 0) return NULL; |
| 2056 | |
| 2057 | // Create a new `Strs` object |
| 2058 | Strs *result = (Strs *)StrsType.tp_alloc(&StrsType, 0); |
| 2059 | if (result == NULL && PyErr_NoMemory()) return NULL; |
| 2060 | |
| 2061 | if (result_count == 0) { |
| 2062 | result->layout = STRS_FRAGMENTED; |
| 2063 | result->data.fragmented.count = 0; |
| 2064 | result->data.fragmented.spans = NULL; |
| 2065 | result->data.fragmented.parent = NULL; |
| 2066 | sz_memory_allocator_init_default(&result->data.fragmented.allocator); |
| 2067 | return (PyObject *)result; |
| 2068 | } |
| 2069 | |
| 2070 | // If a step is requested, we have to create a new `FRAGMENTED` instance of `Strs`, |
| 2071 | // even if the original one was a tape layout. |
| 2072 | if (step != 1) { |
| 2073 | sz_string_view_t *new_spans = (sz_string_view_t *)malloc(result_count * sizeof(sz_string_view_t)); |
| 2074 | if (new_spans == NULL) { |
| 2075 | Py_XDECREF(result); |
| 2076 | PyErr_SetString(PyExc_MemoryError, "Unable to allocate memory for fragmented spans"); |
| 2077 | return NULL; |
| 2078 | } |
| 2079 | |
| 2080 | get_string_at_offset_t getter = str_at_offset_getter(self); |
| 2081 | result->layout = STRS_FRAGMENTED; |
| 2082 | result->data.fragmented.count = result_count; |
| 2083 | result->data.fragmented.spans = new_spans; |
| 2084 | result->data.fragmented.parent = NULL; |
| 2085 | sz_memory_allocator_init_default(&result->data.fragmented.allocator); |
| 2086 | |
| 2087 | // Populate the new fragmented array using `get_string_at_offset` |
| 2088 | sz_size_t j = 0; |
| 2089 | if (step > 0) |
| 2090 | for (Py_ssize_t i = start; i < stop; i += step, ++j) { |
| 2091 | getter(self, i, count, &result->data.fragmented.parent, &new_spans[j].start, &new_spans[j].length); |
| 2092 | } |
| 2093 | else |
| 2094 | for (Py_ssize_t i = start; i > stop; i += step, ++j) { |
| 2095 | getter(self, i, count, &result->data.fragmented.parent, &new_spans[j].start, &new_spans[j].length); |
| 2096 | } |
| 2097 | |
| 2098 | // Ensure the parent string isn't prematurely deallocated by this view. |
nothing calls this directly
no test coverage detected
searching dependent graphs…