Building a lookup table

In the final recipe of the previous chapter on reflection, we built a command-line function caller that did a linear search through all the available functions to find the right one for the command. Here, we'll revisit that concept and generate more efficient code.

How to do it…

Let's execute the following steps to build a lookup table:

  1. Create a switch statement.
  2. If you are looping over a tuple of strings, such as one from a template argument list or returned from __traits, you can write the case statements inside the foreach loop.
  3. Otherwise, build the code as a string and use the mixin expression to add it to your switch statement.
  4. Let the compiler optimize the switch statement.

All the preceding steps are mentioned in the following code:

void callFunction(string functionName) {
  s: switch(functionName) {
     default: assert(0); // can add defaults or cases outside the loop
    foreach(methodName; __traits(allMembers, mixin(__MODULE__))) {
       case methodName:
           // implement the call
       break s; // break the switch specifically to clarify intent inside loop
    }
  }
}

Tip

If you want a custom hash function, you can use CTFE by calling regular hash functions in the case statements: int hash(string s) { … } switch(hash(s)) { case hash("foo"): /* … */ break; case hash("bar"): /* … */ }. Ensure that your hash is well-distributed, because switch will not handle collisions automatically.

How it works…

When a switch statement is compiled, all possible case values are known to the compiler, allowing it to generate more efficient code than a plain list. All the possible string cases are sorted by length and by content at compile time. This list is sent to a runtime function which performs a binary search to find the case that handles a given input value.

We can often take advantage of these optimizations by creating a switch statement and populating the cases with compile-time foreach loops. The code is pretty straightforward.

Another strategy to make lookup tables is with compile-time function evaluation. CTFE is often used with enums, but it also works with static immutable arrays to create data tables. To do this, write a function that calculates the data and returns a table. Then, use that function to initialize the table. It is important that you mark the table static immutable to ensure it is only initialized once, at compile time, and can be shared across all threads implicitly.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.188.190.175