按位压缩布尔 - 切换特定的一个

时间:2017-08-01 13:00:38

标签: php bit-manipulation

背景

我必须在数据库中存储一些true / false值,而不是创建很多列,而是使用单个int列,我存储所有布尔值,使用Bitwise运算符压缩

示例:

Product 1被认证为:

Lead Free - Yes
Gluton Free - No
Free Range - Yes
Organic - Yes

因此,在数据库的certs列中,我将1011压缩为13 (1 + 4 + 8)。

我编写了快速包装函数来压缩和提取这些信息(从int更改为boolean数组并返回)。

问题

我不确定快速添加和删除此值的最佳方法。假设我想将产品更新为不再是免费范围。我可以使用压缩的int,减去4。这样可行。除非它已经不是自由范围了怎么办?如果我正在进行批量操作,我需要我的功能只从当前认证的自由范围的产品中删除4,否则数字会搞乱。

我已经用冗长的if语句弄明白了,但它并不优雅。这有效:

// $certs_current is the compressed int from the DB.
// $certs_new is a new integer. 4 would mean toggle "Free Range" to true. -4 would mean toggle it to false.

if ( $certs_current & abs($certs_new) ) {
    if ( $certs_new < 0 ) {
        $certs_current += $certs_new;
    }
} else {
    if ( $certs_new > 0 ) {
        $certs_current += $certs_new;
    }
}

这是很多if陈述。我使用|运算符,但它只适用于添加正数。将它传递给-4然后就会中断。我无法找出nor运营商。

有更好的方法吗?

修改

换句话说,是否有运营商:如果我给它13-4,它会给我9。但如果我给它9-4,它会给9?或者甚至只是134

修改2

|添加到我的工作逻辑中,我已经降低了复杂性并且仍然有效:

if ( $certs_new > 0 ) {
    $certs_current = ( $certs_current | $certs_new );
} else {
    if ( $certs_current & abs($certs_new) ) {
        $certs_current += $certs_new;
    }
}

基本上它说,如果新数字是正数,那么如果需要添加,请使用|运算符添加它。如果它是否定的,那么我们首先检查是否需要删除它,如果是,则删除它。哪个是我认为我们可以改进的地方。

|替换if语句,因为如果4尚未切换为true,它只会添加4(我意识到这是一种奇怪的方式描述它。)

但是对于负数,我仍然有一个嵌套的if语句,如果可能的话,这就是我要删除的内容。

2 个答案:

答案 0 :(得分:0)

您拥有压缩值,那么为什么不在进行操作之前将其展开?

$certs_temp = $certs_current
$is_organic = $certs_temp >= 8 && $certs_temp -= 8
$is_freerange = $certs_temp >= 4 && $certs_temp -= 4
$is_glutenfree = $certs_temp >= 2 && $certs_temp -= 2
$is_leadfree = $certs_temp >= 1 && $certs_temp -= 1

然后使用更改的值重新压缩(如果确实发生了任何变化)。

如果您尝试直接对存储的整数进行操作,我认为您会遇到麻烦,该整数实际上代表4个单独的二进制标志。要么在DB中单独表示每个标志,要么必须将其存储为整数,然后在应用更改或逻辑之前对其进行解码。

答案 1 :(得分:0)

答案

我明白了。要将布尔值切换为false,我们需要:

  1. 使用~(示例中为13)从数据库中反转主压缩int

  2. 使用4添加新int -4(不是|)的绝对值。

  3. 使用~再次反转完整的int。

  4. 所以最终的代码只有一个if语句:

    if ( $certs_new > 0 ) {
        $certs = ( $certs | $certs_new );
    } else {
        $certs = ~( ~$certs | abs($certs_new) );  
    }
    
    // 13 and 4 .... 13
    // 13 and 2 .... 15
    // 13 and -4 .... 9
    // 13 and -2 .... 13