%if EXISTS("_FIXPTLOOK_SEARCH_") == 0
%assign _FIXPTLOOK_SEARCH_ = 1
%include "fixptlook_support.tlc"
%function FixPt_IndexSearchTrivial(...
xLabel,xDT,...
xBreakPointInfo) void
%if !xBreakPointInfo.evenlySpaced || !ISEQUAL(xBreakPointInfo.spacingValue,1)
%<LibReportFatalError("Must have trivial spacing.")>
%endif
%assign unsignType = utilUnsignedTypeFromDT(xDT)
%assign hiCheckNeeded = FixPt_GreaterThanPossible(xDT,xBreakPointInfo.valueHi)
%assign loCheckNeeded = FixPt_LessThanPossible( xDT,xBreakPointInfo.valueLo)
%assign baseIndexExpr = "((%<unsignType>)(%<xLabel>%<xBreakPointInfo.zeroAdjustStr>))"
%if loCheckNeeded
%if hiCheckNeeded
%assign indexExpr = "( (%<xLabel><=%<xBreakPointInfo.valueLo>) ? 0U : ( (%<xLabel>>=%<xBreakPointInfo.valueHi>) ? (%<xBreakPointInfo.indexHi>) : %<baseIndexExpr> ) )"
%else
%assign indexExpr = "( (%<xLabel><=%<xBreakPointInfo.valueLo>) ? 0U : %<baseIndexExpr> )"
%endif
%else
%if hiCheckNeeded
%assign indexExpr = "( (%<xLabel>>=%<xBreakPointInfo.valueHi>) ? (%<xBreakPointInfo.indexHi>) : %<baseIndexExpr> )"
%else
%assign indexExpr = baseIndexExpr
%endif
%endif
%return indexExpr
%endfunction
%function FixPt_IndexSearchEven(...
iLeftLabel,iRghtLabel,...
u0Label, u0DT, u0BreakPointInfo,...
searchType) Output
%assign unsignType = utilUnsignedTypeFromDT(u0DT)
%assign spacingIsOne = ISEQUAL(u0BreakPointInfo.spacingValue,1)
%if spacingIsOne && !FixPt_DataTypeIsFloat(u0DT)
%assign completelyTrivialCase = 1
%else
%assign completelyTrivialCase = 0
%endif
%assign hiCheckNeeded = FixPt_GreaterThanPossible(u0DT,u0BreakPointInfo.valueHi)
%assign loCheckNeeded = FixPt_LessThanPossible( u0DT,u0BreakPointInfo.valueLo)
/* Find the location of current input value in the data table.
%if !loCheckNeeded
*
* Based on the data type of the input, it is impossible for the
* search value to be less than the smallest point in the table.
%endif
%if !hiCheckNeeded
*
* Based on the data type of the input, it is impossible for the
* search value to be greater than the largest point in the table.
%endif
*/
%if loCheckNeeded
if ( %<u0Label> <= %<u0BreakPointInfo.valueLo> )
{
/* Less than or equal to the smallest point in the table.
*/
%if ( iLeftLabel != "" )
%<iLeftLabel> = 0U;
%endif
%if ( iRghtLabel != "" )
%<iRghtLabel> = 0U;
%endif
}
%endif
%if hiCheckNeeded
%if loCheckNeeded
else/
%endif
if ( %<u0Label> >= %<u0BreakPointInfo.valueHi> )
{
/* Greater than or equal to the largest point in the table. */
%if ( iLeftLabel != "" )
%<iLeftLabel> = %<u0BreakPointInfo.indexHi>;
%endif
%if ( iRghtLabel != "" )
%<iRghtLabel> = %<u0BreakPointInfo.indexHi>;
%endif
}
%endif
%if loCheckNeeded || hiCheckNeeded
else
%endif
%if ( searchType == "Below" ) || ( searchType == "Near" )
{
%if spacingIsOne
%<iLeftLabel> = (%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> );
%elseif u0BreakPointInfo.spacingIsPow2
/* The table is inlined with even spacing 2^%<u0BreakPointInfo.spacingPow2Exp>.
* The index is found by a %<u0BreakPointInfo.spacingPow2Exp> bit shift right. */
%<iLeftLabel> = (%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) >> %<u0BreakPointInfo.spacingPow2Exp>;
%else
/* The table is inlined and evenly spaced.
* The index is found directly by use of division.
*/
%if FixPt_DataTypeIsFloat(u0DT)
%<iLeftLabel> = (%<unsignType>)(( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) / %<u0BreakPointInfo.spacingValue>);
%else
%<iLeftLabel> = (%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) / %<u0BreakPointInfo.spacingValue>;
%endif
%endif
%if completelyTrivialCase
%if ( iRghtLabel != "" )
%<iRghtLabel> = %<iLeftLabel>;
%endif
%else
%if ( iRghtLabel != "" )
%<iRghtLabel> = %<iLeftLabel> + 1;
%endif
%if searchType == "Near"
%if u0BreakPointInfo.spacingIsPow2 && !FixPt_DataTypeIsFloat(u0DT)
/* Adjust the index, if necessary, so that it always
* gives the data point nearest the current input value.
* It is necessary to round up iff the last bit shifted
* off was a one.
*/
%assign mask = PowerOfTwoStr(u0BreakPointInfo.spacingPow2Exp-1,0)
%<iLeftLabel> += ((%<unsignType>)(( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) & %<mask> )) != 0U;
%else
%assign unsignTypeU = utilFloatOrUnsignedTypeFromDT(u0DT)
/* Adjust the index, if necessary, so that it always
* gives the data point nearest the current input value.
* It is necessary to round up iff the remainder is greater
* than or equal to half the data spacing.
* ( spacing / 2 ) <= remainder
* To avoid both division and multiplication and issues of
* rounding and overflow, this test is rearranged.
* ( spacing - remainder ) <= remainder
*/
{
%<unsignTypeU> remainder;
%if FixPt_DataTypeIsFloat(u0DT)
remainder = (%<unsignTypeU>)(( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) - %<u0BreakPointInfo.spacingValue>*%<iLeftLabel>);
%else
remainder = (%<unsignTypeU>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) % %<u0BreakPointInfo.spacingValue>;
%endif
if ( ( %<u0BreakPointInfo.spacingValue> - remainder ) <= remainder )
{
%<iLeftLabel>++;
}
}
%endif
%endif
%endif
}
%else
{
%if spacingIsOne
%<iRghtLabel> = (%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> );
%if FixPt_DataTypeIsFloat(u0DT)
%<iRghtLabel> += (%<unsignType>)(( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) != (%<iRghtLabel>));
%endif
%elseif u0BreakPointInfo.spacingIsPow2 && !FixPt_DataTypeIsFloat(u0DT)
/* The table is inlined with even spacing 2^%<u0BreakPointInfo.spacingPow2Exp>.
* The index is found by a %<u0BreakPointInfo.spacingPow2Exp> bit shift right.
* If any of the %<u0BreakPointInfo.spacingPow2Exp> bits shifted off are not zero, then rounded up. */
%if FixPt_DataTypeIsFloat(u0DT)
%assign xMaskBits = "#error Cannot use Mask with floating point"
%elseif u0DT.RequiredBits <= IntegerSizes.IntNumBits
%assign xMaskBits = IntegerSizes.IntNumBits
%else
%assign xMaskBits = IntegerSizes.LongNumBits
%endif
%assign mask = SetLSNBitsStr(u0BreakPointInfo.spacingPow2Exp,xMaskBits,0)
%<iRghtLabel> = (%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) >> %<u0BreakPointInfo.spacingPow2Exp>;
%<iRghtLabel> += (((%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) & %<mask>) != 0 );
%else
/* The table is inlined and evenly spaced.
* The index is found directly by use of division.
* If the remainder is not zero, then rounded up.
*/
%if FixPt_DataTypeIsFloat(u0DT)
%<iRghtLabel> = (%<unsignType>)(( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) / %<u0BreakPointInfo.spacingValue>);
%<iRghtLabel> += (%<unsignType>)(( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) != (%<u0BreakPointInfo.spacingValue>*%<iRghtLabel>));
%else
%<iRghtLabel> = (%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) / %<u0BreakPointInfo.spacingValue>;
%<iRghtLabel> += (((%<unsignType>)( %<u0Label>%<u0BreakPointInfo.zeroAdjustStr> ) % %<u0BreakPointInfo.spacingValue>) != 0 );
%endif
%endif
%if ( iLeftLabel != "" )
%if completelyTrivialCase
%<iLeftLabel> = %<iRghtLabel>;
%else
%<iLeftLabel> = %<iRghtLabel> - 1;
%endif
%endif
}
%endif
%endfunction
%function FixPt_IndexSearch(iLeftLabel,iRghtLabel,...
u0Label,u0DT,...
u0Data,u0DataDT,...
u0DataBreakPointInfo,u0DataCategory,...
searchType) Output
%<FixPt_IndexSearchProperUseCheck(iLeftLabel,iRghtLabel,u0DT,u0DataDT,searchType)>/
%if u0DataBreakPointInfo.evenlySpaced
%assign u0BreakPointInfo = FixPt_BreakPointInfoCast(u0DataBreakPointInfo,u0DataDT,u0DT)
%<FixPt_IndexSearchEven(iLeftLabel,iRghtLabel,...
u0Label, u0DT, u0BreakPointInfo,...
searchType)>/
%else
%assign iHi = FixPt_HelperVarHiIndex(u0Data, u0DataCategory)
%<FixPt_IndexSearch_New(iLeftLabel,iRghtLabel,...
u0Label,u0DT,...
u0Data,u0DataDT,...
u0DataBreakPointInfo,u0DataCategory,...
iHi,...
searchType)>
%endif
%endfunction
%function FixPt_IndexSearchUneven(...
iLeftLabel,iRghtLabel,...
u0Label, u0DT,...
u0DataAddrLabel, u0DataDT,...
iHi,...
searchType) Output
%<FixPt_IndexSearchProperUseCheck(iLeftLabel,iRghtLabel,u0DT,u0DataDT,searchType)>/
%assign loCheckRelop = "<="
%assign hiCheckRelop = ">="
%assign loCheckComment = "or equal to "
%assign hiCheckComment = "or equal to "
%assign FixPtBinarySearchUseMacros = 0
%assign utilityName = FixPt_UtilityMakeName("BINARYSEARCH")
%assign utilityName = FixPt_UtilityNameAppendDTPair(utilityName,u0DT,u0DataDT)
%if ( searchType != "Below" )
%assign utilityName = utilityName + "_" + STRING(searchType)
%endif
%if iLeftLabel != ""
%if iRghtLabel != ""
%else
%assign utilityName = utilityName + "_iL"
%endif
%else
%if iRghtLabel != ""
%assign utilityName = utilityName + "_iR"
%else
%<LibReportFatalError("FixPt_IndexSearch_New used improperly. Neither a left index nor a right index was specified.")>
%endif
%endif
%if SLibInBlockScope()
%assign block = SLibGetCurrentBlock()
%else
%assign block = ""
%endif
%assign utilityName = SLibRegisterSharedUtility(block, utilityName)
%<FcnTrackSharedUtilHeaderFileUsage(utilityName + ".h", TLC_FALSE)>
%if FixPtBinarySearchUseMacros
%if iLeftLabel != "" && iRghtLabel != ""
%<utilityName>( %<iLeftLabel>, %<iRghtLabel>, %<u0Label>, %<u0DataAddrLabel>, %<iHi>);
%elseif iLeftLabel != ""
%<utilityName>( %<iLeftLabel>, %<u0Label>, %<u0DataAddrLabel>, %<iHi>);
%else
%<utilityName>( %<iRghtLabel>, %<u0Label>, %<u0DataAddrLabel>, %<iHi>);
%endif
%else
%if iLeftLabel != "" && iRghtLabel != ""
%<utilityName>( &(%<iLeftLabel>), &(%<iRghtLabel>), %<u0Label>, %<u0DataAddrLabel>, %<iHi>);
%elseif iLeftLabel != ""
%<utilityName>( &(%<iLeftLabel>), %<u0Label>, %<u0DataAddrLabel>, %<iHi>);
%else
%<utilityName>( &(%<iRghtLabel>), %<u0Label>, %<u0DataAddrLabel>, %<iHi>);
%endif
%endif
%if !(ISFIELD(FixPtUtils,utilityName))
%assign tmpRet = SETFIELD(FixPtUtils,utilityName,1)
%<LibPushEmptyStackSharedUtils()>/
%openfile utilityDef
%assign local_iLeftLabel = "iLeft"
%assign local_iRghtLabel = "iRght"
%assign local_u0Label = "u"
%assign local_pDataLabel = "pData"
%assign local_iHiLabel = "iHi"
%if FixPtBinarySearchUseMacros
%<FcnTrackSharedUtilHeaderFileUsage(utilityName + ".h", TLC_FALSE)>
%if iLeftLabel != "" && iRghtLabel != ""
#define %<utilityName>( %<local_iLeftLabel>, %<local_iRghtLabel>, %<local_u0Label>, %<local_pDataLabel>, %<local_iHiLabel>)
%elseif iLeftLabel != ""
#define %<utilityName>( %<local_iLeftLabel>, %<local_u0Label>, %<local_pDataLabel>, %<local_iHiLabel>)
%else
#define %<utilityName>( %<local_iRghtLabel>, %<local_u0Label>, %<local_pDataLabel>, %<local_iHiLabel>)
%endif
%assign local_iLeftLabel = "("+local_iLeftLabel+")"
%assign local_iRghtLabel = "("+local_iRghtLabel+")"
%assign local_u0Label = "("+local_u0Label +")"
%assign local_pDataLabel = "("+local_pDataLabel+")"
%assign local_iHiLabel = "("+local_iHiLabel +")"
%else
%assign fcnAbstract = "Lookup Binary Search Utility " + utilityName
%assign fcnReturns = "void"
%assign fcnName = utilityName
%if iLeftLabel != "" && iRghtLabel != ""
%assign local_iLeftLabel = "*p"+local_iLeftLabel
%assign local_iRghtLabel = "*p"+local_iRghtLabel
%assign fcnParams = "%<FixPt_uint_label> %<local_iLeftLabel>, %<FixPt_uint_label> %<local_iRghtLabel>, %<u0DT.NativeType> %<local_u0Label>, const %<u0DataDT.NativeType> *%<local_pDataLabel>, %<FixPt_uint_label> %<local_iHiLabel>"
%elseif iLeftLabel != ""
%assign local_iLeftLabel = "*p"+local_iLeftLabel
%assign fcnParams = "%<FixPt_uint_label> %<local_iLeftLabel>, %<u0DT.NativeType> %<local_u0Label>, const %<u0DataDT.NativeType> *%<local_pDataLabel>, %<FixPt_uint_label> %<local_iHiLabel>"
%else
%assign local_iRghtLabel = "*p"+local_iRghtLabel
%assign fcnParams = "%<FixPt_uint_label> %<local_iRghtLabel>, %<u0DT.NativeType> %<local_u0Label>, const %<u0DataDT.NativeType> *%<local_pDataLabel>, %<FixPt_uint_label> %<local_iHiLabel>"
%endif
%assign staticSpecifier = LibGetStaticStorageSpecifierIfNeeded()
%assign funcDecRoot = staticSpecifier + fcnReturns + " " + fcnName + "(" + fcnParams + ")"
%openfile funcProto
%<funcDecRoot>;
%closefile funcProto
%selectfile utilityDef
%createrecord fcnRec {Name fcnName; Returns fcnReturns; Params fcnParams; ...
Abstract fcnAbstract; Category "utility"; GeneratedBy "fixptlook_search.tlc"}
%<SLibDumpFunctionBanner(fcnRec)>
%undef fcnRec
%<funcDecRoot>
%endif
{
%if iLeftLabel == ""
%<FixPt_uint_label> %<local_iLeftLabel>;
%endif
%if iRghtLabel == ""
%<FixPt_uint_label> %<local_iRghtLabel>;
%endif
%if !FixPt_DataTypesSame(u0DT,u0DataDT)
%assign dataTypesDifferent = 1
%assign uCastLabel = "uCast"
%<u0DataDT.NativeType> %<uCastLabel>;
/* cast current input to the data type/scaling of the table data */
%if ( searchType == "Below" ) || ( searchType == "Near" )
%<FixPt_Fix2FixAlwaysOutput(uCastLabel,u0DataDT,local_u0Label,u0DT,"Floor","Saturate")>/
%assign loCheckRelop = "<"
%assign loCheckComment = ""
%else
%<FixPt_Fix2FixAlwaysOutput(uCastLabel,u0DataDT,local_u0Label,u0DT,"Ceiling","Saturate")>/
%assign hiCheckRelop = ">"
%assign hiCheckComment = ""
%endif
%else
%assign dataTypesDifferent = 0
%assign uCastLabel = local_u0Label
%endif
/* Find the location of current input value in the data table. */
%<local_iLeftLabel> = 0U;
%<local_iRghtLabel> = %<local_iHiLabel>;
if ( %<uCastLabel> %<loCheckRelop> %<local_pDataLabel>[0] )
{
/* Less than %<loCheckComment>the smallest point in the table. */
%if iRghtLabel != ""
%<local_iRghtLabel> = 0U;
%endif
}
else if ( %<uCastLabel> %<hiCheckRelop> %<local_pDataLabel>[%<local_iHiLabel>] )
{
/* Greater than %<hiCheckComment>the largest point in the table. */
%if iLeftLabel != ""
%<local_iLeftLabel> = %<local_iHiLabel>;
%endif
}
else
{
%<FixPt_uint_label> i;
/* Do a binary search. */
while ( ( %<local_iRghtLabel> - %<local_iLeftLabel> ) > 1U )
{
/* Get the average of the left and right indices using to Floor rounding. */
i = (%<local_iLeftLabel> + %<local_iRghtLabel>) >> 1;
/* Move either the right index or the left index so that */
%if ( searchType == "Below" ) || ( searchType == "Near" )
/* LeftDataPoint <= CurrentValue < RightDataPoint */
if ( %<uCastLabel> < %<local_pDataLabel>[i] )
%else
/* LeftDataPoint < CurrentValue <= RightDataPoint */
if ( %<uCastLabel> <= %<local_pDataLabel>[i] )
%endif
{
%<local_iRghtLabel> = i;
}
else
{
%<local_iLeftLabel> = i;
}
}
%if searchType == "Near"
%assign unsignTypeU = utilFloatOrUnsignedTypeFromDT(u0DT)
/* Adjust the left index, if necessary, so that it always gives */
/* the index of the data point nearest the current input value. */
{
%<unsignTypeU> diffLeft, diffRght;
%if dataTypesDifferent
/* cast the table data points to the data type/scaling of the input */
%<FixPt_Fix2FixAlwaysOutput("diffLeft",u0DT,local_pDataLabel+"["+local_iLeftLabel+"]",u0DataDT,"Floor","Saturate")>/
%<FixPt_Fix2FixAlwaysOutput("diffRght",u0DT,local_pDataLabel+"["+local_iRghtLabel+"]",u0DataDT,"Floor","Saturate")>/
diffLeft = %<local_u0Label> - diffLeft;
diffRght = diffRght - %<local_u0Label>;
%else
diffLeft = %<local_u0Label> - %<local_pDataLabel>[%<local_iLeftLabel>];
diffRght = %<local_pDataLabel>[%<local_iRghtLabel>] - %<local_u0Label>;
%endif
if ( diffRght <= diffLeft )
{
%<local_iLeftLabel> = %<local_iRghtLabel>;
}
}
%endif
}
%selectfile utilityDef
}
%closefile utilityDef
%if FixPtBinarySearchUseMacros
%assign utilityDef = FEVAL("strrep",utilityDef,"/n"," ///n")
%endif
%if FixPtBinarySearchUseMacros
%<SLibDumpUtilsMacro(utilityName,utilityDef)>/
%else
%<SLibAddMathIncludeForUtilsSourceCode(utilityDef)>
%<SLibDumpUtilsSourceCodeAndCacheFunctionPrototype(utilityName,funcProto,utilityDef)>/
%endif
%assign GSUStackBuf = LibPopStackSharedUtilsIncludes()
%endif
%endfunction
%function FixPt_IndexSearch_New(iLeftLabel,iRghtLabel,...
u0Label,u0DT,...
u0Data,u0DataDT,...
u0DataBreakPointInfo,u0DataCategory,...
iHi,...
searchType) Output
%<FixPt_IndexSearchProperUseCheck(iLeftLabel,iRghtLabel,u0DT,u0DataDT,searchType)>/
%if u0DataBreakPointInfo.evenlySpaced
%assign u0BreakPointInfo = FixPt_BreakPointInfoCast(u0DataBreakPointInfo,u0DataDT,u0DT)
%<FixPt_IndexSearchEven(iLeftLabel,iRghtLabel,...
u0Label, u0DT, u0BreakPointInfo,...
searchType)>/
%else
%assign u0DataAddrLabel = FixPt_HelperGetRValuePtr("","",0,"",u0Data,u0DataCategory)
%<FixPt_IndexSearchUneven(...
iLeftLabel,iRghtLabel,...
u0Label, u0DT,...
u0DataAddrLabel, u0DataDT, ...
iHi,...
searchType)>/
%endif
%endfunction
%function (...
iLeftLabel, ...
iRghtLabel,...
uLabel, ...
uDT, ...
uLoLabel, ...
idxMaxLabel, ...
uMinusLeftLabel, ...
adjustDTForUMinusLeft, ...
dtTypeForUMinusLeft, ...
dtTypeForIndex, ...
spacingLabel, ...
spacingPow2Exp, ...
searchMethod) Output
%assign hasFloatIn = FixPt_DataTypeIsFloat(uDT)
if ( %<uLabel> <= %<uLoLabel> )
{
%<uMinusLeftLabel> = %<FixPt_GetGroundValueOrNameFromDataTypeRec(adjustDTForUMinusLeft, TLC_FALSE)>;
%<iLeftLabel> = 0U;
%<iRghtLabel> = 0U;
}
else
{
%if hasFloatIn
%<dtTypeForUMinusLeft> tmpIdxLeft;
%assign floatLimit = FEVAL("eval","[int2str(2^%<IntegerSizes.LongNumBits>) '.0']")
%if FixPt_DataTypeIsSingle(uDT)
%assign floatLimit = floatLimit + "f"
%endif
%assign floatCheckStart = "(tmpIdxLeft >= %<floatLimit>) || ("
%assign floatCheckEnd = ")"
%else
%assign floatCheckStart = ""
%assign floatCheckEnd = ""
%endif
%<uMinusLeftLabel> = (%<dtTypeForUMinusLeft>)(%<uLabel> - %<uLoLabel>);
%if hasFloatIn
tmpIdxLeft = %<uMinusLeftLabel> / %<spacingLabel>;
%<iLeftLabel> = (%<dtTypeForIndex>)tmpIdxLeft;
%else
%if searchMethod == searchPow2
%<iLeftLabel> = (%<dtTypeForIndex>)(%<uMinusLeftLabel>) >> %<spacingPow2Exp>;
%else
%<iLeftLabel> = (%<dtTypeForIndex>)( %<uMinusLeftLabel> / %<spacingLabel> );
%endif
%endif
if (%<floatCheckStart>%<iLeftLabel> >= %<idxMaxLabel>%<floatCheckEnd>)
{
%<uMinusLeftLabel> = %<FixPt_GetGroundValueOrNameFromDataTypeRec(adjustDTForUMinusLeft, TLC_FALSE)>;
%<iLeftLabel> = %<idxMaxLabel>;
%<iRghtLabel> = %<idxMaxLabel>;
}
else
{
%if searchMethod == searchPow2
%assign mask = SetLSNBitsStr(spacingPow2Exp,uDT.ActualBits,0)
%<uMinusLeftLabel> &= %<mask>;
%else
%<uMinusLeftLabel> = %<uMinusLeftLabel> - (%<iLeftLabel> * %<spacingLabel>);
%endif
%<iRghtLabel> = %<iLeftLabel> + 1U;
}
}
%endfunction
%endif