Skip to content

Commit b925816

Browse files
authored
Add support up to max unsigned integer in Bitfield offset (#2964) (#3099)
* Add support up to max unsigned integer in Bitfield offset (#2964) * Add test for reactive command
1 parent f48b43d commit b925816

File tree

3 files changed

+65
-24
lines changed

3 files changed

+65
-24
lines changed

src/main/java/io/lettuce/core/BitFieldArgs.java

Lines changed: 21 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ private Builder() {
7070
* Create a new {@code GET} subcommand.
7171
*
7272
* @param bitFieldType the bit field type, must not be {@code null}.
73-
* @param offset bitfield offset
73+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
7474
* @return a new {@code GET} subcommand for the given {@code bitFieldType} and {@code offset}.
7575
*/
7676
public static BitFieldArgs get(BitFieldType bitFieldType, int offset) {
@@ -93,7 +93,7 @@ public static BitFieldArgs get(BitFieldType bitFieldType, Offset offset) {
9393
* Create a new {@code SET} subcommand.
9494
*
9595
* @param bitFieldType the bit field type, must not be {@code null}.
96-
* @param offset bitfield offset
96+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
9797
* @param value the value
9898
* @return a new {@code SET} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
9999
*/
@@ -118,7 +118,7 @@ public static BitFieldArgs set(BitFieldType bitFieldType, Offset offset, long va
118118
* Create a new {@code INCRBY} subcommand.
119119
*
120120
* @param bitFieldType the bit field type, must not be {@code null}.
121-
* @param offset bitfield offset
121+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
122122
* @param value the value
123123
* @return a new {@code INCRBY} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value} .
124124
*/
@@ -177,7 +177,7 @@ public static BitFieldType unsigned(int bits) {
177177
/**
178178
* Creates a new {@link Offset} for the given {@code offset}.
179179
*
180-
* @param offset zero-based offset.
180+
* @param offset zero-based offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
181181
* @return the {@link Offset}.
182182
* @since 4.3
183183
*/
@@ -233,7 +233,7 @@ public BitFieldArgs get(BitFieldType bitFieldType) {
233233
* Adds a new {@code GET} subcommand.
234234
*
235235
* @param bitFieldType the bit field type, must not be {@code null}.
236-
* @param offset bitfield offset
236+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
237237
* @return a new {@code GET} subcommand for the given {@code bitFieldType} and {@code offset}.
238238
*/
239239
public BitFieldArgs get(BitFieldType bitFieldType, int offset) {
@@ -258,7 +258,7 @@ public BitFieldArgs get(BitFieldType bitFieldType, Offset offset) {
258258
/**
259259
* Adds a new {@code GET} subcommand using the field type of the previous command.
260260
*
261-
* @param offset bitfield offset
261+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
262262
* @return a new {@code GET} subcommand for the given {@code bitFieldType} and {@code offset}.
263263
* @throws IllegalStateException if no previous field type was found
264264
*/
@@ -291,7 +291,7 @@ public BitFieldArgs set(BitFieldType bitFieldType, long value) {
291291
/**
292292
* Adds a new {@code SET} subcommand using the field type of the previous command.
293293
*
294-
* @param offset bitfield offset
294+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
295295
* @param value the value
296296
* @return a new {@code SET} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
297297
* @throws IllegalStateException if no previous field type was found
@@ -304,7 +304,7 @@ public BitFieldArgs set(int offset, long value) {
304304
* Adds a new {@code SET} subcommand.
305305
*
306306
* @param bitFieldType the bit field type, must not be {@code null}.
307-
* @param offset bitfield offset
307+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
308308
* @param value the value
309309
* @return a new {@code SET} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
310310
*/
@@ -353,7 +353,7 @@ public BitFieldArgs incrBy(BitFieldType bitFieldType, long value) {
353353
/**
354354
* Adds a new {@code INCRBY} subcommand using the field type of the previous command.
355355
*
356-
* @param offset bitfield offset
356+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
357357
* @param value the value
358358
* @return a new {@code INCRBY} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
359359
* @throws IllegalStateException if no previous field type was found
@@ -366,7 +366,7 @@ public BitFieldArgs incrBy(int offset, long value) {
366366
* Adds a new {@code INCRBY} subcommand.
367367
*
368368
* @param bitFieldType the bit field type, must not be {@code null}.
369-
* @param offset bitfield offset
369+
* @param offset bitfield offset, supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}.
370370
* @param value the value
371371
* @return a new {@code INCRBY} subcommand for the given {@code bitFieldType}, {@code offset} and {@code value}.
372372
*/
@@ -432,14 +432,13 @@ private static class Set extends SubCommand {
432432

433433
private final boolean bitOffset;
434434

435-
private final long offset;
435+
private final int offset;
436436

437437
private final long value;
438438

439439
private Set(BitFieldType bitFieldType, boolean bitOffset, int offset, long value) {
440440

441441
LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null");
442-
LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0");
443442

444443
this.bitFieldType = bitFieldType;
445444
this.bitOffset = bitOffset;
@@ -453,9 +452,9 @@ <K, V> void build(CommandArgs<K, V> args) {
453452
args.add(CommandType.SET).add(bitFieldType.asString());
454453

455454
if (bitOffset) {
456-
args.add("#" + offset);
455+
args.add("#" + Integer.toUnsignedString(offset));
457456
} else {
458-
args.add(offset);
457+
args.add(Integer.toUnsignedString(offset));
459458
}
460459

461460
args.add(value);
@@ -477,7 +476,6 @@ private static class Get extends SubCommand {
477476
private Get(BitFieldType bitFieldType, boolean bitOffset, int offset) {
478477

479478
LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null");
480-
LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0");
481479

482480
this.bitFieldType = bitFieldType;
483481
this.bitOffset = bitOffset;
@@ -490,9 +488,9 @@ <K, V> void build(CommandArgs<K, V> args) {
490488
args.add(CommandType.GET).add(bitFieldType.asString());
491489

492490
if (bitOffset) {
493-
args.add("#" + offset);
491+
args.add("#" + Integer.toUnsignedString(offset));
494492
} else {
495-
args.add(offset);
493+
args.add(Integer.toUnsignedString(offset));
496494
}
497495
}
498496

@@ -507,14 +505,13 @@ private static class IncrBy extends SubCommand {
507505

508506
private final boolean bitOffset;
509507

510-
private final long offset;
508+
private final int offset;
511509

512510
private final long value;
513511

514512
private IncrBy(BitFieldType bitFieldType, boolean offsetWidthMultiplier, int offset, long value) {
515513

516514
LettuceAssert.notNull(bitFieldType, "BitFieldType must not be null");
517-
LettuceAssert.isTrue(offset > -1, "Offset must be greater or equal to 0");
518515

519516
this.bitFieldType = bitFieldType;
520517
this.bitOffset = offsetWidthMultiplier;
@@ -528,9 +525,9 @@ <K, V> void build(CommandArgs<K, V> args) {
528525
args.add(CommandType.INCRBY).add(bitFieldType.asString());
529526

530527
if (bitOffset) {
531-
args.add("#" + offset);
528+
args.add("#" + Integer.toUnsignedString(offset));
532529
} else {
533-
args.add(offset);
530+
args.add(Integer.toUnsignedString(offset));
534531
}
535532

536533
args.add(value);
@@ -646,8 +643,8 @@ public String toString() {
646643
}
647644

648645
/**
649-
* Represents a bit field offset. See also <a href="https://redis.io/commands/bitfield#bits-and-positional-offsets">Bits and
650-
* positional offsets</a>
646+
* Represents a bit field offset. Offset supports up to {@code 2^32-1} using {@link Integer#toUnsignedString(int)}. See also
647+
* <a href="https://redis.io/commands/bitfield#bits-and-positional-offsets">Bits and positional offsets</a>
651648
*
652649
* @since 4.3
653650
*/
@@ -681,7 +678,7 @@ public int getOffset() {
681678

682679
@Override
683680
public String toString() {
684-
return (multiplyByTypeWidth ? "#" : "") + offset;
681+
return (multiplyByTypeWidth ? "#" : "") + Integer.toUnsignedString(offset);
685682
}
686683

687684
}

src/test/java/io/lettuce/core/commands/BitCommandIntegrationTests.java

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,9 @@ void bitfieldArgsTest() {
121121

122122
assertThat(offset(5).toString()).isEqualTo("5");
123123
assertThat(typeWidthBasedOffset(5).toString()).isEqualTo("#5");
124+
125+
assertThat(offset(-1).toString()).isEqualTo(Integer.toUnsignedString(-1));
126+
assertThat(typeWidthBasedOffset(-1).toString()).isEqualTo("#" + Integer.toUnsignedString(-1));
124127
}
125128

126129
@Test
@@ -147,6 +150,18 @@ void bitfieldGetWithOffset() {
147150
assertThat(bitstring.get(key)).isEqualTo("10000000");
148151
}
149152

153+
@Test
154+
@EnabledOnCommand("BITFIELD")
155+
void bitfieldGetWithUnsignedOffset() {
156+
157+
long unsignedIntMax = (1L << 32) - 1;
158+
BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 1).get(signed(1), (int) unsignedIntMax);
159+
160+
List<Long> values = redis.bitfield(key, bitFieldArgs);
161+
162+
assertThat(values).containsExactly(0L, 0L);
163+
}
164+
150165
@Test
151166
@EnabledOnCommand("BITFIELD")
152167
void bitfieldSet() {
@@ -171,6 +186,16 @@ void bitfieldWithOffsetSet() {
171186
assertThat(bitstring.get(key)).isEqualTo("1000000000000010");
172187
}
173188

189+
@Test
190+
@EnabledOnCommand("BITFIELD")
191+
void bitfieldWithUnsignedOffsetSet() {
192+
193+
long unsignedIntMax = (1L << 32) - 1;
194+
redis.bitfield(key, BitFieldArgs.Builder.set(signed(1), offset((int) unsignedIntMax), 1));
195+
assertThat(bitstring.getbit(key, unsignedIntMax)).isEqualTo(1);
196+
assertThat(bitstring.bitcount(key)).isEqualTo(1);
197+
}
198+
174199
@Test
175200
@EnabledOnCommand("BITFIELD")
176201
void bitfieldIncrBy() {
@@ -195,6 +220,16 @@ void bitfieldWithOffsetIncrBy() {
195220
assertThat(bitstring.get(key)).isEqualTo("0000000000000010");
196221
}
197222

223+
@Test
224+
@EnabledOnCommand("BITFIELD")
225+
void bitfieldWithUnsignedOffsetIncryBy() {
226+
227+
long unsignedIntMax = (1L << 32) - 1;
228+
redis.bitfield(key, BitFieldArgs.Builder.incrBy(signed(1), offset((int) unsignedIntMax), 1));
229+
assertThat(bitstring.getbit(key, unsignedIntMax)).isEqualTo(1);
230+
assertThat(bitstring.bitcount(key)).isEqualTo(1);
231+
}
232+
198233
@Test
199234
@EnabledOnCommand("BITFIELD")
200235
void bitfieldOverflow() {

src/test/java/io/lettuce/core/commands/reactive/BitReactiveCommandIntegrationTests.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ void bitfieldGetWithOffset() {
5656
assertThat(bitstring.get(key)).isEqualTo("10000000");
5757
}
5858

59+
@Test
60+
void bitfieldGetWithUnsignedOffset() {
61+
62+
long unsignedIntMax = (1L << 32) - 1;
63+
BitFieldArgs bitFieldArgs = BitFieldArgs.Builder.set(signed(8), 0, 1).get(signed(1), (int) unsignedIntMax);
64+
65+
StepVerifier.create(reactive.bitfield(key, bitFieldArgs)).expectNext(Value.just(0L), Value.just(0L)).verifyComplete();
66+
}
67+
5968
@Test
6069
void bitfieldSet() {
6170

0 commit comments

Comments
 (0)