/*
  ===========================================================================
   File: CONTROL.H                                       v.2.3 - 30.Nov.2009
  ===========================================================================

            ITU-T STL BASIC OPERATORS

            CONTROL   FLOW  OPERATORS

   History:
   07 Nov 04   v2.0     Incorporation of new 32-bit / 40-bit / control
                        operators for the ITU-T Standard Tool Library as
                        described in Geneva, 20-30 January 2004 WP 3/16 Q10/16
                        TD 11 document and subsequent discussions on the
                        wp3audio@yahoogroups.com email reflector.
   March 06   v2.1      Changed to improve portability.

  ============================================================================
*/


#ifndef _CONTROL_H
#define _CONTROL_H

#include "stl.h"

/*****************************************************************************
 *
 *  Constants and Globals
 *
 *****************************************************************************/
#if (WMOPS)
extern BASIC_OP multiCounter[MAXCOUNTERS];
extern int currCounter;

  /* Technical note :
   * The following 3 variables are only used for correct complexity
   * evaluation of the following structure :
   *   IF{
   *     ...
   *   } ELSE IF {
   *     ...
   *   } ELSE IF {
   *     ...
   *   }
   *   ...
   *   } ELSE {
   *     ...
   *   }
   */
extern int  funcId_where_last_call_to_else_occurred;
extern long funcid_total_wmops_at_last_call_to_else;
extern int  call_occurred;
#endif /* if WMOPS */


/*****************************************************************************
 *
 *  Function Macros
 *
 *****************************************************************************/

/*****************************************************************************
 *
 *  Function Name : FOR
 *
 *  Purpose :
 *
 *    The macro FOR should be used instead of the 'for' C statement.
 *    The complexity is independent of the number of loop iterations that are
 *    performed.
 *
 *  Complexity weight : 3 (regardless of number of iterations).
 *
 *****************************************************************************/
#if !(WMOPS)
#define FOR( a) for( a)

#else /* if !(WMOPS) */
#define FOR( a) if( incrFor(), 0); else for( a)

static __inline void incrFor( void) {
   multiCounter[currCounter].For++;
}
#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : WHILE
 *
 *  Purpose :
 *
 *    The macro WHILE should be used instead of the 'while' C statement.
 *    The complexity is proportional to the number of loop iterations that
 *    are performed.
 *
 *  Complexity weight : 4 x 'number of loop iterations'.
 *
 *****************************************************************************/
#if !(WMOPS)
#define WHILE( a) while( a)

#else /* if !(WMOPS) */
#define WHILE( a) while( incrWhile(), a)

static __inline void incrWhile( void) {
   multiCounter[currCounter].While++;
}
#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : DO
 *
 *  Purpose :
 *
 *    The macro DO should be used instead of the 'do' C statement.
 *
 *  Complexity weight : 0 (complexity counted by WHILE macro).
 *
 *****************************************************************************/
#if !(WMOPS)
#define DO do

#else /* if !(WMOPS) */
#define DO do

#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : IF
 *
 *  Purpose :
 *
 *    The macro IF should :
 *
 *    - not be used when :
 *      - the 'if' structure does not have any 'else if' nor 'else' statement
 *      - and it conditions only one DSP basic operations.
 *
 *    - be used instead of the 'if' C statement in every other case :
 *      - when there is an 'else' or 'else if' statement,
 *      - or when the 'if' conditions several DSP basic operations,
 *      - or when the 'if' conditions a function call.
 *
 *  Complexity weight : 4
 *
 *****************************************************************************/
#if !(WMOPS)
#define IF( a) if( a)

#else /* if !(WMOPS) */
#define IF( a) if( incrIf(), a)

static __inline void incrIf( void) {
   /* Technical note :
    * If the "IF" operator comes just after an "ELSE", its counter
    * must not be incremented.
    */
   if ( (currCounter != funcId_where_last_call_to_else_occurred)
     || (TotalWeightedOperation() != funcid_total_wmops_at_last_call_to_else)
     || (call_occurred == 1))
     multiCounter[currCounter].If++;

   call_occurred = 0;
   funcId_where_last_call_to_else_occurred = MAXCOUNTERS;
}
#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : ELSE
 *
 *  Purpose :
 *
 *    The macro ELSE should be used instead of the 'else' C statement.
 *
 *  Complexity weight : 4
 *
 *****************************************************************************/
#if !(WMOPS)
#define ELSE else

#else /* if !(WMOPS) */
#define ELSE else if( incrElse(), 0) ; else

static __inline void incrElse( void) {
   multiCounter[currCounter].If++;

   /* We keep track of the funcId of the last function
    * which used ELSE {...} structure.
    */
   funcId_where_last_call_to_else_occurred = currCounter;

   /* We keep track of the number of WMOPS of this funcId
    * when the ELSE macro was called.
    */
   funcid_total_wmops_at_last_call_to_else = TotalWeightedOperation();

   /* call_occurred is set to 0, in order to count the next IF (if necessary)
    */
   call_occurred=0;
}
#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : SWITCH
 *
 *  Purpose :
 *
 *    The macro SWITCH should be used instead of the 'switch' C statement.
 *
 *  Complexity weight : 8
 *
 *****************************************************************************/
#if !(WMOPS)
#define SWITCH( a) switch( a)

#else /* if !(WMOPS) */
#define SWITCH( a) switch( incrSwitch(), a)

static __inline void incrSwitch( void) {
   multiCounter[currCounter].Switch++;
}
#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : CONTINUE
 *
 *  Purpose :
 *
 *    The macro CONTINUE should be used instead of the 'continue' C statement.
 *
 *  Complexity weight : 4
 *
 *****************************************************************************/
#if !(WMOPS)
#define CONTINUE continue

#else /* if !(WMOPS) */
#define CONTINUE if( incrContinue(), 0); else continue

static __inline void incrContinue( void) {
   multiCounter[currCounter].Continue++;
}
#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : BREAK
 *
 *  Purpose :
 *
 *    The macro BREAK should be used instead of the 'break' C statement.
 *
 *  Complexity weight : 4
 *
 *****************************************************************************/
#if !(WMOPS)
#define BREAK break

#else /* if !(WMOPS) */
#define BREAK if( incrBreak(), 0) break; else break

static __inline void incrBreak( void) {
   multiCounter[currCounter].Break++;
}
#endif /* if !(WMOPS) */


/*****************************************************************************
 *
 *  Function Name : GOTO
 *
 *  Purpose :
 *
 *    The macro GOTO should be used instead of the 'goto' C statement.
 *
 *  Complexity weight : 4
 *
 *****************************************************************************/
#if !(WMOPS)
#define GOTO goto

#else /* if !(WMOPS) */
#define GOTO if( incrGoto(), 0); else goto

static __inline void incrGoto( void) {
   multiCounter[currCounter].Goto++;
}
#endif /* if !(WMOPS) */


#endif /* _CONTROL_H */


/* end of file */
