Skip to content

Commit

Permalink
Support BIT/BYTE for bitcount and bitpos for redis 7+
Browse files Browse the repository at this point in the history
  • Loading branch information
fatkodima committed Dec 9, 2023
1 parent eb72f82 commit d04583b
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 7 deletions.
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 bites
# @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: 'BYTE')
command = [:bitcount, key, start, stop]
command << 'BIT' if scale.to_s.upcase == 'BIT'
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 bites
# @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: 'BYTE')
raise(ArgumentError, 'stop parameter specified without start parameter') if stop && !start

command = [:bitpos, key, bit]
command << start if start
command << stop if stop
command << 'BIT' if scale.to_s.upcase == 'BIT'
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: 'BYTE')
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: 'BYTE')
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

0 comments on commit d04583b

Please sign in to comment.