This commit is contained in:
LiiNen 2024-04-18 10:13:50 +08:00 committed by GitHub
commit b8ad30a75f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 54 additions and 25 deletions

View File

@ -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;

View File

@ -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 ********************/

View File

@ -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"
}
]
}
]
}

View File

@ -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}
}