使用数字模式的 Switch 语句

Switch statement using numeric patterns

我正在尝试为给定值创建一个 switch 语句。该值是一个 16 位无符号数,我想跳转到适当的模式。每个模式都是一个十六进制字符串,但下划线表示通配符。例如,(0x1234 匹配“1234”和“12_4”但不匹配“56_8”)。虽然我只发布了这些模式的一个子集,但假设它们涵盖了 0x0000-0xFFFF 的整个范围。

patterns = {
    '15__': foo,
    '2__0': bar,
    '8__0': baz,
    ...
}

...

def run(self, x: int) -> None:

    # x to string (0x567f -> "567F")
    x_str = str(hex(opcode))[2:].zfill(4).upper()

    # Search for the matching pattern and execute the associated method
    for pattern, instruction in patterns.items():
        if all([x_str[i] == pattern[i] for i in range(len(pattern)) if pattern[i] != '_'):
            instruction(x)
            break

现在,这行得通了。然而,它非常慢,并且违背了使用字典的目的,因为它只是遍历它。此外,由于它必须将 x 转换为字符串(带格式),然后根据模式字符串检查该字符串,所以整个过程是一个巨大的瓶颈。我正在寻找一种方法,最好是让它更接近实际查找 table,如果我们不需要将 x 转换为字符串,则加分。

这种类型的 switch 语句一个迭代过程,而不是跳转table。在您提出的一般情况下,避免迭代的方法是根据 table.

中常见数字(hexits)和通配符的特定排列生成部分索引决策图

相反,尝试简单地加快匹配速度。我建议您对 table 键采用掩码匹配方法。分别对“无关”(通配符)位置进行编码,并将键保存为匹配值和掩码值的元组。你的例子是

patterns = {
    (0x1500, 0xFF00): foo,
    (0x2000, 0xF00F): bar,
    (0x8000, 0xF00F): baz,
    ...
}

要根据候选 cand 检查特定密钥,您需要寻找位相等性,但要屏蔽通配符位置中的任何不匹配:

cand ^ match       # bit inequality; mismatch is 1
result & mask      # force don't-care bits to 0

以便您检查

if (cand ^ match) & mask:
    continue      # Something doesn't match
else:
    return value from dict

你的字典格式是

(match, mask): value

你能处理迭代和 return 值的逻辑吗?