Skip to content
Advertisement

How to determine all of the set bits in a Redis bitfield?

I need the ability to identify the index of each set bit (value=1) in a Redis bitfield. I found this which suggests using the bitpos function but there’s a problem. As far as I can tell it takes the start of the range with a byte level specificity so if there’s multiple set bits in a given byte I can only see the first set bit within that byte. Alternatively I could grab the entire value but I’m getting incorrect answers when I do this (my code is in PHP).

    $temp = $redis_conn->getRange('mykey', 0, -1);
    $output = "";
    for($i=0;$i < strlen($temp); $i++) {
        $up = unpack('H*', $temp[$i]);
        $bc = base_convert($up[1], 16, 2);
        if($bc == '0') {
            $bc = '00000000';
        }
        $output .= $bc;
    }
    
    for($i = 0; $i < strlen($output); $i++) {
        if($output[$i] == '1') {
            echo ($i+1).PHP_EOL;
        }
    }

I think this code should work but the answers are wildly incorrect. I put a check in for a one character string because when all 8 digits should’ve been 0 the base_convert only gave me one digit back throwing the indices way off. Looking through I can see that there are other places where the result of base_convert is not 8 digits which can account for a lot of the mismatch between expected and actual results but not all of it. Does anyone know of a good way to get either of these methods to work? Either the bitpos command or converting the binary after pulling down the entire bitfield?

EDIT: As an example I told it to set the bits at indices 12921, 72312 and 74616. I have 12921 coming out as expected but the highest index I’m seeing is 73623.

Advertisement

Answer

Sounds like you are always expecting it to produce 8 characters from base_convert(), but it will only provide enough digits to represent the number.

You can pad the number with leading 0’s to make sure it’s always 8 chars using str_pad() and STR_PAD_LEFT to left pad the string…

$output .= str_pad($bc, 8, "0", STR_PAD_LEFT);
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement