Make SETBIT return original bit value
This commit is contained in:
parent
6a246b1e7e
commit
30407e1f4f
@ -111,17 +111,18 @@ void setbitCommand(redisClient *c) {
|
|||||||
robj *o;
|
robj *o;
|
||||||
char *err = "bit is not an integer or out of range";
|
char *err = "bit is not an integer or out of range";
|
||||||
size_t bitoffset;
|
size_t bitoffset;
|
||||||
long long bitvalue;
|
int byte, bit;
|
||||||
int byte, bit, on;
|
int byteval, bitval;
|
||||||
|
long on;
|
||||||
|
|
||||||
if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK)
|
if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (getLongLongFromObjectOrReply(c,c->argv[3],&bitvalue,err) != REDIS_OK)
|
if (getLongFromObjectOrReply(c,c->argv[3],&on,err) != REDIS_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* A bit can only be set to be on or off... */
|
/* Bits can only be set or cleared... */
|
||||||
if (bitvalue & ~1) {
|
if (on & ~1) {
|
||||||
addReplyError(c,err);
|
addReplyError(c,err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -142,23 +143,30 @@ void setbitCommand(redisClient *c) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Grow sds value to the right length if necessary */
|
||||||
byte = bitoffset >> 3;
|
byte = bitoffset >> 3;
|
||||||
bit = 7 - (bitoffset & 0x7);
|
|
||||||
on = bitvalue & 0x1;
|
|
||||||
o->ptr = sdsgrowzero(o->ptr,byte+1);
|
o->ptr = sdsgrowzero(o->ptr,byte+1);
|
||||||
((char*)o->ptr)[byte] |= on << bit;
|
|
||||||
((char*)o->ptr)[byte] &= ~((!on) << bit);
|
|
||||||
|
|
||||||
|
/* Get current values */
|
||||||
|
byteval = ((char*)o->ptr)[byte];
|
||||||
|
bit = 7 - (bitoffset & 0x7);
|
||||||
|
bitval = byteval & (1 << bit);
|
||||||
|
|
||||||
|
/* Update byte with new bit value and return original value */
|
||||||
|
byteval &= ~(1 << bit);
|
||||||
|
byteval |= ((on & 0x1) << bit);
|
||||||
|
((char*)o->ptr)[byte] = byteval;
|
||||||
touchWatchedKey(c->db,c->argv[1]);
|
touchWatchedKey(c->db,c->argv[1]);
|
||||||
server.dirty++;
|
server.dirty++;
|
||||||
addReply(c,shared.cone);
|
addReply(c, bitval ? shared.cone : shared.czero);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getbitCommand(redisClient *c) {
|
void getbitCommand(redisClient *c) {
|
||||||
robj *o;
|
robj *o;
|
||||||
size_t bitoffset, byte, bitmask;
|
|
||||||
int on = 0;
|
|
||||||
char llbuf[32];
|
char llbuf[32];
|
||||||
|
size_t bitoffset;
|
||||||
|
size_t byte, bit;
|
||||||
|
size_t bitval = 0;
|
||||||
|
|
||||||
if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK)
|
if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK)
|
||||||
return;
|
return;
|
||||||
@ -167,15 +175,16 @@ void getbitCommand(redisClient *c) {
|
|||||||
checkType(c,o,REDIS_STRING)) return;
|
checkType(c,o,REDIS_STRING)) return;
|
||||||
|
|
||||||
byte = bitoffset >> 3;
|
byte = bitoffset >> 3;
|
||||||
bitmask = 1 << (7 - (bitoffset & 0x7));
|
bit = 7 - (bitoffset & 0x7);
|
||||||
if (o->encoding != REDIS_ENCODING_RAW) {
|
if (o->encoding != REDIS_ENCODING_RAW) {
|
||||||
if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr))
|
if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr))
|
||||||
on = llbuf[byte] & bitmask;
|
bitval = llbuf[byte] & (1 << bit);
|
||||||
} else {
|
} else {
|
||||||
if (byte < sdslen(o->ptr))
|
if (byte < sdslen(o->ptr))
|
||||||
on = ((sds)o->ptr)[byte] & bitmask;
|
bitval = ((char*)o->ptr)[byte] & (1 << bit);
|
||||||
}
|
}
|
||||||
addReply(c, on ? shared.cone : shared.czero);
|
|
||||||
|
addReply(c, bitval ? shared.cone : shared.czero);
|
||||||
}
|
}
|
||||||
|
|
||||||
void setrangeCommand(redisClient *c) {
|
void setrangeCommand(redisClient *c) {
|
||||||
|
@ -377,29 +377,29 @@ start_server {tags {"basic"}} {
|
|||||||
|
|
||||||
test "SETBIT against non-existing key" {
|
test "SETBIT against non-existing key" {
|
||||||
r del mykey
|
r del mykey
|
||||||
|
assert_equal 0 [r setbit mykey 1 1]
|
||||||
# Setting 2nd bit to on is integer 64, ascii "@"
|
assert_equal [binary format B* 01000000] [r get mykey]
|
||||||
assert_equal 1 [r setbit mykey 1 1]
|
|
||||||
assert_equal "@" [r get mykey]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test "SETBIT against string-encoded key" {
|
test "SETBIT against string-encoded key" {
|
||||||
# Single byte with 2nd bit set
|
# Ascii "@" is integer 64 = 01 00 00 00
|
||||||
r set mykey "@"
|
r set mykey "@"
|
||||||
|
|
||||||
# 64 + 32 = 96 => ascii "`" (backtick)
|
assert_equal 0 [r setbit mykey 2 1]
|
||||||
assert_equal 1 [r setbit mykey 2 1]
|
assert_equal [binary format B* 01100000] [r get mykey]
|
||||||
assert_equal "`" [r get mykey]
|
assert_equal 1 [r setbit mykey 1 0]
|
||||||
|
assert_equal [binary format B* 00100000] [r get mykey]
|
||||||
}
|
}
|
||||||
|
|
||||||
test "SETBIT against integer-encoded key" {
|
test "SETBIT against integer-encoded key" {
|
||||||
|
# Ascii "1" is integer 49 = 00 11 00 01
|
||||||
r set mykey 1
|
r set mykey 1
|
||||||
assert_encoding int mykey
|
assert_encoding int mykey
|
||||||
|
|
||||||
# Ascii "1" is integer 49 = 00 11 00 01
|
assert_equal 0 [r setbit mykey 6 1]
|
||||||
# Setting 7th bit = 51 => ascii "3"
|
assert_equal [binary format B* 00110011] [r get mykey]
|
||||||
assert_equal 1 [r setbit mykey 6 1]
|
assert_equal 1 [r setbit mykey 2 0]
|
||||||
assert_equal "3" [r get mykey]
|
assert_equal [binary format B* 00010011] [r get mykey]
|
||||||
}
|
}
|
||||||
|
|
||||||
test "SETBIT against key with wrong type" {
|
test "SETBIT against key with wrong type" {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user