Repository: roaringbitmap/roaringbitmap
Issue: RangeBitmap can give wrong result when computing between on 2 values with different highest bit

**Describe the bug**
When setting the RangeBitmap to full range (`0xFFFFFFFFFFFFFFFFL`, used for computing double range), computing a between for 2 values with different highest bit won't return the expected matching value.

**To Reproduce**
```
  public static void main(String[] args) {
    RangeBitmap.Appender appender = RangeBitmap.appender(0xFFFFFFFFFFFFFFFFL);
    appender.add(0xFFFFFFFFFFFFFFF0L);
    RangeBitmap rangeBitmap = appender.build();
    System.out.println(rangeBitmap.between(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF0L));
    System.out.println(rangeBitmap.between(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF1L));
  }
```

It returns empty bitmap in both operations.

**RoaringBitmap version:**
0.9.28


**Java version:**
11





Changed files:
RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java, RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java

diff --git a/RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java b/RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java
index b8e4320d..3b95471c 100644
--- a/RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java
+++ b/RoaringBitmap/src/main/java/org/roaringbitmap/RangeBitmap.java
@@ -729,11 +729,15 @@ public final class RangeBitmap {
       // most significant absent bit in the threshold for which there is no container;
       // everything before this is wasted work, so we just skip over the containers
       int skipLow = 64 - Long.numberOfLeadingZeros(((~lower & ~containerMask) & mask));
-      if (skipLow > 0) {
+      if (skipLow == 64) {
+        lower = 0L;
+      } else if (skipLow > 0) {
         lower &= -(1L << skipLow);
       }
       int skipHigh = 64 - Long.numberOfLeadingZeros(((~upper & ~containerMask) & mask));
-      if (skipHigh > 0) {
+      if (skipHigh == 64) {
+        upper = 0L;
+      } else if (skipHigh > 0) {
         upper &= -(1L << skipHigh);
       }
       setupFirstSlice(upper, high, (int) remaining, skipHigh == 0);
@@ -741,9 +745,12 @@ public final class RangeBitmap {
       if ((containerMask & 1) == 1) {
         skipContainer();
       }
-      for (int slice = 1; slice < Long.bitCount(mask); ++slice) {
-        if ((containerMask >>> slice & 1) == 1) {
-          int flags = (int) (((upper >>> slice) & 1) | (((lower >>> slice) & 1) << 1));
+      containerMask >>>= 1;
+      upper >>>= 1;
+      lower >>>= 1;
+      for (; containerMask != 0; containerMask >>>= 1, upper >>>= 1, lower >>>= 1) {
+        if ((containerMask & 1) == 1) {
+          int flags = (int) ((upper & 1) | ((lower & 1) << 1));
           switch (flags) {
             case 0: // both absent
               andLowAndHigh();
diff --git a/RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java b/RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
index 6a508ef8..e3120fd8 100644
--- a/RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
+++ b/RoaringBitmap/src/test/java/org/roaringbitmap/RangeBitmapTest.java
@@ -736,6 +736,25 @@ public class RangeBitmapTest {
     assertEquals(accumulator.build().betweenCardinality(value, value), count);
   }
 
+  @Test
+  public void regressionTestIssue586() {
+    // see https://github.com/RoaringBitmap/RoaringBitmap/issues/586
+    assertAll(
+            () -> regresssionTestIssue586(0x0FFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFF0L, 0xFFFFFFFFFFFFFF0L),
+            () -> regresssionTestIssue586(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF0L, 0xFFFFFFFFFFFFFFF0L),
+            () -> regresssionTestIssue586(0x0FFFFFFFFFFFFFFFL, 0xFFFFFFFFFFFFFFF1L, 0xFFFFFFFFFFFFFFF0L),
+            () -> regresssionTestIssue586(0, 10_000_000_000L, 10_000_000L)
+    );
+  }
+
+  private static void regresssionTestIssue586(long low, long high, long value) {
+    RangeBitmap.Appender appender = RangeBitmap.appender(0xFFFFFFFFFFFFFFFFL);
+    appender.add(value);
+    RangeBitmap rangeBitmap = appender.build();
+    assertEquals(rangeBitmap.gte(low, rangeBitmap.lte(high)), rangeBitmap.between(low, high));
+    assertEquals(1, rangeBitmap.between(low, high).getCardinality());
+  }
+
   public static class ReferenceImplementation {
 
     public static Builder builder() {