Wednesday, July 21, 2010

Condition check versus a type map

Often, the programmer is faced with the need to translate from one type to another, e.g., given a boolean variable return a corresponding integer value. As a real world example see a piece of Lazarus code:

if NewWordWrap then
gtk_text_view_set_wrap_mode(AGtkTextView, GTK_WRAP_WORD)
gtk_text_view_set_wrap_mode(AGtkTextView, GTK_WRAP_NONE);

NewWordWrap is a boolean variable, but the gtk function expects an integer. To translate from type to another a condition check is done.

Another way to handle this would be creating a map array with the type to be translated. Lazarus also has an example of this technique:

WidgetDirection : array[boolean] of longint = (GTK_TEXT_DIR_LTR, GTK_TEXT_DIR_RTL);
gtk_widget_set_direction(AGtkWidget, WidgetDirection[UseRightToLeftAlign]);

Here is the same pattern: UseRightToLeftAlign is a boolean variable and the gtk function expects a integer, but instead of checking for the variable value a boolean to integer map (WidgetDirection) is used.

While the map approach seems faster because avoids a check, it adds an additional constant. I decided to look at the generated code to see the actual benefits.

Check the condition code:

if B then

Map code:

BoolMap: array[Boolean] of Integer = (CONST_2, CONST_1);


Here is the generated code. This shows a clear advantage to the map approach. Notice that in this small example the size of executables were the same.

I also tested a more complex type than boolean: an enumerated.

Check the condition code:

case E of
EnumA: DoIt(CONST_1);
EnumB: DoIt(CONST_2);
EnumC: DoIt(CONST_3);

Map code:

EnumMap: array[TMyEnum] of Integer = (CONST_1, CONST_2, CONST_3);


The result.

Now with a slight optimized code for the condition check...

I: Integer;

case E of
EnumA: I := CONST_1;
EnumB: I := CONST_2;
EnumC: I := CONST_3;

... i got this.

No comments: