Search code examples
javasyntaxbranchconventions

Elegant Branching (In any language)


I've only been programming for a short while and have yet to find a way to write branching code that covers every possible configuration of two or more boolean values without any redundant if-statements.

For example, a table showing all possible outcomes may look like this:

          true    false
      ---------------------
true  | Thing A | Thing B |
      ---------------------
false | Thing C | Thing D |
      ---------------------

Yet the only code that I can think of to program things A though D is as follows:

if(boolean1) {
    if(boolean2)
        ThingA();
    else
        ThingB();
}
else if (boolean2)
    ThingC();
else
    ThingD();

Is there any way to write this without having to write a check for boolean2 twice? I am aware that only one check can run for one iteration of this code, but in a situation where there are more than two boolean values to worry about, this approach could become quite cumbersome.


Solution

  • What you can do is to create a mask using bit-shifts and introduce a switch

    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <cstdint>
    
    using namespace std;
    
    int main() {
      bool bArray[2];
      for (size_t i = 0 ; i < 2 ; i++) {
        cin >> bArray[i];
      }
    
      uint32_t mask = 0;
    
      mask = bArray[0];
      mask = mask << 1;
      mask = mask ^ bArray[1];
    
      switch(mask) {
        case 0:
          cout << "bot false" << endl;
          break;
        case 1:
          cout << "first false, second true" << endl;
          break;
        case 2:
          cout << "first true, second false" << endl;
          break;
        case 3:
          cout << "both true" << endl;
          break;
      }
      return 0;
    }
    

    You can make it very elegant using the new C++11 extension, where you can overload literal operator ""_ and e.g. replace case 2: with "10"_bin2int in a similar way to how hashes are created in

    Compile time string hashing

    There is a full working example for such a switch here

    http://dev.krzaq.cc/switch-on-strings-with-c11/

    Using the information from above, the most elegant solution I can think of looks like this. Note how the literals are evaluated compile-time. You need a compiler which supports string-literals to compile this

    #include <cstdlib>
    #include <cstdio>
    #include <iostream>
    #include <cstdint>
    
    using namespace std;
    
    constexpr uint32_t basis = 0;
    
    constexpr uint32_t bin2int_compile_time(char const* str,
                                            uint32_t last_value = basis) {
      return *str ?
        bin2int_compile_time(str+1,(last_value << 1) ^ ((uint8_t)*str)-48) :
        last_value;
    }
    
    constexpr uint32_t operator "" _bin2int(char const* p, size_t) {
      return bin2int_compile_time(p);
    }
    
    uint32_t bool2int(const bool* bools, const size_t length) {
      uint32_t mask = bools[0];
      for (size_t i = 1 ; i < length ; i++) {
        mask = mask << 1;
        mask = mask ^ bools[i];
      }
      return mask;
    }
    
    int main() {
      const size_t nBooleans = 2;
      bool bArray[nBooleans];
      for (size_t i = 0 ; i < nBooleans ; i++) {
        cin >> bArray[i];
      }
    
      uint32_t mask = bool2int(bArray, nBooleans);
    
      switch(mask) {
        case "00"_bin2int:
          cout << "both false" << endl;
          break;
        case "01"_bin2int:
          cout << "first false, second true" << endl;
          break;
        case "10"_bin2int:
          cout << "first true, second false" << endl;
          break;
        case "11"_bin2int:
          cout << "both true" << endl;
          break;
        default:
          break;
      }
      return 0;
    }