From 30407e1f4fc290468f3d8ec31cb933402767568d Mon Sep 17 00:00:00 2001 From: Pieter Noordhuis Date: Wed, 15 Dec 2010 00:42:32 +0100 Subject: [PATCH] Make SETBIT return original bit value --- src/t_string.c | 41 +++++++++++++++++++++++++---------------- tests/unit/basic.tcl | 24 ++++++++++++------------ 2 files changed, 37 insertions(+), 28 deletions(-) diff --git a/src/t_string.c b/src/t_string.c index 736b1673d..f1bab4dad 100644 --- a/src/t_string.c +++ b/src/t_string.c @@ -111,17 +111,18 @@ void setbitCommand(redisClient *c) { robj *o; char *err = "bit is not an integer or out of range"; size_t bitoffset; - long long bitvalue; - int byte, bit, on; + int byte, bit; + int byteval, bitval; + long on; if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK) return; - if (getLongLongFromObjectOrReply(c,c->argv[3],&bitvalue,err) != REDIS_OK) + if (getLongFromObjectOrReply(c,c->argv[3],&on,err) != REDIS_OK) return; - /* A bit can only be set to be on or off... */ - if (bitvalue & ~1) { + /* Bits can only be set or cleared... */ + if (on & ~1) { addReplyError(c,err); return; } @@ -142,23 +143,30 @@ void setbitCommand(redisClient *c) { } } + /* Grow sds value to the right length if necessary */ byte = bitoffset >> 3; - bit = 7 - (bitoffset & 0x7); - on = bitvalue & 0x1; 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]); server.dirty++; - addReply(c,shared.cone); + addReply(c, bitval ? shared.cone : shared.czero); } void getbitCommand(redisClient *c) { robj *o; - size_t bitoffset, byte, bitmask; - int on = 0; char llbuf[32]; + size_t bitoffset; + size_t byte, bit; + size_t bitval = 0; if (getBitOffsetFromArgument(c,c->argv[2],&bitoffset) != REDIS_OK) return; @@ -167,15 +175,16 @@ void getbitCommand(redisClient *c) { checkType(c,o,REDIS_STRING)) return; byte = bitoffset >> 3; - bitmask = 1 << (7 - (bitoffset & 0x7)); + bit = 7 - (bitoffset & 0x7); if (o->encoding != REDIS_ENCODING_RAW) { if (byte < (size_t)ll2string(llbuf,sizeof(llbuf),(long)o->ptr)) - on = llbuf[byte] & bitmask; + bitval = llbuf[byte] & (1 << bit); } else { 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) { diff --git a/tests/unit/basic.tcl b/tests/unit/basic.tcl index 7d5667726..901507964 100644 --- a/tests/unit/basic.tcl +++ b/tests/unit/basic.tcl @@ -377,29 +377,29 @@ start_server {tags {"basic"}} { test "SETBIT against non-existing key" { r del mykey - - # Setting 2nd bit to on is integer 64, ascii "@" - assert_equal 1 [r setbit mykey 1 1] - assert_equal "@" [r get mykey] + assert_equal 0 [r setbit mykey 1 1] + assert_equal [binary format B* 01000000] [r get mykey] } test "SETBIT against string-encoded key" { - # Single byte with 2nd bit set + # Ascii "@" is integer 64 = 01 00 00 00 r set mykey "@" - # 64 + 32 = 96 => ascii "`" (backtick) - assert_equal 1 [r setbit mykey 2 1] - assert_equal "`" [r get mykey] + assert_equal 0 [r setbit mykey 2 1] + assert_equal [binary format B* 01100000] [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" { + # Ascii "1" is integer 49 = 00 11 00 01 r set mykey 1 assert_encoding int mykey - # Ascii "1" is integer 49 = 00 11 00 01 - # Setting 7th bit = 51 => ascii "3" - assert_equal 1 [r setbit mykey 6 1] - assert_equal "3" [r get mykey] + assert_equal 0 [r setbit mykey 6 1] + assert_equal [binary format B* 00110011] [r get mykey] + assert_equal 1 [r setbit mykey 2 0] + assert_equal [binary format B* 00010011] [r get mykey] } test "SETBIT against key with wrong type" {