安全切换语句的优化

时间:2013-12-24 12:32:45

标签: c++ switch-statement

我需要使用经常调用的开关优化函数:(这个函数的想法非常简单)

StringTable<T> *FastTableOf2( const char &seek ) {
    switch ( Count ) {
        case 256:
            return *( Children + *( byte* )&seek );
        case 10:
            if ( seek != Keys[ 9 ] )
        ...
        case 2:
            if ( seek != Keys[ 1 ] )
        case 1:
            if ( seek == Keys[ 0 ] )
                return Children[ 0 ];
            else {
            }
            else
                return Children[ 1 ];
            else
                return Children[ 2 ];
            ...
            else
                return Children[ 9 ];
    }
    return 0;
}

我考虑过检查Count是否为256然后执行return *( Children + *( byte* )&seek ); 如果没有,则执行goto case[Count]而不检查该值是否在10-1范围内。 (Count只能是256或1到10之间)

有没有办法告诉编译器只需要jmp在switch中标记,而不是检查它是否在范围内? 我知道这种优化很小,但每个百分比都很重要。

2 个答案:

答案 0 :(得分:0)

对于高度关键的代码部分,我根本不会使用switch,而是使用跳转表。

在跳转表中,您可以设置一个函数指针数组。这些函数可以做一些非常简单的事情,比如返回一个直接的值,或做一些更复杂的事情。您的数组中将包含N个元素,其中N是您switch上可能的最高值。

在设置跳转表时,您将提前填充数组,可能是在程序启动时。每个条目都指向一个真正的功能或某种“未处理”处理程序。

更换switch并不简单:

StringTable<T> *FastTableOf2( const char &seek ) {

  return (mJumpTable[Count])(seek);
}

你不会比这更快。

答案 1 :(得分:0)

我认为交换机实现已经尝试优化, 因为代码似乎等同于:

StringTable<T> *FastTableOf2(const char& seek)
{
    if (Count == 256) {
        return *(Children + *(byte*)&seek);
    }
    assert(1 <= Count && Count <= 10);
    for (auto c = Count; c != 0; --c) {
        if (seek == Keys[c - 1]) {
            return Children[c - 1];
        } 
    }
    return nullptr;
}

我会尽量避免switch default中的“差距”。 default目前为{0,[11; 255],257 +}。 由于未达到default,您可以将其与任何其他label合并。

我注意到char(256) == '\0'所以所有有效值都在[0; 10]中, 所以default = 11+使用与10+相同的标签成为case 11

或者,您可以使用Count - 1并将defaultcase 256合并, 所以default在这两种情况下都只有11+

完全删除特例default

所以,也许以下可能会更快:

StringTable<T> *FastTableOf2(const char &seek ) {
    switch (char(Count)) {
        default: // Count >= 10 
        case 10: if (seek != Keys[9]) {
        ...
        case 2: if (seek != Keys[1]) {
        case 1:
            if (seek != Keys[0]) { return nullptr; } else { return Children[0]; }
            } else { return Children[1]; } // Count == 2
            } else { return Children[2]; } // Count == 3
            ...
            } else { return Children[9]; } // Count == 10
        // char(256) == '\0'
        case char(256): return *(Children + *(byte*)&seek);
    }
}