Best way to do a switch on 256 cases


#1

I need the effect of a switch statement on 256 cases. There are 256 small bits of code I need to quickly get to. If I make a switch statement with 256 cases, will the compiler automatically generate efficient code that effectively dispatches from an array? The situation I want to avoid is the switch degenerating into a long series of if/else.


#2

Are you able to say more specifically what you're trying to achieve? It's likely that there's a better method than 200+ switch cases


#3

I’m porting a CPU emulator. There are 256 instructions. Each ‘case’ is fairly simple, executing that specific instruction. In C++, the switch is quite fast. The switch statement works well in that case.

Other options I’ve considered include an array of 256 blocks, etc. My concern with an array is I’ve seen swift have issues with very long literal arrays. Non-literal arrays feel like they would be a burden to build.


(Jeremy David Giesbrecht) #4

I’m having difficulty imagining exactly what it is you want, but let me take a stab at it anyway...

Assuming:

  1. You have 256 instructions that can be modelled as closures with the same signature.
  2. You want to be able to reference them by name in O(1).
  3. You also want to be able to reference them by index in O(1).
public enum Instruction: Int {

    public typealias InstructionClosure = () -> Void

    case doSomething
    case doSomethingElse
    // ...
    
    fileprivate static let byIndex: [InstructionClosure] = [
        // 0
        { print("Doing something...") },
        // 1
        { print("Doing something else...") }
        // ...
    ]
}

public func execute(_ instruction: Instruction) {
    execute(instruction.rawValue)
}
public func execute(_ instructionIndex: Int) {
    Instruction.byIndex[instructionIndex]()
}

// Then use either way:

execute(.doSomething) // Doing something...
execute(1) // Doing something else...

You will just want tests to make sure updates to your code never accidentally push the index and name orders out of sync with one another.

This only becomes cumbersome if the compiler is left to infer the type and that process gets complicated due to subclasses, protocols, overloads, etc. This little annotation works wonders to short‐circuit the entire process: : [InstructionClosure]. I’ve made use of much longer literal arrays than 256 without any issues.


#5

That looks very reasonable. Thanks!