Vui La Chinh
Vui La Chinh

Reputation: 243

How to shorten multiple && condition

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

Answers (6)

chux
chux

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

chux
chux

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

asdf
asdf

Reputation: 3067

const char invalidChars[] = "edpq";
while (strchr(invalidChars, tolower(option)) != 0) {
    ...
}

Upvotes: 8

NathanOliver
NathanOliver

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

Jon Purdy
Jon Purdy

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

Kat
Kat

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

Related Questions