This is an automated email from the ASF dual-hosted git repository.

benedict pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/cassandra-accord.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 875937c8 CASSANDRA-20883: bitset changes to support cassandra 
serializers
875937c8 is described below

commit 875937c8844e854a55765c64ac34a2bd4a6bc187
Author: David Capwell <dcapw...@apple.com>
AuthorDate: Wed Sep 3 10:00:51 2025 -0700

    CASSANDRA-20883: bitset changes to support cassandra serializers
    
    patch by David Capwell and Benedict for CASSANDRA-20883
---
 .gitignore                                         |   7 +
 .../src/main/java/accord/utils/SimpleBitSet.java   |   1 +
 .../{SimpleBitSet.java => SimpleBitSets.java}      |  22 ++-
 .../src/main/java/accord/utils/SmallBitSet.java    |  25 +++
 .../src/main/java/accord/utils/SortedArrays.java   | 213 +++++++++++++++++++++
 .../test/java/accord/utils/SimpleBitSetTest.java   | 173 +++++++++++++++++
 6 files changed, 431 insertions(+), 10 deletions(-)

diff --git a/.gitignore b/.gitignore
index bd3d7a7f..34cc6f2d 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,3 +4,10 @@ build/
 accord-core/build/
 accord-maelstrom/build/
 .rat-excludes.txt
+
+# Coding tools like NeoVim and Visual Studio Code will store their metadata at 
the following paths
+accord-core/bin/
+accord-maelstrom/bin/
+.project
+.settings
+.classpath
diff --git a/accord-core/src/main/java/accord/utils/SimpleBitSet.java 
b/accord-core/src/main/java/accord/utils/SimpleBitSet.java
index 24428971..8df24a80 100644
--- a/accord-core/src/main/java/accord/utils/SimpleBitSet.java
+++ b/accord-core/src/main/java/accord/utils/SimpleBitSet.java
@@ -26,6 +26,7 @@ public interface SimpleBitSet
     void clear();
     boolean isEmpty();
     int nextSetBit(int fromIndex);
+    int getSetBitCount();
 
     static SimpleBitSet allocate(int size)
     {
diff --git a/accord-core/src/main/java/accord/utils/SimpleBitSet.java 
b/accord-core/src/main/java/accord/utils/SimpleBitSets.java
similarity index 70%
copy from accord-core/src/main/java/accord/utils/SimpleBitSet.java
copy to accord-core/src/main/java/accord/utils/SimpleBitSets.java
index 24428971..bdd99c69 100644
--- a/accord-core/src/main/java/accord/utils/SimpleBitSet.java
+++ b/accord-core/src/main/java/accord/utils/SimpleBitSets.java
@@ -18,18 +18,20 @@
 
 package accord.utils;
 
-public interface SimpleBitSet
+public final class SimpleBitSets
 {
-    boolean get(int i);
-    boolean set(int i);
-    boolean unset(int i);
-    void clear();
-    boolean isEmpty();
-    int nextSetBit(int fromIndex);
+    private SimpleBitSets() {}
 
-    static SimpleBitSet allocate(int size)
+    public static SimpleBitSet allSet(int bits)
     {
-        if (size <= 64) return new SmallBitSet();
-        else return new LargeBitSet(size);
+        SimpleBitSet set = SimpleBitSet.allocate(bits);
+        for (int i = 0; i < bits; i++)
+            set.set(i);
+        return set;
+    }
+
+    public static SimpleBitSet allUnset(int bits)
+    {
+        return SimpleBitSet.allocate(bits);
     }
 }
diff --git a/accord-core/src/main/java/accord/utils/SmallBitSet.java 
b/accord-core/src/main/java/accord/utils/SmallBitSet.java
index f10f6706..a0e692f9 100644
--- a/accord-core/src/main/java/accord/utils/SmallBitSet.java
+++ b/accord-core/src/main/java/accord/utils/SmallBitSet.java
@@ -26,6 +26,20 @@ public class SmallBitSet implements SimpleBitSet
 {
     private long bits;
 
+    public SmallBitSet()
+    {
+    }
+
+    public SmallBitSet(long bits)
+    {
+        this.bits = bits;
+    }
+
+    public long bits()
+    {
+        return bits;
+    }
+
     public boolean set(int i)
     {
         long bit = bit(i);
@@ -69,4 +83,15 @@ public class SmallBitSet implements SimpleBitSet
         return numberOfTrailingZeros(bits);
     }
 
+    @Override
+    public int getSetBitCount()
+    {
+        return Long.bitCount(bits);
+    }
+
+    @Override
+    public boolean equals(Object that)
+    {
+        return that instanceof SmallBitSet && this.bits == ((SmallBitSet) 
that).bits;
+    }
 }
diff --git a/accord-core/src/main/java/accord/utils/SortedArrays.java 
b/accord-core/src/main/java/accord/utils/SortedArrays.java
index 6ffd16d3..8a613af5 100644
--- a/accord-core/src/main/java/accord/utils/SortedArrays.java
+++ b/accord-core/src/main/java/accord/utils/SortedArrays.java
@@ -50,6 +50,8 @@ import static accord.utils.SortedArrays.Search.FAST;
 //        - Exploit exponentialSearch in union/intersection/etc
 public class SortedArrays
 {
+    private static final int[] NO_INTS = new int[0];
+
     public static class SortedArrayList<T extends Comparable<? super T>> 
extends AbstractList<T> implements SortedList<T>
     {
         final T[] array;
@@ -468,6 +470,187 @@ public class SortedArrays
         }
     }
 
+    /**
+     * A linear intersection where we only want results from the left inputs, 
and the right inputs may either be a different type or otherwise only used for 
filtering
+     */
+    public static int[] linearIntersection(int[] left, int leftStart, int 
leftEnd, int[] right, int rightStart, int rightEnd, ArrayBuffers.IntBuffers 
buffers)
+    {
+        if (leftEnd - leftStart > rightEnd - rightStart)
+        {
+            int[] tmp = left;
+            int tmpStart = leftStart, tmpEnd = leftEnd;
+            left = right;
+            leftStart = rightStart;
+            leftEnd = rightEnd;
+            right = tmp;
+            rightStart = tmpStart;
+            rightEnd = tmpEnd;
+        }
+
+        int leftIdx = leftStart;
+        int rightIdx = rightStart;
+
+        int[] result = null;
+        int resultSize = 0;
+
+        boolean hasMatch = false;
+        {
+            while (leftIdx < leftEnd && rightIdx < rightEnd)
+            {
+                int leftKey = left[leftIdx];
+                int rightKey = right[rightIdx];
+                int cmp = Integer.compare(leftKey, rightKey);
+
+                if (cmp >= 0)
+                {
+                    rightIdx += 1;
+                    leftIdx += cmp == 0 ? 1 : 0;
+                    if (cmp == 0)
+                        hasMatch = true;
+                }
+                else
+                {
+                    resultSize = leftIdx++;
+                    result = buffers.getInts(resultSize + Math.min(leftEnd - 
leftIdx, rightEnd - rightIdx));
+                    System.arraycopy(left, 0, result, 0, resultSize);
+                    break;
+                }
+            }
+
+            if (result == null)
+            {
+                if (!hasMatch)
+                    return left.length == 0 ? left : NO_INTS;
+                if (leftStart == 0 && leftEnd == left.length)
+                    return left;
+                return Arrays.copyOfRange(left, leftStart, leftEnd);
+            }
+        }
+
+        try
+        {
+            while (leftIdx < leftEnd && rightIdx < rightEnd)
+            {
+                int leftKey = left[leftIdx];
+                int rightKey = right[rightIdx];
+                int cmp = Integer.compare(leftKey, rightKey);
+
+                if (cmp == 0)
+                {
+                    leftIdx++;
+                    rightIdx++;
+                    result[resultSize++] = leftKey;
+                }
+                else if (cmp < 0) leftIdx++;
+                else rightIdx++;
+            }
+
+            return buffers.complete(result, resultSize);
+        }
+        finally
+        {
+            buffers.discard(result, resultSize);
+        }
+    }
+
+    public static int[] linearUnion(int[] left, int leftStart, int leftEnd, 
int[] right, int rightStart, int rightEnd, ArrayBuffers.IntBuffers buffers)
+    {
+        if (leftEnd - leftStart < rightEnd - rightStart)
+        {
+            int[] tmp = left;
+            int tmpStart = leftStart, tmpEnd = leftEnd;
+            left = right;
+            leftStart = rightStart;
+            leftEnd = rightEnd;
+            right = tmp;
+            rightStart = tmpStart;
+            rightEnd = tmpEnd;
+        }
+
+        int leftIdx = leftStart;
+        int rightIdx = rightStart;
+
+        int[] result;
+        int resultSize;
+
+        // first, pick the superset candidate and merge the two until we find 
the first missing item
+        // if none found, return the superset candidate
+        {
+            int cmp;
+            boolean unfinished;
+            while (unfinished = (leftIdx < leftEnd && rightIdx < rightEnd))
+            {
+                int leftKey = left[leftIdx];
+                int rightKey = right[rightIdx];
+
+                cmp = Integer.compare(leftKey, rightKey);
+                if (cmp > 0) break;
+
+                leftIdx += 1;
+                rightIdx += cmp == 0 ? 1 : 0;
+            }
+
+            if (unfinished)
+            {
+                resultSize = leftIdx - leftStart;
+                result = buffers.getInts(resultSize + (leftEnd - leftIdx) + 
(rightEnd - (rightIdx - 1)));
+                System.arraycopy(left, leftStart, result, 0, resultSize);
+                result[resultSize++] = right[rightIdx++];
+            }
+            else
+            {
+                if (rightIdx == rightEnd) // all elements matched, so can 
return the other array
+                {
+                    if (leftStart == 0 && leftEnd == left.length)
+                        return left;
+
+                    return Arrays.copyOfRange(left, leftStart, leftEnd);
+                }
+                // no elements matched or only a subset matched
+                result = buffers.getInts((leftEnd - leftStart) + (rightEnd - 
rightIdx));
+                resultSize = leftIdx - leftStart;
+                System.arraycopy(left, leftStart, result, 0, resultSize);
+            }
+        }
+
+        try
+        {
+            while (leftIdx < leftEnd && rightIdx < rightEnd)
+            {
+                int leftKey = left[leftIdx];
+                int rightKey = right[rightIdx];
+                int cmp = Integer.compare(leftKey, rightKey);
+
+                int minKey;
+                if (cmp <= 0)
+                {
+                    leftIdx++;
+                    rightIdx += cmp == 0 ? 1 : 0;
+                    minKey = leftKey;
+                }
+                else
+                {
+                    rightIdx++;
+                    minKey = rightKey;
+                }
+                result[resultSize++] = minKey;
+            }
+
+            while (leftIdx < leftEnd)
+                result[resultSize++] = left[leftIdx++];
+
+            while (rightIdx < rightEnd)
+                result[resultSize++] = right[rightIdx++];
+
+            return buffers.completeAndDiscard(result, resultSize);
+        }
+        catch (Throwable t)
+        {
+            buffers.discard(result, resultSize);
+            throw t;
+        }
+    }
+
     // applies the update function to all entries in left, and any matching 
entries in right
     public static <O, T extends O> O[] linearUpdate(T[] left, int leftStart, 
int leftUpdateEnd, int leftEnd, T[] right, int rightStart, int rightEnd, 
AsymmetricComparator<? super T, ? super T> comparator, BiFunction<? super T, ? 
super T, ? extends T> update, IntFunction<T[]> allocate)
     {
@@ -1096,6 +1279,36 @@ public class SortedArrays
         }
     }
 
+    public static boolean hasIntersection(int[] left, int[] right)
+    {
+        return hasIntersection(left, 0, left.length, right, 0, right.length);
+    }
+
+    public static boolean hasIntersection(int[] left, int leftIndex, int 
leftEnd, int[] right, int rightIndex, int rightEnd)
+    {
+        if (leftIndex == leftEnd || rightIndex == rightEnd)
+            return false;
+
+        while (true)
+        {
+            leftIndex = SortedArrays.exponentialSearch(left, leftIndex, 
leftEnd, right[rightIndex]);
+            if (leftIndex >= 0)
+                return true;
+
+            leftIndex = -1 - leftIndex;
+            if (leftIndex == leftEnd)
+                return false;
+
+            rightIndex = SortedArrays.exponentialSearch(right, rightIndex, 
rightEnd, left[leftIndex]);
+            if (rightIndex >= 0)
+                return true;
+
+            rightIndex = -1 - rightIndex;
+            if (rightIndex == rightEnd)
+                return false;
+        }
+    }
+
     private static <T> T[] resizeIfNecessary(T[] input, int size)
     {
         if (size < input.length)
diff --git a/accord-core/src/test/java/accord/utils/SimpleBitSetTest.java 
b/accord-core/src/test/java/accord/utils/SimpleBitSetTest.java
new file mode 100644
index 00000000..6c750eaa
--- /dev/null
+++ b/accord-core/src/test/java/accord/utils/SimpleBitSetTest.java
@@ -0,0 +1,173 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package accord.utils;
+
+
+import java.util.BitSet;
+
+import org.junit.jupiter.api.Test;
+
+import org.assertj.core.api.Assertions;
+
+import static accord.utils.Property.commands;
+import static accord.utils.Property.stateful;
+
+class SimpleBitSetTest
+{
+    private static Property.Command<State, Void, ?> get(RandomSource rs, State 
state)
+    {
+        int idx = rs.nextInt(0, state.size);
+        return new Property.SimpleCommand<>("Get(" + idx + ')', s2 -> 
s2.get(idx));
+    }
+
+    private static Property.Command<State, Void, ?> set(RandomSource rs, State 
state)
+    {
+        int idx = rs.nextInt(0, state.size);
+        return new Property.SimpleCommand<>("Set(" + idx + ')', s2 -> 
s2.set(idx));
+    }
+
+    private static Property.Command<State, Void, ?> unset(RandomSource rs, 
State state)
+    {
+        int idx = rs.nextInt(0, state.size);
+        return new Property.SimpleCommand<>("Unset(" + idx + ')', s2 -> 
s2.unset(idx));
+    }
+
+    private static Property.Command<State, Void, ?> clear(RandomSource rs, 
State state)
+    {
+        return new Property.SimpleCommand<>("Clear", State::clear);
+    }
+
+    private static Property.Command<State, Void, ?> isEmpty(RandomSource rs, 
State state)
+    {
+        return new Property.SimpleCommand<>("Is Empty", State::isEmpty);
+    }
+
+    private static Property.Command<State, Void, ?> nextSetBit(RandomSource 
rs, State state)
+    {
+        int idx = rs.nextInt(0, state.size);
+        return new Property.SimpleCommand<>("NextSetBit(" + idx + ')', s2 -> 
s2.nextSetBit(idx));
+    }
+
+    @Test
+    public void test()
+    {
+        stateful().withExamples(1000).check(commands(() -> State::new)
+                                            .add(SimpleBitSetTest::get)
+                                            .add(SimpleBitSetTest::set)
+                                            .add(SimpleBitSetTest::unset)
+                                            .add(SimpleBitSetTest::clear)
+                                            .add(SimpleBitSetTest::isEmpty)
+                                            .add(SimpleBitSetTest::nextSetBit)
+                                            .build());
+    }
+
+    private static class State implements SimpleBitSet
+    {
+        private final BitSet model;
+        private final SimpleBitSet sut;
+        private final int size;
+
+        private State(RandomSource rs)
+        {
+            this.size = rs.nextInt(1, (1 << 7) + 1); // small vs large have 
roughly equal probability
+            this.model = new BitSet(size);
+            this.sut = SimpleBitSet.allocate(size);
+        }
+
+        @Override
+        public boolean get(int i)
+        {
+            boolean expected = model.get(i);
+            boolean actual = sut.get(i);
+            Assertions.assertThat(actual).isEqualTo(expected);
+            return actual;
+        }
+
+        @Override
+        public boolean set(int i)
+        {
+            boolean expected = !model.get(i);
+            model.set(i);
+            boolean actual = sut.set(i);
+
+            Assertions.assertThat(actual).isEqualTo(expected);
+
+            return actual;
+        }
+
+        @Override
+        public boolean unset(int i)
+        {
+            boolean expected = model.get(i);
+            model.clear(i);
+            boolean actual = sut.unset(i);
+
+            Assertions.assertThat(actual).isEqualTo(expected);
+
+            return actual;
+        }
+
+        @Override
+        public void clear()
+        {
+            model.clear();
+            sut.clear();
+        }
+
+        @Override
+        public boolean isEmpty()
+        {
+            boolean expected = model.isEmpty();
+            boolean actual = sut.isEmpty();
+
+            Assertions.assertThat(actual).isEqualTo(expected);
+
+            return actual;
+        }
+
+        @Override
+        public int nextSetBit(int fromIndex)
+        {
+            int expected;
+            for (expected = fromIndex; expected < size; expected++)
+            {
+                if (model.get(expected))
+                    break;
+            }
+            if (expected == size)
+                expected = -1;
+            int actual = sut.nextSetBit(fromIndex);
+
+            Assertions.assertThat(actual).isEqualTo(expected);
+            return actual;
+        }
+
+        @Override
+        public int getSetBitCount()
+        {
+            return sut.getSetBitCount();
+        }
+
+        @Override
+        public String toString()
+        {
+            return sut.getClass().getSimpleName();
+        }
+    }
+}
\ No newline at end of file


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org
For additional commands, e-mail: commits-h...@cassandra.apache.org

Reply via email to