@@ -3772,6 +3772,21 @@ private static ByteString binaryOperator(
37723772 return new ByteString (result );
37733773 }
37743774
3775+ /**
3776+ * Returns {@code x} modulo {@code m}, normalized to the range {@code [0, m)}
3777+ * (unlike {@code %}, the result is never negative). Used to normalize a shift
3778+ * amount to the bit width of the value being shifted.
3779+ *
3780+ * @param x the value (typically a shift amount, which may be negative)
3781+ * @param m the modulus, which must be positive (typically a bit width)
3782+ * @return {@code x} modulo {@code m}, in the range {@code [0, m)}
3783+ */
3784+ private static int positiveModulo (long x , int m ) {
3785+ // Math.floorMod(long, int) is only available since JDK 9, so widen to
3786+ // Math.floorMod(long, long) and narrow the result (always in [0, m)) to int.
3787+ return (int ) Math .floorMod (x , (long ) m );
3788+ }
3789+
37753790 /**
37763791 * Performs PostgresSQL-style bitwise shift on a 32-bit integer.
37773792 *
@@ -3780,7 +3795,7 @@ private static ByteString binaryOperator(
37803795 * @return the shifted integer
37813796 */
37823797 public static int leftShift (int x , long y ) {
3783- int shift = Math . floorMod (y , 32 ); // normalize to 0~31
3798+ int shift = positiveModulo (y , 32 ); // normalize to 0~31
37843799 return y >= 0 ? x << shift : x >> shift ; // arithmetic right shift
37853800 }
37863801
@@ -3794,7 +3809,7 @@ public static int leftShift(int x, long y) {
37943809 * @return the shifted long value
37953810 */
37963811 public static long leftShift (long x , long y ) {
3797- int shift = Math . floorMod (y , 64 ); // normalize to 0~63
3812+ int shift = positiveModulo (y , 64 ); // normalize to 0~63
37983813 return y >= 0 ? x << shift : x >> shift ;
37993814 }
38003815
@@ -3816,7 +3831,7 @@ public static byte[] leftShift(byte[] bytes, long y) {
38163831
38173832 // PostgreSQL behavior: always treat as left shift with modulo arithmetic
38183833 // Negative y becomes equivalent positive shift
3819- int shift = Math . floorMod (y , bitLen );
3834+ int shift = positiveModulo (y , bitLen );
38203835
38213836 if (shift == 0 ) {
38223837 return bytes .clone ();
@@ -3863,7 +3878,7 @@ public static ByteString leftShift(ByteString bytes, long y) {
38633878 * Overflow bits are masked to 8 bits.
38643879 */
38653880 public static UByte leftShift (UByte x , long y ) {
3866- int shift = Math . floorMod (y , 8 );
3881+ int shift = positiveModulo (y , 8 );
38673882 int val = x .byteValue () & 0xFF ;
38683883 val = (y >= 0 ) ? (val << shift ) & 0xFF : (val >> shift ) & 0xFF ;
38693884 return UByte .valueOf ((byte ) val );
@@ -3874,7 +3889,7 @@ public static UByte leftShift(UByte x, long y) {
38743889 * Overflow bits are masked to 16 bits.
38753890 */
38763891 public static UShort leftShift (UShort x , long y ) {
3877- int shift = Math . floorMod (y , 16 );
3892+ int shift = positiveModulo (y , 16 );
38783893 int val = x .shortValue () & 0xFFFF ;
38793894 val = (y >= 0 ) ? (val << shift ) & 0xFFFF : (val >> shift ) & 0xFFFF ;
38803895 return UShort .valueOf ((short ) val );
@@ -3885,7 +3900,7 @@ public static UShort leftShift(UShort x, long y) {
38853900 * Overflow bits are masked to 32 bits.
38863901 */
38873902 public static UInteger leftShift (UInteger x , long y ) {
3888- int shift = Math . floorMod (y , 32 );
3903+ int shift = positiveModulo (y , 32 );
38893904 long val = x .longValue () & 0xFFFFFFFFL ;
38903905 val = (y >= 0 ) ? (val << shift ) & 0xFFFFFFFFL : (val >> shift ) & 0xFFFFFFFFL ;
38913906 return UInteger .valueOf (val );
@@ -3896,7 +3911,7 @@ public static UInteger leftShift(UInteger x, long y) {
38963911 * Overflow bits are masked to 64 bits (long shifts naturally truncate).
38973912 */
38983913 public static ULong leftShift (ULong x , long y ) {
3899- int shift = Math . floorMod (y , 64 );
3914+ int shift = positiveModulo (y , 64 );
39003915 long val = x .longValue ();
39013916 val = (y >= 0 ) ? val << shift : val >> shift ;
39023917 return ULong .valueOf (val );
@@ -3910,7 +3925,7 @@ public static ULong leftShift(ULong x, long y) {
39103925 * @return the shifted integer
39113926 */
39123927 public static int rightShift (int x , long y ) {
3913- int shift = Math . floorMod (y , 32 ); // normalize to 0~31
3928+ int shift = positiveModulo (y , 32 ); // normalize to 0~31
39143929 return y >= 0 ? x >> shift : x << shift ; // arithmetic right shift
39153930 }
39163931
@@ -3924,7 +3939,7 @@ public static int rightShift(int x, long y) {
39243939 * @return the shifted long value
39253940 */
39263941 public static long rightShift (long x , long y ) {
3927- int shift = Math . floorMod (y , 64 ); // normalize to 0~63
3942+ int shift = positiveModulo (y , 64 ); // normalize to 0~63
39283943 return y >= 0 ? x >> shift : x << shift ;
39293944 }
39303945
@@ -3946,7 +3961,7 @@ public static byte[] rightShift(byte[] bytes, long y) {
39463961
39473962 // PostgreSQL behavior: always treat as right shift with modulo arithmetic
39483963 // Negative y becomes equivalent positive shift
3949- int shift = Math . floorMod (y , bitLen );
3964+ int shift = positiveModulo (y , bitLen );
39503965
39513966 if (shift == 0 ) {
39523967 return bytes .clone ();
@@ -3993,7 +4008,7 @@ public static ByteString rightShift(ByteString bytes, long y) {
39934008 * Overflow bits are masked to 8 bits.
39944009 */
39954010 public static UByte rightShift (UByte x , long y ) {
3996- int shift = Math . floorMod (y , 8 );
4011+ int shift = positiveModulo (y , 8 );
39974012 int val = x .byteValue () & 0xFF ;
39984013 val = (y >= 0 ) ? (val >> shift ) & 0xFF : (val << shift ) & 0xFF ;
39994014 return UByte .valueOf ((byte ) val );
@@ -4004,7 +4019,7 @@ public static UByte rightShift(UByte x, long y) {
40044019 * Overflow bits are masked to 16 bits.
40054020 */
40064021 public static UShort rightShift (UShort x , long y ) {
4007- int shift = Math . floorMod (y , 16 );
4022+ int shift = positiveModulo (y , 16 );
40084023 int val = x .shortValue () & 0xFFFF ;
40094024 val = (y >= 0 ) ? (val >> shift ) & 0xFFFF : (val << shift ) & 0xFFFF ;
40104025 return UShort .valueOf ((short ) val );
@@ -4015,7 +4030,7 @@ public static UShort rightShift(UShort x, long y) {
40154030 * Overflow bits are masked to 32 bits.
40164031 */
40174032 public static UInteger rightShift (UInteger x , long y ) {
4018- int shift = Math . floorMod (y , 32 );
4033+ int shift = positiveModulo (y , 32 );
40194034 long val = x .longValue () & 0xFFFFFFFFL ;
40204035 val = (y >= 0 ) ? (val >> shift ) & 0xFFFFFFFFL : (val << shift ) & 0xFFFFFFFFL ;
40214036 return UInteger .valueOf (val );
@@ -4026,7 +4041,7 @@ public static UInteger rightShift(UInteger x, long y) {
40264041 * Overflow bits are masked to 64 bits (long shifts naturally truncate).
40274042 */
40284043 public static ULong rightShift (ULong x , long y ) {
4029- int shift = Math . floorMod (y , 64 );
4044+ int shift = positiveModulo (y , 64 );
40304045 long val = x .longValue ();
40314046 val = (y >= 0 ) ? val >> shift : val << shift ;
40324047 return ULong .valueOf (val );
0 commit comments