生成前缀位掩码

时间:2020-06-22 09:19:22

标签: c++ c bit-manipulation undefined-behavior

我正在寻找一种生成前缀位掩码的便携式方法,该前缀具有为@Component @Order(SwaggerPluginSupport.SWAGGER_PLUGIN_ORDER + 1000) public class SwaggerIncludeMissingNicknameIntoUniqueIdReader implements OperationBuilderPlugin { @Override public void apply(OperationContext context) { Optional<ApiOperation> methodAnnotation = context.findControllerAnnotation(ApiOperation.class); Operation operationBuilder = context.operationBuilder().build(); String uniqueId = operationBuilder.getUniqueId().replaceAll("Using(GET|POST|PUT|DELETE)", ""); // If nickname exists, populate the value of nickname annotation into uniqueId String fillId = methodAnnotation.transform(ApiOperation::nickname).or(uniqueId); context.operationBuilder().uniqueId(fillId); context.operationBuilder().codegenMethodNameStem(fillId); } @Override public boolean supports(DocumentationType delimiter) { return SwaggerPluginSupport.pluginDoesApply(delimiter); } } (或64或任意整数类型的位宽)设置的前n位。

示例:

0 <= n <= 32

如果我们忽略案例prefix_bitmask(0) = 0b00000000000000000000000000000000u prefix_bitmask(4) = 0b00000000000000000000000000001111u prefix_bitmask(32) = 0b11111111111111111111111111111111u n == 0,有两种方法已经可以起作用:

n == 32

// "constructive": set only the required bits uint32_t prefix_mask1(int i) { return (uint32_t(1) << i) - 1; } // "destructive": shift unneeded bits out uint32_t prefix_mask2(int i) { return ~uint32_t(0) >> (32 - i); } 失败32且prefix_mask1失败0都是因为大于整数类型的移位是未定义的行为(因为允许CPU仅使用移位大小的最低5位)。

是否有一种“规范”的方法可以解决此问题而无需分支?

4 个答案:

答案 0 :(得分:4)

((uint32_t) 1 << i/2 << i-i/2) - 1

以上方法可以将uint32_t替换为任何无符号类型。并且不需要其他更改。需要知道类型中的位数b和掩码m = 2 b -1的其他选项包括:

((uint32_t) 1 << (i & m)) - 1 - (i >> b)(来自supercat

和:

((uint32_t) i >> b) ^ 1) << (i & m)) - 1(来自Matt Timmermans的建议)。

答案 1 :(得分:3)

这可以通过使用prefix_mask2想法和算术移位来完成,以准备正确的模式来完成,总共有3条指令(假定CPU中的移位计数为模数字宽):

// minimal instruction dependency (2 cycles), but requires large constant
// that some architectures have trouble generating
uint32_t prefix_mask2a(int i) {
    return ((int32_t) (i + (0x80000000 - 32))) >> ((i ^ 31) & 31);
}

// 3 cycles
uint32_t prefix_mask2b(int i) {
    return (uint32_t) ((int32_t) -i >> 31) >> (-i & 31);
}

答案 2 :(得分:2)

您可以将uint32_t投射到更多位上,进行移位,然后再转换回去:

uint32_t prefix_mask(int i) {
  return UINT32_MAX & ((UINT64_C(1) << i) - 1);
}

答案 3 :(得分:0)

我认为它很便携

#define PREFIX(type, n) (type)(((sizeof(type) * CHAR_BIT - (n)) == sizeof(type) * CHAR_BIT) ? ((type)0) : (!(sizeof(type) * CHAR_BIT - (n)) ? (~(type)(0)) : ((~(type)(0)) << (sizeof(type) * CHAR_BIT - n))))
#define POSTFIX(type, n) (type)(((sizeof(type) * CHAR_BIT - (n)) == sizeof(type) * CHAR_BIT) ? ((type)0) : (!(sizeof(type) * CHAR_BIT - (n)) ? (~(type)(0)) : ((~(type)(0)) >> (sizeof(type) * CHAR_BIT - n))))

#define TEST_TYPE unsigned long long

void printbin(TEST_TYPE x)
{
    TEST_TYPE mask = (TEST_TYPE)1 << (sizeof(x) * CHAR_BIT - 1);
    while(mask)
    {
        printf("%d", !!(x & mask));
        mask >>= 1;
    }
}


int main()
{
    for(int x = 0; x <= sizeof(TEST_TYPE) * CHAR_BIT; x++)
    {
        printbin(PREFIX(TEST_TYPE, x)); printf("\n");
    }
    printf("\n");
    for(int x = 0; x <= sizeof(TEST_TYPE) * CHAR_BIT; x++)
    {
        printbin(POSTFIX(TEST_TYPE, x)); printf("\n");
    }
}

https://godbolt.org/z/_NadkH

相关问题