Merge 00a7f7173c
into 804110a487
This commit is contained in:
commit
b8ad30a75f
20
src/bitops.c
20
src/bitops.c
|
@ -771,7 +771,7 @@ void bitopCommand(client *c) {
|
|||
addReplyLongLong(c,maxlen); /* Return the output string length in bytes. */
|
||||
}
|
||||
|
||||
/* BITCOUNT key [start end [BIT|BYTE]] */
|
||||
/* BITCOUNT key [start [end [BIT|BYTE]]] */
|
||||
void bitcountCommand(client *c) {
|
||||
robj *o;
|
||||
long long start, end;
|
||||
|
@ -782,11 +782,9 @@ void bitcountCommand(client *c) {
|
|||
unsigned char first_byte_neg_mask = 0, last_byte_neg_mask = 0;
|
||||
|
||||
/* Parse start/end range if any. */
|
||||
if (c->argc == 4 || c->argc == 5) {
|
||||
if (c->argc == 3 || c->argc == 4 || c->argc == 5) {
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[2],&start,NULL) != C_OK)
|
||||
return;
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[3],&end,NULL) != C_OK)
|
||||
return;
|
||||
if (c->argc == 5) {
|
||||
if (!strcasecmp(c->argv[4]->ptr,"bit")) isbit = 1;
|
||||
else if (!strcasecmp(c->argv[4]->ptr,"byte")) isbit = 0;
|
||||
|
@ -795,21 +793,32 @@ void bitcountCommand(client *c) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
if (c->argc >= 4) {
|
||||
if (getLongLongFromObjectOrReply(c,c->argv[3],&end,NULL) != C_OK)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Lookup, check for type. */
|
||||
o = lookupKeyRead(c->db, c->argv[1]);
|
||||
if (checkType(c, o, OBJ_STRING)) return;
|
||||
p = getObjectReadOnlyString(o,&strlen,llbuf);
|
||||
long long totlen = strlen;
|
||||
|
||||
/* Make sure we will not overflow */
|
||||
long long totlen = strlen;
|
||||
serverAssert(totlen <= LLONG_MAX >> 3);
|
||||
|
||||
if (c->argc < 4) {
|
||||
if (isbit) end = (totlen<<3) + 7;
|
||||
else end = totlen-1;
|
||||
}
|
||||
|
||||
/* Convert negative indexes */
|
||||
if (start < 0 && end < 0 && start > end) {
|
||||
addReply(c,shared.czero);
|
||||
return;
|
||||
}
|
||||
if (isbit) totlen <<= 3;
|
||||
/* Convert negative indexes */
|
||||
if (start < 0) start = totlen+start;
|
||||
if (end < 0) end = totlen+end;
|
||||
if (start < 0) start = 0;
|
||||
|
@ -828,6 +837,7 @@ void bitcountCommand(client *c) {
|
|||
o = lookupKeyRead(c->db, c->argv[1]);
|
||||
if (checkType(c, o, OBJ_STRING)) return;
|
||||
p = getObjectReadOnlyString(o,&strlen,llbuf);
|
||||
|
||||
/* The whole string. */
|
||||
start = 0;
|
||||
end = strlen-1;
|
||||
|
|
|
@ -51,23 +51,28 @@ keySpec BITCOUNT_Keyspecs[1] = {
|
|||
};
|
||||
#endif
|
||||
|
||||
/* BITCOUNT range unit argument table */
|
||||
struct COMMAND_ARG BITCOUNT_range_unit_Subargs[] = {
|
||||
/* BITCOUNT range end_unit_block unit argument table */
|
||||
struct COMMAND_ARG BITCOUNT_range_end_unit_block_unit_Subargs[] = {
|
||||
{MAKE_ARG("byte",ARG_TYPE_PURE_TOKEN,-1,"BYTE",NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
{MAKE_ARG("bit",ARG_TYPE_PURE_TOKEN,-1,"BIT",NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
};
|
||||
|
||||
/* BITCOUNT range end_unit_block argument table */
|
||||
struct COMMAND_ARG BITCOUNT_range_end_unit_block_Subargs[] = {
|
||||
{MAKE_ARG("end",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
{MAKE_ARG("unit",ARG_TYPE_ONEOF,-1,NULL,NULL,"7.0.0",CMD_ARG_OPTIONAL,2,NULL),.subargs=BITCOUNT_range_end_unit_block_unit_Subargs},
|
||||
};
|
||||
|
||||
/* BITCOUNT range argument table */
|
||||
struct COMMAND_ARG BITCOUNT_range_Subargs[] = {
|
||||
{MAKE_ARG("start",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
{MAKE_ARG("end",ARG_TYPE_INTEGER,-1,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
{MAKE_ARG("unit",ARG_TYPE_ONEOF,-1,NULL,NULL,"7.0.0",CMD_ARG_OPTIONAL,2,NULL),.subargs=BITCOUNT_range_unit_Subargs},
|
||||
{MAKE_ARG("end-unit-block",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,2,NULL),.subargs=BITCOUNT_range_end_unit_block_Subargs},
|
||||
};
|
||||
|
||||
/* BITCOUNT argument table */
|
||||
struct COMMAND_ARG BITCOUNT_Args[] = {
|
||||
{MAKE_ARG("key",ARG_TYPE_KEY,0,NULL,NULL,NULL,CMD_ARG_NONE,0,NULL)},
|
||||
{MAKE_ARG("range",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,3,NULL),.subargs=BITCOUNT_range_Subargs},
|
||||
{MAKE_ARG("range",ARG_TYPE_BLOCK,-1,NULL,NULL,NULL,CMD_ARG_OPTIONAL,2,NULL),.subargs=BITCOUNT_range_Subargs},
|
||||
};
|
||||
|
||||
/********** BITFIELD ********************/
|
||||
|
|
|
@ -54,24 +54,31 @@
|
|||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "end",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "unit",
|
||||
"type": "oneof",
|
||||
"name": "end-unit-block",
|
||||
"type": "block",
|
||||
"optional": true,
|
||||
"since": "7.0.0",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "byte",
|
||||
"type": "pure-token",
|
||||
"token": "BYTE"
|
||||
"name": "end",
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"name": "bit",
|
||||
"type": "pure-token",
|
||||
"token": "BIT"
|
||||
"name": "unit",
|
||||
"type": "oneof",
|
||||
"optional": true,
|
||||
"since": "7.0.0",
|
||||
"arguments": [
|
||||
{
|
||||
"name": "byte",
|
||||
"type": "pure-token",
|
||||
"token": "BYTE"
|
||||
},
|
||||
{
|
||||
"name": "bit",
|
||||
"type": "pure-token",
|
||||
"token": "BIT"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -128,6 +128,15 @@ start_server {tags {"bitops"}} {
|
|||
}
|
||||
}
|
||||
|
||||
test {BITCOUNT with start} {
|
||||
set s "foobar"
|
||||
r set s $s
|
||||
assert_equal [r bitcount s 0] [count_bits "foobar"]
|
||||
assert_equal [r bitcount s 1] [count_bits "oobar"]
|
||||
assert_equal [r bitcount s -1] [count_bits "r"]
|
||||
assert_equal [r bitcount s -2] [count_bits "ar"]
|
||||
}
|
||||
|
||||
test {BITCOUNT with start, end} {
|
||||
set s "foobar"
|
||||
r set s $s
|
||||
|
@ -150,12 +159,10 @@ start_server {tags {"bitops"}} {
|
|||
test {BITCOUNT with illegal arguments} {
|
||||
# Used to return 0 for non-existing key instead of errors
|
||||
r del s
|
||||
assert_error {ERR *syntax*} {r bitcount s 0}
|
||||
assert_error {ERR *syntax*} {r bitcount s 0 1 hello}
|
||||
assert_error {ERR *syntax*} {r bitcount s 0 1 hello hello2}
|
||||
|
||||
r set s 1
|
||||
assert_error {ERR *syntax*} {r bitcount s 0}
|
||||
assert_error {ERR *syntax*} {r bitcount s 0 1 hello}
|
||||
assert_error {ERR *syntax*} {r bitcount s 0 1 hello hello2}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue