Reputation: 877
As a practice exercise, I'm writing a lua script for Redis which basically executes the JavaScript method Array#copyWithin().
Quoting from MDN,
The copyWithin() method copies the sequence of array elements within the array to the position starting at target. The copy is taken from the index positions of the second and third arguments start and end.
Here is the script I've written so far :
local list = redis.call('lrange', KEYS[1], 0, -1)
local target = tonumber(ARGV[1])
local startIndex = tonumber(ARGV[2])
local len = #list
local endIndex = len
--Handle negative startIndex
if startIndex < 0 then
startIndex = len+startIndex
end
--If the third argument is provided, get the endIndex from it
if #ARGV > 2 then
local arg = tonumber(ARGV[3])
if arg >= 0 then
if arg < endIndex then
endIndex = arg
end
else
if len+arg >= 0 then
endIndex = len+arg
else
endIndex = 0
end
end
end
--An array containing the elements which will be copied
local targeted_elements = {}
--Fill elements from the list
for i=1, (endIndex-startIndex+1) do
targeted_elements[i] = list[startIndex+i]
end
--Make sure no additional elements are pushed to the end of array in case of range overflow
local target_end = #targeted_elements
if target + target_end > len then
target_end = len-target
end
--replace all the changed elements of the list in redis
for i=1, target_end do
redis.call('lset', KEYS[1], target+(i-1), targeted_elements[i])
end
During testing, the first test case is successfully cleared :
Test case : convert [1, 2, 3, 4, 5]
into [4, 5, 3, 4, 5]
using copyWithin(0, 3)
LRANGE MyList 0 -1
> [1, 2, 3, 4, 5]
EVALSHA "sha1 of script" 1 MyList 0 3
(basically the same as `[1, 2, 3, 4, 5].copyWithin(0, 3)`)
> nil
LRANGE MyList 0 -1
> [4, 5, 3, 4, 5]
The second test case however, did not go that smooth.
Test case : convert [1, 2, 3, 4, 5]
into [4, 2, 3, 4, 5]
using copyWithin(0, 3, 4)
LRANGE MyList 0 -1
> [1, 2, 3, 4, 5]
EVALSHA "sha1 of script" 1 MyList 0 3 4
(basically the same as `[1, 2, 3, 4, 5].copyWithin(0, 3, 4)`)
> nil
LRANGE MyList 0 -1
> [4, 5, 3, 4, 5]
After some debugging, I found that the value of targeted_elements
is {4, 5}
in both the cases, whereas it should be {4}
in case 2.
Is there anything suspicious in the loops? Any help would be great.
Upvotes: 2
Views: 273
Reputation: 877
I fixed this by modifying the following part of the script :
--Fill elements from the list
for i=1, (endIndex-startIndex+1) do
targeted_elements[i] = list[startIndex+i]
end
Changed it into this:
--Fill elements from the list
for i=1, (endIndex-startIndex) do
targeted_elements[i] = list[startIndex+i]
end
The +1
in the for
expression added an additional element to the array. It worked in the first case because the selected part was from 3, 5
, so 5-3+1 = 3
which means 3
elements should be selected. But since only 2
elements are left, the case still works.
Whereas for the second case, 4-3+1 = 2
, which means 2
elements were being selected, instead of 1
.
Upvotes: 2