【问题标题】:Switch statement using numeric patterns使用数字模式的 Switch 语句
【发布时间】:2020-12-07 00:30:56
【问题描述】:

我正在尝试为给定值创建一个 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 转换为字符串(带格式)然后检查该字符串与模式字符串,所以整个事情是一个巨大的瓶颈。我正在寻找一种方法,最好是让它更接近实际的查找表,如果我们不需要将 x 转换为字符串,则可以加分。

【问题讨论】:

    标签: python switch-statement pattern-matching bit-manipulation


    【解决方案1】:

    这种类型的 switch 语句一个迭代过程,而不是一个跳转表。在您提出的一般情况下,避免迭代的方法是根据表中常见数字(十六进制)和通配符的特定排列生成部分索引决策图。

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

    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
    

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

    【讨论】:

      猜你喜欢
      • 2021-04-26
      • 1970-01-01
      • 1970-01-01
      • 2011-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多