introduce
This article describes an attempt to switch-case a short string (less than 4) in C + +, as with an integer value, to avoid the overhead of string matching and slightly improve the efficiency of the operation. background
As you know, C + + does not support branching operations on string (given or supported), because the switch's expression only supports integer values or types that can be converted to integer values. Since the switch case can not be used, the option is only left if-else, map, hash (or other, hope to inform), first of these three kinds of programs to make a brief description.
If-else, if the string has a possible value of only three or three kinds, so this is a good choice, code simple, easy to read, as for efficiency, at most, do 3 times the string comparison; but if the string has more than 3 possible values, such as the number of 10, then this scheme is not very competent, in the worst case, String comparisons may have to go through the entire if judgment, which is common to beginners.
Map (or dictionary), benefiting from boost and c++11 function libraries, key-value "string-functor" to one by one pairs, with branch selection dependent on the return entry (functor) of the map lookup. Compared to if-else, the average efficiency is improved, and the code looks better, adding a new string, just add in the map initialization, the cost of this is only the content cost of map storage, which is a way of space change time.
Hash, should be the most efficient of these three, almost equivalent to the integer value of the switch-case operation, the string hash first, and then each case branch is a matching string hash value. Because of the nature of the switch-case, the case expression must be a constant-expression, that is, it cannot rely on the hash value of the original string at runtime, and the compiler does not, so the hash value can only be computed for each possible string. This code has to write the original string as a comment, and the code looks weird, like this:
int hash_val = Hash_func (str);
Switch (hash_val)
{case
hash_option1: Break ; "ABCD" Case
Hash_option2: Break ; "ABDC" Case
Hash_option3: Break ; "ACBD" Case
hash_option4: Break ; "Acdb"
}
So, to overcome the problem of hash this scheme, try to make it reach switch-case "efficacy", is the purpose of this experiment.
Implement
As you can see from the code snippet above, this scenario works if there is a way to get the string "ABCD" to automatically compute the hash value at compile time. So how do you automatically convert a string to an integer value? Macro definition ... A string-related macro definition has "#" such a symbol, perhaps it can help busy, Google, sure enough, in addition to "# #", "#", there are "#@" such a combination, the mark into characters, such as
#define MAKECHAR (x) #@x
char A;
A = Makechar (b);
BOOL Is_equal = (A = = ' B '); Is_equal value is True
Try more than one character Makechar (ABC), compile, debug after the ABC was found by byte "or" to the integer value, then just the string to be matched in the same way to "transform" to the integer value on the line, directly affixed to the code:
Template<typename t> T copy_str_to (t& dest, const char* str) {int len = (int) strlen (str);
for (int i = len-1 i >= 0; i.) * ((char*) &dest) + (Len-i-1)) = Str[i];
return dest;
} template<typename t> T copy_wstr_to (t& dest, const wchar_t* str) {int len = (int) wcslen (str);
for (int i = len-1 i >= 0; i.) * ((char*) &dest) + (Len-i-1)) = (char) str[i];
return dest; }//////////////////////////////////////////////////////////////////////////template<typename T> struct CAT_
str_to {template<typename char_type> static t Go (const char_type* psz) {T dest;
Return copy_str_to (dest, psz);
} template<> static T go<wchar_t> (const wchar_t* psz) {T dest;
Return copy_wstr_to (dest, psz);
}
}; Template<short cvt> struct _CASE_
Cvtr_2{static Const Short value = CVT; Template<int Cvt> struct _case_cvtr_4{static const int value = CVT; --------------------------usage--------------------------//#define STR_SWITCH_2 (str) switch (cat_str_to< Short>::go (str)) #define STR_CASE_2 (a) Case _case_cvtr_2<#@a>::value #define STR_SWITCH_4 (str) switch (cat_ Str_to<int>::go (str)) #define STR_CASE_4 (a) Case _case_cvtr_4<#@a>::value//-------------------------- Usage--------------------------//
Use
#define SWITCH str_switch_4
#define CASE str_case_4
switch (str)
{case
(ABC) break
;
Case (ABCD) break
;
Case (db) break
;
Default: Break
;
}