Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support BIT/BYTE for bitcount and bitpos for redis 7+ #1242

Merged
merged 1 commit into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions lib/redis/commands/bitmaps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ def getbit(key, offset)
# @param [String] key
# @param [Integer] start start index
# @param [Integer] stop stop index
# @param [String, Symbol] scale the scale of the offset range
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
# @return [Integer] the number of bits set to 1
def bitcount(key, start = 0, stop = -1)
send_command([:bitcount, key, start, stop])
def bitcount(key, start = 0, stop = -1, scale: nil)
command = [:bitcount, key, start, stop]
command << scale if scale
send_command(command)
end

# Perform a bitwise operation between strings and store the resulting string in a key.
Expand All @@ -51,14 +55,17 @@ def bitop(operation, destkey, *keys)
# @param [Integer] bit whether to look for the first 1 or 0 bit
# @param [Integer] start start index
# @param [Integer] stop stop index
# @param [String, Symbol] scale the scale of the offset range
# e.g. 'BYTE' - interpreted as a range of bytes, 'BIT' - interpreted as a range of bits
# @return [Integer] the position of the first 1/0 bit.
# -1 if looking for 1 and it is not found or start and stop are given.
def bitpos(key, bit, start = nil, stop = nil)
def bitpos(key, bit, start = nil, stop = nil, scale: nil)
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start

command = [:bitpos, key, bit]
command << start if start
command << stop if stop
command << scale if scale
send_command(command)
end
end
Expand Down
8 changes: 4 additions & 4 deletions lib/redis/distributed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -370,8 +370,8 @@ def append(key, value)
end

# Count the number of set bits in a range of the string value stored at key.
def bitcount(key, start = 0, stop = -1)
node_for(key).bitcount(key, start, stop)
def bitcount(key, start = 0, stop = -1, scale: nil)
node_for(key).bitcount(key, start, stop, scale: scale)
end

# Perform a bitwise operation between strings and store the resulting string in a key.
Expand All @@ -383,8 +383,8 @@ def bitop(operation, destkey, *keys)
end

# Return the position of the first bit set to 1 or 0 in a string.
def bitpos(key, bit, start = nil, stop = nil)
node_for(key).bitpos(key, bit, start, stop)
def bitpos(key, bit, start = nil, stop = nil, scale: nil)
node_for(key).bitpos(key, bit, start, stop, scale: scale)
end

# Set the string value of a key and return its old value.
Expand Down
9 changes: 9 additions & 0 deletions test/lint/strings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,15 @@ def test_bitcount
assert_equal 17, r.bitcount("foo", 0, -1)
end

def test_bitcount_bits_range
target_version "7.0" do
r.set("foo", "abcde")

assert_equal 10, r.bitcount("foo", 8, 31, scale: :bit)
assert_equal 17, r.bitcount("foo", 0, -1, scale: :byte)
end
end

def test_getrange
r.set("foo", "abcde")

Expand Down
8 changes: 8 additions & 0 deletions test/redis/bitpos_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ def test_bitpos_one_intervals
assert_equal(8, r.bitpos("foo", 1, 1, 1))
end

def test_bitpos_one_intervals_bit_range
target_version "7.0" do
r.set "foo", "\x00\xff\x00"
assert_equal(8, r.bitpos("foo", 1, 8, -1, scale: 'bit'))
assert_equal(-1, r.bitpos("foo", 1, 8, -1, scale: 'byte'))
end
end

def test_bitpos_raise_exception_if_stop_not_start
assert_raises(ArgumentError) do
r.bitpos("foo", 0, nil, 2)
Expand Down
Loading