[6.0] src/bitops.c
This commit is contained in:
+42
-19
@@ -36,7 +36,7 @@
|
||||
|
||||
/* Count number of bits set in the binary array pointed by 's' and long
|
||||
* 'count' bytes. The implementation of this function is required to
|
||||
* work with a input string length up to 512 MB. */
|
||||
* work with an input string length up to 512 MB. */
|
||||
size_t redisPopcount(void *s, PORT_LONG count) {
|
||||
size_t bits = 0;
|
||||
unsigned char *p = s;
|
||||
@@ -107,7 +107,7 @@ PORT_LONG redisBitpos(void *s, PORT_ULONG count, int bit) {
|
||||
int found;
|
||||
|
||||
/* Process whole words first, seeking for first word that is not
|
||||
* all ones or all zeros respectively if we are lookig for zeros
|
||||
* all ones or all zeros respectively if we are looking for zeros
|
||||
* or ones. This is much faster with large strings having contiguous
|
||||
* blocks of 1 or 0 bits compared to the vanilla bit per bit processing.
|
||||
*
|
||||
@@ -257,7 +257,7 @@ int64_t getSignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits) {
|
||||
/* If the top significant bit is 1, propagate it to all the
|
||||
* higher bits for two's complement representation of signed
|
||||
* integers. */
|
||||
if (value & ((uint64_t)1 << (bits-1)))
|
||||
if (bits < 64 && (value & ((uint64_t)1 << (bits-1))))
|
||||
value |= ((uint64_t)-1) << bits;
|
||||
return value;
|
||||
}
|
||||
@@ -269,7 +269,7 @@ int64_t getSignedBitfield(unsigned char *p, uint64_t offset, uint64_t bits) {
|
||||
* then zero is returned, otherwise in case of overflow, 1 is returned,
|
||||
* otherwise in case of underflow, -1 is returned.
|
||||
*
|
||||
* When non-zero is returned (oferflow or underflow), if not NULL, *limit is
|
||||
* When non-zero is returned (overflow or underflow), if not NULL, *limit is
|
||||
* set to the value the operation should result when an overflow happens,
|
||||
* depending on the specified overflow semantics:
|
||||
*
|
||||
@@ -356,7 +356,6 @@ int checkSignedBitfieldOverflow(int64_t value, int64_t incr, uint64_t bits, int
|
||||
|
||||
handle_wrap:
|
||||
{
|
||||
uint64_t mask = ((uint64_t)-1) << bits;
|
||||
uint64_t msb = (uint64_t)1 << (bits-1);
|
||||
uint64_t a = value, b = incr, c;
|
||||
c = a+b; /* Perform addition as unsigned so that's defined. */
|
||||
@@ -364,10 +363,13 @@ handle_wrap:
|
||||
/* If the sign bit is set, propagate to all the higher order
|
||||
* bits, to cap the negative value. If it's clear, mask to
|
||||
* the positive integer limit. */
|
||||
if (c & msb) {
|
||||
c |= mask;
|
||||
} else {
|
||||
c &= ~mask;
|
||||
if (bits < 64) {
|
||||
uint64_t mask = ((uint64_t)-1) << bits;
|
||||
if (c & msb) {
|
||||
c |= mask;
|
||||
} else {
|
||||
c &= ~mask;
|
||||
}
|
||||
}
|
||||
*limit = c;
|
||||
}
|
||||
@@ -494,7 +496,7 @@ robj *lookupStringForBitCommand(client *c, size_t maxbit) {
|
||||
* in 'len'. The user is required to pass (likely stack allocated) buffer
|
||||
* 'llbuf' of at least LONG_STR_SIZE bytes. Such a buffer is used in the case
|
||||
* the object is integer encoded in order to provide the representation
|
||||
* without usign heap allocation.
|
||||
* without using heap allocation.
|
||||
*
|
||||
* The function returns the pointer to the object array of bytes representing
|
||||
* the string it contains, that may be a pointer to 'llbuf' or to the
|
||||
@@ -554,7 +556,7 @@ void setbitCommand(client *c) {
|
||||
byteval &= ~(1 << bit);
|
||||
byteval |= ((on & 0x1) << bit);
|
||||
((uint8_t*)o->ptr)[byte] = byteval;
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
signalModifiedKey(c,c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
|
||||
server.dirty++;
|
||||
addReply(c, bitval ? shared.cone : shared.czero);
|
||||
@@ -754,14 +756,15 @@ void bitopCommand(client *c) {
|
||||
/* Store the computed value into the target key */
|
||||
if (maxlen) {
|
||||
o = createObject(OBJ_STRING,res);
|
||||
setKey(c->db,targetkey,o);
|
||||
setKey(c,c->db,targetkey,o);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,"set",targetkey,c->db->id);
|
||||
decrRefCount(o);
|
||||
server.dirty++;
|
||||
} else if (dbDelete(c->db,targetkey)) {
|
||||
signalModifiedKey(c->db,targetkey);
|
||||
signalModifiedKey(c,c->db,targetkey);
|
||||
notifyKeyspaceEvent(NOTIFY_GENERIC,"del",targetkey,c->db->id);
|
||||
server.dirty++;
|
||||
}
|
||||
server.dirty++;
|
||||
addReplyLongLong(c,maxlen); /* Return the output string length in bytes. */
|
||||
}
|
||||
|
||||
@@ -902,6 +905,9 @@ void bitposCommand(client *c) {
|
||||
* OVERFLOW [WRAP|SAT|FAIL]
|
||||
*/
|
||||
|
||||
#define BITFIELD_FLAG_NONE 0
|
||||
#define BITFIELD_FLAG_READONLY (1<<0)
|
||||
|
||||
struct bitfieldOp {
|
||||
uint64_t offset; /* Bitfield offset. */
|
||||
int64_t i64; /* Increment amount (INCRBY) or SET value */
|
||||
@@ -911,7 +917,10 @@ struct bitfieldOp {
|
||||
int sign; /* True if signed, otherwise unsigned op. */
|
||||
};
|
||||
|
||||
void bitfieldCommand(client *c) {
|
||||
/* This implements both the BITFIELD command and the BITFIELD_RO command
|
||||
* when flags is set to BITFIELD_FLAG_READONLY: in this case only the
|
||||
* GET subcommand is allowed, other subcommands will return an error. */
|
||||
void bitfieldGeneric(client *c, int flags) {
|
||||
robj *o;
|
||||
size_t bitoffset;
|
||||
int j, numops = 0, changes = 0;
|
||||
@@ -999,6 +1008,12 @@ void bitfieldCommand(client *c) {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if (flags & BITFIELD_FLAG_READONLY) {
|
||||
zfree(ops);
|
||||
addReplyError(c, "BITFIELD_RO only supports the GET subcommand");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Lookup by making room up to the farest bit reached by
|
||||
* this operation. */
|
||||
if ((o = lookupStringForBitCommand(c,
|
||||
@@ -1008,7 +1023,7 @@ void bitfieldCommand(client *c) {
|
||||
}
|
||||
}
|
||||
|
||||
addReplyMultiBulkLen(c,numops);
|
||||
addReplyArrayLen(c,numops);
|
||||
|
||||
/* Actually process the operations. */
|
||||
for (j = 0; j < numops; j++) {
|
||||
@@ -1053,7 +1068,7 @@ void bitfieldCommand(client *c) {
|
||||
setSignedBitfield(o->ptr,thisop->offset,
|
||||
thisop->bits,newval);
|
||||
} else {
|
||||
addReply(c,shared.nullbulk);
|
||||
addReplyNull(c);
|
||||
}
|
||||
} else {
|
||||
uint64_t oldval, newval, wrapped, retval;
|
||||
@@ -1082,7 +1097,7 @@ void bitfieldCommand(client *c) {
|
||||
setUnsignedBitfield(o->ptr,thisop->offset,
|
||||
thisop->bits,newval);
|
||||
} else {
|
||||
addReply(c,shared.nullbulk);
|
||||
addReplyNull(c);
|
||||
}
|
||||
}
|
||||
changes++;
|
||||
@@ -1123,9 +1138,17 @@ void bitfieldCommand(client *c) {
|
||||
}
|
||||
|
||||
if (changes) {
|
||||
signalModifiedKey(c->db,c->argv[1]);
|
||||
signalModifiedKey(c,c->db,c->argv[1]);
|
||||
notifyKeyspaceEvent(NOTIFY_STRING,"setbit",c->argv[1],c->db->id);
|
||||
server.dirty += changes;
|
||||
}
|
||||
zfree(ops);
|
||||
}
|
||||
|
||||
void bitfieldCommand(client *c) {
|
||||
bitfieldGeneric(c, BITFIELD_FLAG_NONE);
|
||||
}
|
||||
|
||||
void bitfieldroCommand(client *c) {
|
||||
bitfieldGeneric(c, BITFIELD_FLAG_READONLY);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user