[6.0] src/bitops.c

This commit is contained in:
tporadowski
2020-12-07 00:14:07 +01:00
parent 76a9436752
commit 63edc22098
+42 -19
View File
@@ -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);
}