Skip to content
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
24 changes: 24 additions & 0 deletions lib/redis/commands/bitmaps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,30 @@ def bitpos(key, bit, start = nil, stop = nil, scale: nil)
command << scale if scale
send_command(command)
end

# Return the offsets of the set (or clear) bits in a range of the string value stored at key.
#
# @example Offsets of the set bits in the whole string
# redis.bitrangeintarray("key", 0, -1) # => [1, 7, 9, 30]
# @example Clear bits in a bit range, at most two of them
# redis.bitrangeintarray("key", 24, 31, scale: :bit, zeros: true, limit: 2) # => [24, 25]
#
# @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
# @param [Integer] limit return at most this many offsets; in byte scale the byte
# holding the last match is completed, so a few more may be returned
# @param [Boolean] zeros return the offsets of the clear bits instead of the set bits
# @return [Array<Integer>] the matching bit offsets in ascending order
def bitrangeintarray(key, start, stop, scale: nil, limit: nil, zeros: false)
command = [:bitrangeintarray, key, start, stop]
command << scale if scale
command << "LIMIT" << limit if limit
command << "ZEROS" if zeros
send_command(command)
end
end
end
end
5 changes: 5 additions & 0 deletions lib/redis/distributed.rb
Original file line number Diff line number Diff line change
Expand Up @@ -572,6 +572,11 @@ def bitpos(key, bit, start = nil, stop = nil, scale: nil)
node_for(key).bitpos(key, bit, start, stop, scale: scale)
end

# Return the offsets of the set (or clear) bits in a range of the string value stored at key.
def bitrangeintarray(key, start, stop, scale: nil, limit: nil, zeros: false)
node_for(key).bitrangeintarray(key, start, stop, scale: scale, limit: limit, zeros: zeros)
end

# Set the string value of a key and return its old value.
def getset(key, value)
node_for(key).getset(key, value)
Expand Down
45 changes: 45 additions & 0 deletions test/lint/strings.rb
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,51 @@ def test_bitcount_bits_range
end
end

def test_bitrangeintarray
target_version "8.11" do
[1, 7, 9, 30].each { |offset| r.setbit("foo", offset, 1) }

assert_equal [1, 7, 9, 30], r.bitrangeintarray("foo", 0, -1)
assert_equal [9, 30], r.bitrangeintarray("foo", 1, -1)
assert_equal [], r.bitrangeintarray("foo", 10, 20)
assert_equal [], r.bitrangeintarray("nosuchkey", 0, -1)
end
end

def test_bitrangeintarray_bit_scale
target_version "8.11" do
[1, 7, 9, 30].each { |offset| r.setbit("foo", offset, 1) }

assert_equal [7, 9], r.bitrangeintarray("foo", 5, 10, scale: :bit)
end
end

def test_bitrangeintarray_zeros
target_version "8.11" do
[1, 7, 9, 30].each { |offset| r.setbit("foo", offset, 1) }

assert_equal [24, 25, 26, 27, 28, 29, 31], r.bitrangeintarray("foo", 24, 31, scale: :bit, zeros: true)
end
end

def test_bitrangeintarray_limit
target_version "8.11" do
[1, 7, 9, 30].each { |offset| r.setbit("foo", offset, 1) }

assert_equal [7, 9], r.bitrangeintarray("foo", 2, -1, scale: :bit, limit: 2)
# byte scale completes the byte holding the last match
assert_equal [1, 7], r.bitrangeintarray("foo", 0, -1, limit: 1)
end
end

def test_bitrangeintarray_wrong_type
target_version "8.11" do
r.sadd("foo", "a")

assert_raises(Redis::WrongTypeError) { r.bitrangeintarray("foo", 0, -1) }
end
end

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

Expand Down
Loading