C++ 安全切换语句的优化
我需要使用经常调用的开关优化一个函数:(这个函数的思想非常简单)C++ 安全切换语句的优化,c++,switch-statement,C++,Switch Statement,我需要使用经常调用的开关优化一个函数:(这个函数的思想非常简单) StringTable*FastTableOf2(常量字符和搜索){ 开关(计数){ 案例256: 返回*(子项+*(字节*)&查找); 案例10: if(seek!=键[9]) ... 案例2: if(seek!=键[1]) 案例1: if(seek==键[0]) 返回子项[0]; 否则{ } 其他的 返回儿童[1]; 其他的 返回儿童[2]; ... 其他的 返回儿童[9]; } 返回0; } 我考虑检查Count是否为25
StringTable*FastTableOf2(常量字符和搜索){
开关(计数){
案例256:
返回*(子项+*(字节*)&查找);
案例10:
if(seek!=键[9])
...
案例2:
if(seek!=键[1])
案例1:
if(seek==键[0])
返回子项[0];
否则{
}
其他的
返回儿童[1];
其他的
返回儿童[2];
...
其他的
返回儿童[9];
}
返回0;
}
我考虑检查Count
是否为256,然后执行return*(Children+*(byte*)&seek)代码>
如果没有,则执行转到case[Count]
而不检查值是否在10-1范围内。(计数
只能为256或介于1和10之间)
有没有办法告诉编译器只需执行jmp
即可在开关中添加标签,而不必检查它是否在范围内?
我知道这种优化非常小,但这里每个百分比都很重要。对于高度关键的代码部分,我根本不会使用开关,而是使用跳转表
在跳转表中设置函数指针数组。这些函数可以做一些非常简单的事情,比如返回一个立即值,或者做一些更复杂的事情。数组中有N个元素,其中N是您可以打开的最大可能值
在设置跳转表时,您将提前填充数组,可能是在程序启动时。每个条目要么指向一个实函数,要么指向某种“未处理”的处理程序
更换开关
非常简单:
StringTable<T> *FastTableOf2( const char &seek ) {
return (mJumpTable[Count])(seek);
}
StringTable*FastTableOf2(常量字符和搜索){
返回(mJumpTable[Count])(seek);
}
你不会比这更快了。我认为交换机的实现已经是一次尝试优化,
因为代码似乎相当于:
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;
}
如果将案例1
更改为默认值
,是否有帮助?(不是答案,因为我现在无法测试)。@MikeSeymour编译器将缩小表并执行另一个jmp
。(如果不在范围内)尝试过,但谢谢。请注意,这里的开关
对于用作标签的案例
来说很棘手uncase'(如展开循环)可能会产生大量重复代码。也许您可以进行更改以减少调用此方法的频率。你可以使用一些记忆…@MikeSeymour:默认值
应该是返回0
,正如我所理解的(根据OP,不应该调用)。有些人告诉我做类似的事情。调用函数不是更慢吗?我现在就试试。它与您正在查找的jmp
相同。但是它使用push-seek和push-this-address,然后是jmp。我想我有一个想法,没有追求。您正在直接寻址数组中的函数指针。我认为编译器(may)已经通过跳转表实现了开关
,在这种情况下。我在代码中展开了循环。(性能更好)我已经用可能的优化编辑了我的答案。
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;
}
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);
}
}