Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ruanhaishen
redis
Commits
495327c0
Commit
495327c0
authored
Jun 11, 2020
by
antirez
Browse files
LPOS: update to latest proposal.
See
https://gist.github.com/antirez/3591c5096bc79cad8b5a992e08304f48
parent
afb8b3c0
Changes
1
Hide whitespace changes
Inline
Side-by-side
src/t_list.c
View file @
495327c0
...
@@ -487,63 +487,75 @@ void ltrimCommand(client *c) {
...
@@ -487,63 +487,75 @@ void ltrimCommand(client *c) {
addReply
(
c
,
shared
.
ok
);
addReply
(
c
,
shared
.
ok
);
}
}
/* LPOS key element [match
po
s] [
ALL] [RELATIVE
]
/* LPOS key element [
FIRST rank] [COUNT num-
match
e
s] [
MAXLEN len
]
*
*
*
matchnum
is the position of the match, so if it is 1, the first match
*
FIRST "rank"
is the position of the match, so if it is 1, the first match
* is returned, if it is 2 the second match is returned and so forth.
* is returned, if it is 2 the second match is returned and so forth.
* It is 1 by default. If negative has the same meaning but the search is
* It is 1 by default. If negative has the same meaning but the search is
* performed starting from the end of the list.
* performed starting from the end of the list.
*
*
* A matchnum of 0 is accepted only if ALL is given, and means to return
* If COUNT is given, instead of returning the single element, a list of
* all the elements.
* all the matching elements up to "num-matches" are returned. COUNT can
* be combiled with FIRST in order to returning only the element starting
* from the Nth. If COUNT is zero, all the matching elements are returned.
*
*
*
If ALL is given, instead of returning the single elmenet, a list of
*
MAXLEN tells the command to scan a max of len elements. If zero (the
*
all the matching elements up to "matchnum" are return
ed.
*
default), all the elements in the list are scanned if need
ed.
*
*
* The returned elements indexes are always referring to what LINDEX
* The returned elements indexes are always referring to what LINDEX
* would return. So first element from head is 0, and so forth.
* would return. So first element from head is 0, and so forth. */
* However if RELATIVE is given and a negative matchpos is given, the
* indexes are returned as if the last element of the list is the element 0,
* the penultimante is 1, and so forth. */
void
lposCommand
(
client
*
c
)
{
void
lposCommand
(
client
*
c
)
{
robj
*
o
,
*
ele
;
robj
*
o
,
*
ele
;
ele
=
c
->
argv
[
2
];
ele
=
c
->
argv
[
2
];
int
all
=
0
,
direction
=
LIST_TAIL
;
int
direction
=
LIST_TAIL
;
long
matchpos
=
1
;
long
rank
=
1
,
count
=
-
1
,
maxlen
=
0
;
/* Count -1: option not given. */
/* Parse the optional "matchpos" argument, and the ALL option. */
/* Parse the optional arguments. */
if
(
c
->
argc
>=
4
&&
for
(
int
j
=
3
;
j
<
c
->
argc
;
j
++
)
{
getLongFromObjectOrReply
(
c
,
c
->
argv
[
3
],
&
matchpos
,
NULL
)
!=
C_OK
)
char
*
opt
=
c
->
argv
[
j
]
->
ptr
;
{
int
moreargs
=
(
c
->
argc
-
1
)
-
j
;
return
;
}
if
(
c
->
argc
==
5
)
{
if
(
!
strcasecmp
(
opt
,
"FIRST"
)
&&
moreargs
)
{
if
(
!
strcasecmp
(
c
->
argv
[
4
]
->
ptr
,
"all"
))
{
j
++
;
all
=
1
;
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
j
],
&
rank
,
NULL
)
!=
C_OK
)
return
;
if
(
rank
==
0
)
{
addReplyError
(
c
,
"FIRST can't be zero: use 1 to start from "
"the first match, 2 from the second, ..."
);
return
;
}
}
else
if
(
!
strcasecmp
(
opt
,
"COUNT"
)
&&
moreargs
)
{
j
++
;
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
j
],
&
count
,
NULL
)
!=
C_OK
)
return
;
if
(
count
<
0
)
{
addReplyError
(
c
,
"COUNT can't be negative"
);
return
;
}
}
else
if
(
!
strcasecmp
(
opt
,
"MAXLEN"
)
&&
moreargs
)
{
j
++
;
if
(
getLongFromObjectOrReply
(
c
,
c
->
argv
[
j
],
&
maxlen
,
NULL
)
!=
C_OK
)
return
;
if
(
maxlen
<
0
)
{
addReplyError
(
c
,
"MAXLEN can't be negative"
);
return
;
}
}
else
{
}
else
{
addReply
(
c
,
shared
.
syntaxerr
);
addReply
(
c
,
shared
.
syntaxerr
);
return
;
return
;
}
}
}
}
/* Raise an error on incompatible options. */
/* A negative rank means start from the tail. */
if
(
!
all
&&
matchpos
==
0
)
{
if
(
rank
<
0
)
{
addReplyError
(
c
,
"A match position of zero is valid only "
rank
=
-
rank
;
"when using the ALL option"
);
return
;
}
/* A negative matchpos means start from the tail. */
if
(
matchpos
<
0
)
{
matchpos
=
-
matchpos
;
direction
=
LIST_HEAD
;
direction
=
LIST_HEAD
;
}
}
/* We return NULL or an empty array if there is no such key (or
/* We return NULL or an empty array if there is no such key (or
* if we find no matches, depending on the presence of the
ALL
option. */
* if we find no matches, depending on the presence of the
COUNT
option. */
if
((
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
NULL
))
==
NULL
)
{
if
((
o
=
lookupKeyWriteOrReply
(
c
,
c
->
argv
[
1
],
NULL
))
==
NULL
)
{
if
(
all
)
if
(
count
!=
-
1
)
addReply
(
c
,
shared
.
emptyarray
);
addReply
(
c
,
shared
.
emptyarray
);
else
else
addReply
(
c
,
shared
.
null
[
c
->
resp
]);
addReply
(
c
,
shared
.
null
[
c
->
resp
]);
...
@@ -551,9 +563,9 @@ void lposCommand(client *c) {
...
@@ -551,9 +563,9 @@ void lposCommand(client *c) {
}
}
if
(
checkType
(
c
,
o
,
OBJ_LIST
))
return
;
if
(
checkType
(
c
,
o
,
OBJ_LIST
))
return
;
/* If we got the
ALL
option, prepare to emit an array. */
/* If we got the
COUNT
option, prepare to emit an array. */
void
*
arraylenptr
=
NULL
;
void
*
arraylenptr
=
NULL
;
if
(
all
)
arraylenptr
=
addReplyDeferredLen
(
c
);
if
(
count
!=
-
1
)
arraylenptr
=
addReplyDeferredLen
(
c
);
/* Seek the element. */
/* Seek the element. */
listTypeIterator
*
li
;
listTypeIterator
*
li
;
...
@@ -561,21 +573,28 @@ void lposCommand(client *c) {
...
@@ -561,21 +573,28 @@ void lposCommand(client *c) {
listTypeEntry
entry
;
listTypeEntry
entry
;
long
llen
=
listTypeLength
(
o
);
long
llen
=
listTypeLength
(
o
);
long
index
=
0
,
matches
=
0
,
matchindex
=
-
1
;
long
index
=
0
,
matches
=
0
,
matchindex
=
-
1
;
while
(
listTypeNext
(
li
,
&
entry
))
{
while
(
listTypeNext
(
li
,
&
entry
)
&&
(
maxlen
==
0
||
index
<
maxlen
)
)
{
if
(
listTypeEqual
(
&
entry
,
ele
))
{
if
(
listTypeEqual
(
&
entry
,
ele
))
{
matches
++
;
matches
++
;
matchindex
=
(
direction
==
LIST_TAIL
)
?
index
:
llen
-
index
-
1
;
matchindex
=
(
direction
==
LIST_TAIL
)
?
index
:
llen
-
index
-
1
;
if
(
all
)
addReplyLongLong
(
c
,
matchindex
);
if
(
matches
>=
rank
)
{
if
(
matches
==
matchpos
)
break
;
if
(
arraylenptr
)
{
addReplyLongLong
(
c
,
matchindex
);
if
(
count
&&
matches
-
rank
+
1
>=
count
)
break
;
}
else
{
break
;
}
}
}
}
index
++
;
index
++
;
matchindex
=
-
1
;
/* Remember if we exit the loop without a match. */
}
}
listTypeReleaseIterator
(
li
);
listTypeReleaseIterator
(
li
);
/* Reply to the client. Note that arraylenptr is not NULL only if
/* Reply to the client. Note that arraylenptr is not NULL only if
* the
ALL
option was selected. */
* the
COUNT
option was selected. */
if
(
arraylenptr
!=
NULL
)
{
if
(
arraylenptr
!=
NULL
)
{
setDeferredArrayLen
(
c
,
arraylenptr
,
matches
);
setDeferredArrayLen
(
c
,
arraylenptr
,
matches
-
rank
+
1
);
}
else
{
}
else
{
if
(
matchindex
!=
-
1
)
if
(
matchindex
!=
-
1
)
addReplyLongLong
(
c
,
matchindex
);
addReplyLongLong
(
c
,
matchindex
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment