diff --git a/.github/workflows/buildwheels.yml b/.github/workflows/buildwheels.yml index 72f56a9..8f49cc0 100644 --- a/.github/workflows/buildwheels.yml +++ b/.github/workflows/buildwheels.yml @@ -53,12 +53,11 @@ jobs: uses: pypa/cibuildwheel@v3.4.0 env: CIBW_TEST_REQUIRES: hypothesis pytest - CIBW_TEST_COMMAND: "python {project}/cydoctest.py -v" # full test command: py.test {project}/test.py -v + CIBW_TEST_COMMAND: "pytest {project}/test.py -v && python {project}/cydoctest.py -v" CIBW_SKIP: "cp38-*" CIBW_ARCHS_LINUX: ${{ runner.arch == 'X64' && 'auto' || 'auto armv7l' }} CIBW_ARCHS_MACOS: ${{ runner.arch == 'X64' && 'auto' || 'auto universal2' }} CIBW_ARCHS_WINDOWS: "auto ARM64" - CIBW_TEST_SKIP: "*-win_arm64" CIBW_BUILD_FRONTEND: "build" MACOSX_DEPLOYMENT_TARGET: "14.0" # fix build for macos-15-intel diff --git a/pyroaring/abstract_bitmap.pxi b/pyroaring/abstract_bitmap.pxi index f7079c0..e2aef3e 100644 --- a/pyroaring/abstract_bitmap.pxi +++ b/pyroaring/abstract_bitmap.pxi @@ -701,18 +701,21 @@ cdef class AbstractBitMap: assert len(r) > 0 first_elt = self._get_elt(start) last_elt = self._get_elt(stop-sign) - values = range(first_elt, last_elt+sign, step) - if abs(step) == 1 and len(values) <= len(self) / 100: # contiguous and small chunk of the bitmap - return self & self.__class__(values, copy_on_write=self.copy_on_write) - else: # generic case - if step < 0: - start = r[-1] - stop = r[0] + 1 - step = -step - else: - start = r[0] - stop = r[-1] + 1 - return self._generic_get_slice(start, stop, step) + if abs(step) == 1: + # Compute range size without len() to avoid OverflowError on 32-bit platforms + # when first_elt and last_elt span a range exceeding Py_ssize_t. + size = abs(last_elt - first_elt) + 1 + if size <= len(self) / 100: # contiguous and small chunk of the bitmap + return self & self.__class__(range(first_elt, last_elt+sign, step), copy_on_write=self.copy_on_write) + # generic case + if step < 0: + start = r[-1] + stop = r[0] + 1 + step = -step + else: + start = r[0] + stop = r[-1] + 1 + return self._generic_get_slice(start, stop, step) cdef _generic_get_slice(self, uint32_t start, uint32_t stop, uint32_t step): """Assume that start, stop and step > 0 and that the result will not be empty.""" @@ -1163,18 +1166,21 @@ cdef class AbstractBitMap64: assert len(r) > 0 first_elt = self._get_elt(start) last_elt = self._get_elt(stop-sign) - values = range(first_elt, last_elt+sign, step) - if abs(step) == 1 and len(values) <= len(self) / 100: # contiguous and small chunk of the bitmap - return self & self.__class__(values) - else: # generic case - if step < 0: - start = r[-1] - stop = r[0] + 1 - step = -step - else: - start = r[0] - stop = r[-1] + 1 - return self._generic_get_slice(start, stop, step) + if abs(step) == 1: + # Compute range size without len() to avoid OverflowError on platforms + # where Py_ssize_t cannot hold the distance between first_elt and last_elt. + size = abs(last_elt - first_elt) + 1 + if size <= len(self) / 100: # contiguous and small chunk of the bitmap + return self & self.__class__(range(first_elt, last_elt+sign, step)) + # generic case + if step < 0: + start = r[-1] + stop = r[0] + 1 + step = -step + else: + start = r[0] + stop = r[-1] + 1 + return self._generic_get_slice(start, stop, step) cdef _generic_get_slice(self, uint64_t start, uint64_t stop, uint64_t step): """Assume that start, stop and step > 0 and that the result will not be empty.""" diff --git a/test.py b/test.py index be51da7..8e13e6f 100755 --- a/test.py +++ b/test.py @@ -424,6 +424,12 @@ def test_slice_select_none( assume(step != 0) self.check_slice(cls, values, start, stop, step, cow) + def test_get_slice_large_span(self) -> None: + # Regression for https://github.com/Ezibenroc/PyRoaringBitMap/issues/145 + bm = BitMap([0, 2**31 - 1 if is_32_bits else 2**63 - 1]) + assert bm[:] == bm + assert bm[::-1] == bm + @given(bitmap_cls, hyp_collection, st.booleans()) def test_simple_rank( self,