Assembly code snippets
Details
Title | Switch / Case |
---|---|
Author | bitRAKE |
Submitted by: | bitRAKE |
Date added: | 2002-02-17 21:02:01 |
Date modified: | 2002-02-17 21:02:01 |
Comments
This offers an optimized branching method for a large set of unordered cases.
Snippet
;#############################################
; Optimized Switch/Case Macro
; by bitRAKE (aka Rickey Bowers Jr.)
;#############################################
SwitchThreshHold = 3 ;when is a bad idea to partition
.switch MACRO
SwitchNodes = 0
SwitchDefault TEXTEQU <>
SwitchExit TEXTEQU <>
ENDM
.case MACRO xVal:REQ, xNode:REQ
@CatStr(<SwitchValue>, %SwitchNodes) = &xVal
@CatStr(<SwitchNode>, %SwitchNodes) TEXTEQU <&xNode>
SwitchNodes = SwitchNodes + 1
ENDM
.default MACRO def:REQ
SwitchDefault TEXTEQU <&def>
ENDM
.endswitch MACRO sexit
LOCAL TheEnd, ww, oo, temp1, temp2, temp3, temp4
SwitchExit TEXTEQU <&sexit>
;; This is a bubble sort on the values of the case statements
;; the labels follow their associated values.
ww = SwitchNodes
WHILE ww
ww = ww - 1
oo = ww
WHILE oo
oo = oo - 1
temp1 = @CatStr(<SwitchValue>, %oo)
temp2 = @CatStr(<SwitchValue>, %ww)
;; We need MASM to evaluate this at assemble-time
% IF &temp1 GT &temp2
;; Numberic values can be swaped easily
@CatStr(<SwitchValue>, %oo) = &temp2
@CatStr(<SwitchValue>, %ww) = &temp1
;; Strings are a little harder...
;; Get the variable names
temp3 TEXTEQU @CatStr(<SwitchNode>, %oo)
temp4 TEXTEQU @CatStr(<SwitchNode>, %ww)
;; Get the value of those varibles
;; MASM doesn't allow &@CatStr(...)!
temp3 TEXTEQU &temp3
temp4 TEXTEQU &temp4
;; Swap them
@CatStr(<SwitchNode>, %oo) TEXTEQU &temp4
@CatStr(<SwitchNode>, %ww) TEXTEQU &temp3
ENDIF
ENDM
ENDM
;; This starts the trasversal of the array as if it were a bbtree
.SwitchPartition 0, SwitchNodes - 1
;; Output the code for the case nodes that haven't been done already
ww = SwitchNodes
WHILE ww
ww = ww - 1
;; Previously output nodes are cleared in the transveral
% IFNB <@CatStr(<SwitchNode>, %ww)>
@CatStr(<SwitchLabel>, %ww, <:>)
% @CatStr(<SwitchNode>, %ww)
IFNB <&SwitchExit>
% &SwitchExit
ELSE
jmp SwitchExitLabel
ENDIF
ENDIF
ENDM
SwitchDefaultLabel:
IFNB <&SwitchDefault>
% &SwitchDefault
IFNB <&SwitchExit>
% &SwitchExit
ENDIF
ENDIF
SwitchExitLabel:
ENDM
;; Transverse the sorted array of variables that was created for each
;; case statement like a balanced binary tree...
.SwitchPartition MACRO _min:REQ, _max:REQ
LOCAL delta, mmin, HighHalf
delta = _max - _min
mmin = _min
IF delta LT SwitchThreshHold
;; Output a string of nodes comparisons and a node on the end
WHILE delta GT 0
% cmp eax, @CatStr(<SwitchValue>, %mmin)
je @CatStr(<SwitchLabel>, %mmin)
mmin = mmin + 1
delta = delta - 1
ENDM
% cmp eax, @CatStr(<SwitchValue>, %mmin)
jne SwitchDefaultLabel
% @CatStr(<SwitchNode>, %mmin)
;; Clear this label variable so we don't output the code again
@CatStr(<SwitchNode>, %mmin) TEXTEQU <>
IFNB <&SwitchExit>
% &SwitchExit
ELSE
jmp SwitchExitLabel
ENDIF
ELSE
;; Output a branch test
delta = _min + (delta/2)
% cmp eax, @CatStr(<SwitchValue>, %delta)
jg HighHalf
je @CatStr(<SwitchLabel>, %delta)
;; Re-Enter this macro until we've tested all the nodes
;; note that we skip the node we just tested for.
.SwitchPartition _min, (delta-1) ;; Lower half of the range
HighHalf:
.SwitchPartition (delta+1), _max ;; High half of the range
ENDIF
ENDM
; Optimized Switch/Case Macro
; by bitRAKE (aka Rickey Bowers Jr.)
;#############################################
SwitchThreshHold = 3 ;when is a bad idea to partition
.switch MACRO
SwitchNodes = 0
SwitchDefault TEXTEQU <>
SwitchExit TEXTEQU <>
ENDM
.case MACRO xVal:REQ, xNode:REQ
@CatStr(<SwitchValue>, %SwitchNodes) = &xVal
@CatStr(<SwitchNode>, %SwitchNodes) TEXTEQU <&xNode>
SwitchNodes = SwitchNodes + 1
ENDM
.default MACRO def:REQ
SwitchDefault TEXTEQU <&def>
ENDM
.endswitch MACRO sexit
LOCAL TheEnd, ww, oo, temp1, temp2, temp3, temp4
SwitchExit TEXTEQU <&sexit>
;; This is a bubble sort on the values of the case statements
;; the labels follow their associated values.
ww = SwitchNodes
WHILE ww
ww = ww - 1
oo = ww
WHILE oo
oo = oo - 1
temp1 = @CatStr(<SwitchValue>, %oo)
temp2 = @CatStr(<SwitchValue>, %ww)
;; We need MASM to evaluate this at assemble-time
% IF &temp1 GT &temp2
;; Numberic values can be swaped easily
@CatStr(<SwitchValue>, %oo) = &temp2
@CatStr(<SwitchValue>, %ww) = &temp1
;; Strings are a little harder...
;; Get the variable names
temp3 TEXTEQU @CatStr(<SwitchNode>, %oo)
temp4 TEXTEQU @CatStr(<SwitchNode>, %ww)
;; Get the value of those varibles
;; MASM doesn't allow &@CatStr(...)!
temp3 TEXTEQU &temp3
temp4 TEXTEQU &temp4
;; Swap them
@CatStr(<SwitchNode>, %oo) TEXTEQU &temp4
@CatStr(<SwitchNode>, %ww) TEXTEQU &temp3
ENDIF
ENDM
ENDM
;; This starts the trasversal of the array as if it were a bbtree
.SwitchPartition 0, SwitchNodes - 1
;; Output the code for the case nodes that haven't been done already
ww = SwitchNodes
WHILE ww
ww = ww - 1
;; Previously output nodes are cleared in the transveral
% IFNB <@CatStr(<SwitchNode>, %ww)>
@CatStr(<SwitchLabel>, %ww, <:>)
% @CatStr(<SwitchNode>, %ww)
IFNB <&SwitchExit>
% &SwitchExit
ELSE
jmp SwitchExitLabel
ENDIF
ENDIF
ENDM
SwitchDefaultLabel:
IFNB <&SwitchDefault>
% &SwitchDefault
IFNB <&SwitchExit>
% &SwitchExit
ENDIF
ENDIF
SwitchExitLabel:
ENDM
;; Transverse the sorted array of variables that was created for each
;; case statement like a balanced binary tree...
.SwitchPartition MACRO _min:REQ, _max:REQ
LOCAL delta, mmin, HighHalf
delta = _max - _min
mmin = _min
IF delta LT SwitchThreshHold
;; Output a string of nodes comparisons and a node on the end
WHILE delta GT 0
% cmp eax, @CatStr(<SwitchValue>, %mmin)
je @CatStr(<SwitchLabel>, %mmin)
mmin = mmin + 1
delta = delta - 1
ENDM
% cmp eax, @CatStr(<SwitchValue>, %mmin)
jne SwitchDefaultLabel
% @CatStr(<SwitchNode>, %mmin)
;; Clear this label variable so we don't output the code again
@CatStr(<SwitchNode>, %mmin) TEXTEQU <>
IFNB <&SwitchExit>
% &SwitchExit
ELSE
jmp SwitchExitLabel
ENDIF
ELSE
;; Output a branch test
delta = _min + (delta/2)
% cmp eax, @CatStr(<SwitchValue>, %delta)
jg HighHalf
je @CatStr(<SwitchLabel>, %delta)
;; Re-Enter this macro until we've tested all the nodes
;; note that we skip the node we just tested for.
.SwitchPartition _min, (delta-1) ;; Lower half of the range
HighHalf:
.SwitchPartition (delta+1), _max ;; High half of the range
ENDIF
ENDM