GROOVY-11306: Provide left/right shift operators for BitSet
diff --git a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java index 424bcdb..1f78e16 100644 --- a/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java +++ b/src/main/java/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -8561,6 +8561,26 @@ return NumberMath.leftShift(self, operand); } + /** + * Implementation of the left shift operator for BitSets, + * returning a new BitSet and leaving the original unchanged. + * The {@code intValue()} is taken for the shift distance for non-integer operands. + * + * @param self a BitSet + * @param operand the shift distance by which to shift the BitSet left + * @return the resulting BitSet + * @since 5.0.0 + */ + public static BitSet leftShift(BitSet self, Number operand) { + BitSet result = new BitSet(self.size()); + final int limit = self.size() - 1; + self.stream().forEach(i -> { + if (i < limit) + result.set(i + operand.intValue()); + }); + return result; + } + //-------------------------------------------------------------------------- // max @@ -11397,6 +11417,23 @@ return NumberMath.rightShift(self, operand); } + /** + * Implementation of the right shift operator for BitSets, + * returning a new BitSet and leaving the original unchanged. + * The {@code intValue()} is taken for the shift distance for non-integer operands. + * + * @param self a BitSet + * @param operand the shift distance by which to right shift the BitSet + * @return the resulting BitSet + * @since 5.0.0 + */ + public static BitSet rightShift(BitSet self, Number operand) { + boolean carry = self.get(self.size() - 1); + BitSet result = self.get(operand.intValue(), Math.max(operand.intValue(), self.length())); + result.set(self.size() - 1, carry); + return result; + } + //-------------------------------------------------------------------------- // rightShiftUnsigned @@ -11413,6 +11450,21 @@ return NumberMath.rightShiftUnsigned(self, operand); } + /** + * Implementation of the right shift (unsigned) operator for BitSets, + * returning a new BitSet and leaving the original unchanged. + * The {@code intValue()} is taken for the shift distance for non-integer operands. + * + * @param self a BitSet + * @param operand the shift distance by which to right shift (unsigned) the BitSet + * @return the resulting BitSet + * @since 5.0.0 + */ + public static BitSet rightShiftUnsigned(BitSet self, Number operand) { + return self.get(operand.intValue(), Math.max(operand.intValue(), self.length())); + } + + //-------------------------------------------------------------------------- // round
diff --git a/src/test/groovy/BitSetTest.groovy b/src/test/groovy/BitSetTest.groovy index 9910fca..25a7192 100644 --- a/src/test/groovy/BitSetTest.groovy +++ b/src/test/groovy/BitSetTest.groovy
@@ -162,6 +162,24 @@ assertBitFalse b, 3 } + void testLeftShift() { + def testCases = [ + [1, -12L], + [3, 271], + [1, (Long.MAX_VALUE/2 - 10).longValue()], + [1, (Long.MAX_VALUE/2 + 10).longValue()] + ] + testCases.each { int operand, long value -> + def a = BitSet.valueOf(value) + def b = BitSet.valueOf(value << operand) + def c = BitSet.valueOf(value >> operand) + def d = BitSet.valueOf(value >>> operand) + assert b == a << operand + assert c == a >> operand + assert d == a >>> operand + } + } + private assertBitTrue(bitset, index) { assertTrue 'index ' + index + ' should have been true', bitset[index] }