0

I have a 3 element enum, it defines one of three contexts, for example red, green, or blue. This enum is used in a loop with millions of iterations, for example, pixel many. The fields are currently one int apart, the default. Given a desired production order of R,G,B,R,G,B..., I have currently resorted to checking if the value is currently B, thus assigning it to R, otherwise incrementing the value.

private enum CHANNEL_CONTEXT {RED, GREEN, BLUE} //here is a sample enum

//here is a sample loop with the relevant construct
CHANNEL_CONTEXT current = CHANNEL_CONTEXT.RED;
while(condition)
{
    use current;
    //...
    if(current == CHANNEL_CONTEXT.BLUE)
        current = CHANNEL_CONTEXT.RED
    else
        current+=1;

}

Is there a way to wrap a 3 field enum with a single operation, such that no branch is required to determine if it is time to wrap. I know modulus(%) fits the bill, but my motivation is a performance based one, and I'd break even at best with such an expensive operation(testing corroborated, but not exhaustively).

To put my agenda in perspective, if i had 256 relevant fields, I could create a byte based enum, and increment with impunity and intended overflow. Alas, I only have three, and I cant think of a way to manipulate any integral primitive in a way that three values are produced cyclically, using a lightweight ALU operation,(+,-,&,^,|,<<..etc). I also wouldn't have been able to think of a way to swap bits with no temporary using such operations, but there is a rarely practical but possible way to do so.

Can someone guide me to a way to distribute 3 integral enum values such that they are traversable periodically, with no branch required, and no division based operators used(like modulus)?

schulmaster
  • 413
  • 5
  • 16
  • 1
    I honestly think you are going for a premature optimisation. Have you ran a profiler on your code and saw that the % was actually the slowest operation in the code? I am willing to bet it will be very far from the top of the list of big offenders. Write your code in a maintainable way (use the %) then once it is done run a profiler on the code and fix the places that actually take up time. – Scott Chamberlain Jun 21 '19 at 04:20

1 Answers1

2

While it sounds very unlikely that you can beat x = (x + 1) % 3 you can try to use mapping table:

var map = new[]{1,2,0};
x = map[x];

You probably would need to wrap that in unsafe to remove boundary checks on array access.


If you really set on bit manipulation irrespective of readability of the code - the table of converting numbers you are interested in is small enough to build manually for each bit and then combine.

Truth table:

Source     Result
Bit2 Bit1  Bit2 Bit1
0    0     0    1
0    1     1    0
1    0     0    0
1    1     x    x 

As you can see the values we are interested in only produce 2 non-zero bits so resulting expression will be very simple - one case for 1 for lower bit and one case for higher bit (assuming values never fall out of the range 0-2 (which is safe if this is the only transformation).

var b1 = (x & 1) >> 0; // extract lower bit  0
var b2 = (x & 2) >> 1; // extract higher bit 1
// only care of cases when pair of bits results in 1 
var resultBit1 =  1 & (~b1 & ~b2); // 00 -> x1, other cases is 0
var resultBit2 = (1 & (b1 & ~b2)) << 1;               // 01 -> 1x, other cases is 0
x = resultBit1 | resultBit2;

Or inlining all into one unreadable line:

x = 1 & ~(x | x >> 1) | 2 & (x & 1 & ~x >> 1) << 1;
Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179