XorThaX
XorThaX

Reputation: 1

an alternative to the following case

I have encountered a problem for which I'm unable to find an easily maintainable and readable solution to.

I'm basically writing a "master state machine" I have a node which receives enums from 3 other slave nodes, which independently do their thing and come to a certain state and report it to the master

Slave 1 outputs one of the enums:

enum slave1 {
A,
B
}

Slave 2 outputs one of the enums:

enum slave2 {
1,
2
}

Slave 3 outputs one of the enums:

enum slave3 {
a,
b,
c
}

It is important to note that i don't have any control over the behavior, structure and outputs of the slave nodes

Now, based on the values received my master node has the following logic

val_slave_1 = getSlave1Val();
val_slave_2 = getSlave2Val();
val_slave_3 = getSlave3Val();

switch(val_slave_1):
  case A:
    switch(val_slave_2):
      case 1:
        switch(val_slave_3):
          case a: {do Z}
          case b: {do Y}
          case c: {do X}
      case 2:
        switch(val_slave_3):
          case a: {do W}
          case b: {do V}
          case c: {do U}
  case B:
    switch(val_slave_2):
      case 1:
        switch(val_slave_3):
          case a: {do T}
          case b: {do S}
          case c: {do R}
      case 2:
        switch(val_slave_3):
          case a: {do Q}
          case b: {do P}
          case c: {do O}

The advantages of this code are -

  1. Given 3 numbers I can find out exactly what behavior to expect.
  2. It's easy to debug.
  3. Do not have to maintain several booleans or if statements.

The problem with this code is that it -

  1. The current code is a combination of (2,2,3) cases permuted together, but in reality I have a lot more enums (3, 4, 7). This makes it extremely hard to read and maintain.
  2. If in the future one of the slaves changes the number of enums, say slave 2 adds another enum. I will need to add a whole lot of cases to make this work making it really hard to test
  3. If there is another independent slave (slave 4) which comes along and provides information, I'm pretty screwed.

My question to you all is that is there a better way to do this? I read a lot of places which said polymorphism is often a good way to solve switch statements but I tried making my code polymorphic and can't seem to nail down a solution. While a lot of people gave simple examples of vehicles and cats, it doesn't seem like I can apply it to my problem.

Another important note: it may be obvious but I'll still write it. It doesnt matter what order I write switch case statements in. To maintain sanity I will choose to write it in the order of most to least enums to save lines of code (I think)

The closest thread I found to this problem is -

Is there any design pattern to avoid a nested switch case?

But is there a better way to do this than maintaining a dictionary of enums to map to a function?

Upvotes: 0

Views: 60

Answers (1)

Pezo
Pezo

Reputation: 1448

Because your enum values are small, a map from enum combinations to functions could just be an array. When you have 3, 4, and 7 values (i.e. 2, 2, and 3 bits, respectively), you could use a single byte for indexing into an array of function pointers. Something like this:

using Handler = void (*)();
std::array<Handler, 128> handlers = { doA, doB, doB, doG, nullptr, ..., doFoo };

int v1 = slave1(); // 0-6
int v2 = slave2(); // 0-3
int v3 = slave3(); // 0-2

int index = (v2 << 5) | (v1 * 3 + v3);
handlers[index]();

If your enum values are not continuous from 0 to n, you might have to remap them to that.

You might want to come up with a clever way of populating the array, since manually recalculating the indexes when something changes might take a while. One way I can think of right now is a constexpr function that takes a number of structs that each contain the enum values and a function pointer, populating an array from those. The structs would calculate the index, the function would just assign function pointers from indexes. Or something like that.

Upvotes: 1

Related Questions