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)
else
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:


const
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
DoIt(CONST_1)
else
DoIt(CONST_2);

Map code:


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

DoIt(BoolMap[B])

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);
end;

Map code:


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

DoIt(EnumMap[E])

The result.

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


var
I: Integer;

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

... i got this.

No comments: