Search code examples
c#enumsperiodicity

Single(and inexpensive) operation to cycle through a 3 value C# enum periodically(ie with wrap)


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)?


Solution

  • 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;