Reputation: 243
Currently I can run my program but my code consists of a lot of repetition which looks something like:
while(option != 'E' && option != 'D' && option != 'P' && option != 'Q' &&
option != 'e' && option != 'd' && option != 'p' && option != 'q') {
// Some code here
}
or:
while(cType != 'S' && cType != 'L' && cType != 'O' && cType != 'Q' &&
cType != 's' && cType != 'l' && cType != 'o' && cType != 'q') {
// Some code here
}
What's the fastest way to shorten above code?
(Is there any way beside using additional function?)
Upvotes: 11
Views: 542
Reputation: 154228
A candidate quick test with no branching.
1) Make case-less.
2) Form product of 4 differences.
3) 1 compare against 0.
Assumes only letters.
Works up to 4 (sizeof int/sizeof char
) letters.
Upper/Lower case differ by the same bit. (This works with ASCII and EBCDIC)
#define CaseMaskBits ((unsigned char)~('A'^'a'))
#define Product4(ch, s) ((ch-s[0]) * (ch-s[1]) * (ch-s[2]) * (ch-s[3]))
#define TestEq4(ch, t, s) (t=ch&CaseMaskBits, !Product4(t, s))
int main(void) {
int ch;
printf("%X\n", CaseMaskBits);
for (ch = 0; ch < 256; ch++){
int t; // temp var for TestEQ4
while (TestEq4(ch, t, "ELPQ")) {
printf("%d %c\n", ch, ch);
break;
}
}
return 0;
}
280 while (TestEq4(ch, t, "ELPQ")) {
00402560: mov %ebx,%eax
00402562: and $0xdf,%eax
00402567: lea -0x4c(%eax),%edx
0040256a: lea -0x45(%eax),%ecx
0040256d: imul %edx,%ecx
00402570: lea -0x50(%eax),%edx
00402573: sub $0x51,%eax
00402576: imul %ecx,%edx
00402579: imul %edx,%eax
0040257c: test %eax,%eax
0040257e: jne 0x402555 <main+37>
281 printf("%d %c\n", ch, ch);
Upvotes: 1
Reputation: 154228
If option/cType
have <= 8 bits of significance, for speed, use a table lookup. @Dieter Lücking
unsigned char Table[UCHAR_MAX + 1] = {
fill per needs };
#define Table_OptionMask 1
#define Table_cTypeMask 2
#define Table_nextMask 4
while (!(Table[(unsigned char)option] & Table_OptionMask)) ...
while (!(Table[(unsigned char)cType] & Table_cTypeMask)) ...
For simpler code maintenance, populate the table on code startup by calling Table_Setup()
.
static void Table_SetInsensitive(unsigned char *Table, unsigned mask, cnst char *src) {
while (*src) {
Table[toupper((unsigned char) *src)] |= mask;
Table[tolower((unsigned char) *src)] |= mask;
src++;
}
}
void Table_Setup(void) {
memset(Table, 0, sizeof Table);
Table_SetInsensitive(Table, Table_OptionMask, "EDPQ");
Table_SetInsensitive(Table, Table_cTypeMask, "SLOQ");
Table_SetInsensitive(Table, Table_cTypeMask, tbd);
}
Upvotes: 0
Reputation: 3067
const char invalidChars[] = "edpq";
while (strchr(invalidChars, tolower(option)) != 0) {
...
}
Upvotes: 8
Reputation: 181027
You could get rid of half of the conditions with std::tolower
while(std::tolower(option) != 'e' && std::tolower(option) != 'd' && std::tolower(option) != 'p' && std::tolower(option) != 'q')
You could also use a std::string
and it's find
member function like:
std::string options = "edpq";
//...
while (options.find(std::tolower(option)) == std::string::npos)
Upvotes: 3
Reputation: 55069
You could initialize a string containing the characters you want to match, then use find
, which returns npos
if no match was found:
string match = "SLOQsloq";
while (match.find(cType) == string::npos)
...
Upvotes: 3
Reputation: 4695
You could simplify the logic and make things more readable by using an std::set
and checking if the set contains (or doesn't contain) the variable we're comparing to:
std::set<char> someChars { 'a', 'b', 'c' };
if(someChars.find(myChar) != someChars.end()) {
// myChar is either 'a', 'b', or 'c'
}
The condition in most other languages would be written more cleanly as something like someChars.contains(myChar)
(but C++'s set interface is very minimal).
However, for a small number of comparisons, your method is probably faster.
Upvotes: 2