JD2022-TU1/main/extern/gear4/gear_testing/performance/perftest_traits.h

258 lines
14 KiB
C++

#ifndef _GEAR_TESTING__PERFTEST_TRAITS_H_
#define _GEAR_TESTING__PERFTEST_TRAITS_H_
#include "perftest_generators.h"
namespace G4
{
//
// *** IMPORTANT NOTE ***
// There is a liberal (to put it mildly) use of preprocessor macros in the performance testing code.
// The reason for this is because we have to handle functions with varying numbers of arguments, and this code has many classes which
// need to be templated based on the length of a function's argument list. Unfortunately, template classes are somewhat ill-suited for
// use in generic programming based on the number of function arguments.
// Template specialization gets us most of the way to solving this problem, but it is easy to see that a large number of specializations
// results in many chunks of (mostly) similar code which is unwieldy to maintain. (i.e. nearly ideneity chunks for 1-argument, 2-argument, etc)
// We therefore use convenience macros that easily construct lists of arbitrary length. These lists can then be used in larger macros which
// provide the skeleton for the specialization of some template class. Template specializations can then be constructed by simply invoking
// the macro with a number representing the number of function arguments.
// For a good example, see the FunctionTraits<> class.
//
// ----------
//
// ArgType
// Sometimes we must alias a function parameter as something else when we store it
// For example, in the case of fixed-dimension arrays, or pair types that hold const-qualified data
//
template < typename TYPE >
struct ArgType
{
typedef TYPE type;
};
template < typename TYPE, int M, int N >
struct ArgType< TYPE[M][N] >
{
typedef Array2DWrapper< TYPE, M, N > type;
};
template < typename _TYPE1, typename _TYPE2 >
struct ArgType< std::pair< _TYPE1, _TYPE2 > >
{
typedef PairWrapper< typename G4::remove_const< _TYPE1 >::type, typename G4::remove_const< _TYPE2 >::type, std::pair > type;
};
template < typename _TYPE1, typename _TYPE2 >
struct ArgType< G4::Pair< _TYPE1, _TYPE2 > >
{
typedef PairWrapper< typename G4::remove_const< _TYPE1 >::type, typename G4::remove_const< _TYPE2 >::type, G4::Pair > type;
};
// Removes both the "const" and reference ('&') qualifiers from any type - This is similar to std::decay
template < typename T >
struct RemoveQualifiers
{
typedef typename G4::remove_const< typename G4::remove_reference< T >::type >::type type;
};
/*
// A handy macro to perform a LISP-like 'cons' of an element onto a (possibly empty) list
// -- Currently not used because the clang compiler (Orbis, Mac, iOS) doesn't seem to like it.
#if G4_PLATFORM_MS
#define CONS( _CAR, ... ) _CAR , ## __VA_ARGS__
#else
#define CONS_PASTE( _CAR, ... ) _CAR , ## __VA_ARGS__
#define CONS( ... ) CONS_PASTE( __VA_ARGS__ )
#endif
*/
//
// Helper macros to expand lists where the Nth item in the list has the number N inserted appropriately
// The number N is added by invoking a macro (the 'stub') which does the proper substitution
// The macro is used as follows: LIST ## N ( MY_STUB )
// There are two other variants of these macros, "LIST_POST" and "LIST_PRE", which are useful when the list is appended
// or prepended to another list. They solve the 'dangling comma' problem when the list is empty.
//
#define LIST0( _STUB )
#define LIST1( _STUB ) _STUB( 0 )
#define LIST2( _STUB ) LIST1( _STUB ) , _STUB( 1 )
#define LIST3( _STUB ) LIST2( _STUB ) , _STUB( 2 )
#define LIST4( _STUB ) LIST3( _STUB ) , _STUB( 3 )
#define LIST5( _STUB ) LIST4( _STUB ) , _STUB( 4 )
#define LIST6( _STUB ) LIST5( _STUB ) , _STUB( 5 )
#define LIST7( _STUB ) LIST6( _STUB ) , _STUB( 6 )
#define LIST8( _STUB ) LIST7( _STUB ) , _STUB( 7 )
#define LIST9( _STUB ) LIST8( _STUB ) , _STUB( 8 )
// #define LIST( _N, _STUB ) LIST## _N ( TEMPLATE_ARGS_STUB ) // This macro doesn't seem to work with the SNC compiler
#define LIST_POST0( _STUB )
#define LIST_POST1( _STUB ) , LIST1( _STUB )
#define LIST_POST2( _STUB ) , LIST2( _STUB )
#define LIST_POST3( _STUB ) , LIST3( _STUB )
#define LIST_POST4( _STUB ) , LIST4( _STUB )
#define LIST_POST5( _STUB ) , LIST5( _STUB )
#define LIST_POST6( _STUB ) , LIST6( _STUB )
#define LIST_POST7( _STUB ) , LIST7( _STUB )
#define LIST_POST8( _STUB ) , LIST8( _STUB )
#define LIST_POST9( _STUB ) , LIST9( _STUB )
// #define LIST_POST( _N, _STUB ) LIST_POST ## _N ( TEMPLATE_ARGS_STUB ) // This macro doesn't seem to work with the SNC compiler
#define LIST_PRE0( _STUB )
#define LIST_PRE1( _STUB ) LIST1( _STUB ) ,
#define LIST_PRE2( _STUB ) LIST2( _STUB ) ,
#define LIST_PRE3( _STUB ) LIST3( _STUB ) ,
#define LIST_PRE4( _STUB ) LIST4( _STUB ) ,
#define LIST_PRE5( _STUB ) LIST5( _STUB ) ,
#define LIST_PRE6( _STUB ) LIST6( _STUB ) ,
#define LIST_PRE7( _STUB ) LIST7( _STUB ) ,
#define LIST_PRE8( _STUB ) LIST8( _STUB ) ,
#define LIST_PRE9( _STUB ) LIST9( _STUB ) ,
// #define LIST_PRE( _N, _STUB ) LIST_PRE ## _N ( TEMPLATE_ARGS_STUB ) // This macro doesn't seem to work with the SNC compiler
//
// *** ArgListTraits ***
// A traits class that helps set up some required data structures
// Given the length of a function's argument list and a list of argument types, it defines a tuple (ArgTypes) that can hold
// data that will be passed to the function during testing.
// We also define a tuple (RandomValueGenerators) that holds a list of test value generators for each of the function's arguments.
//
template < int _NUMARGS >
struct ArgListTraits;
// Expands to a list: typename _ARGTYPE0, typename _ARGTYPE1, ... , typename _ARGTYPEN
#define TEMPLATE_ARGS_STUB( _N ) typename _ARGTYPE ## _N
#define TEMPLATE_ARGS( _N ) LIST ## _N ( TEMPLATE_ARGS_STUB )
#define TEMPLATE_ARGS_POST( _N ) LIST_POST ## _N ( TEMPLATE_ARGS_STUB )
// Expands to a list: _ARGTYPE0, _ARGTYPE1, ... , _ARGTYPEN
#define ARGLIST_STUB( _N ) _ARGTYPE ## _N
#define ARGLIST( _N ) LIST ## _N ( ARGLIST_STUB )
#define ARGLIST_POST( _N ) LIST_POST ## _N ( ARGLIST_STUB )
#define UNQUALIFIED_TYPENAME_STUB( _N ) typename ArgType< typename G4::RemoveQualifiers< _ARGTYPE ## _N >::type >::type
#define UNQUALIFIED_TYPENAMES( _N ) LIST ## _N ( UNQUALIFIED_TYPENAME_STUB )
#define RANDOM_VALUE_GENERATORS_STUB( _N ) RandomValueGenerator< typename G4::RemoveQualifiers< _ARGTYPE ## _N >::type >
#define RANDOM_VALUE_GENERATORS( _N ) LIST ## _N ( RANDOM_VALUE_GENERATORS_STUB )
template < >
struct ArgListTraits< 0 >
{
template < typename _RESULTTYPE >
struct Traits
{
typedef G4::tuple< typename G4::RemoveQualifiers< _RESULTTYPE >::type > ArgTypes;
typedef void RandomValueGenerators;
};
};
#define ARGLIST_TRAITS( _X ) \
template < > \
struct ArgListTraits< _X > \
{ \
template < typename _RESULTTYPE TEMPLATE_ARGS_POST( _X ) > \
struct Traits \
{ \
typedef G4::tuple< UNQUALIFIED_TYPENAMES( _X ), \
typename G4::RemoveQualifiers< _RESULTTYPE >::type > ArgTypes; \
typedef G4::tuple< RANDOM_VALUE_GENERATORS( _X ) > RandomValueGenerators; \
}; \
template < TEMPLATE_ARGS( _X ) > \
struct Traits< void ARGLIST_POST( _X ) > \
{ \
typedef G4::tuple< UNQUALIFIED_TYPENAMES( _X ) > ArgTypes; \
typedef G4::tuple< RANDOM_VALUE_GENERATORS( _X ) > RandomValueGenerators; \
}; \
};
// ARGLIST_TRAITS( 0 ) // Requires explicit specialization because we cannot have tuples of length zero
ARGLIST_TRAITS( 1 )
ARGLIST_TRAITS( 2 )
ARGLIST_TRAITS( 3 )
ARGLIST_TRAITS( 4 )
ARGLIST_TRAITS( 5 )
ARGLIST_TRAITS( 6 )
ARGLIST_TRAITS( 7 )
ARGLIST_TRAITS( 8 )
ARGLIST_TRAITS( 9 )
//
// *** FunctionTraits ***
// A traits class to provide information about function signatures.
// The key information is:
// ResultType - The (possibly void) value type that the function returns
// Signature - The function signature itself
// IsClassMethod - true if the function signature is for a (non-static) class method
// NumArgs - The number of arguments that the function takes. For (non-static) class methods, the class itself is regarded as an argument!
// HasReturnvalue - true if the function returns a non-void value
// ArgList - A tuple that is able to hold one full set of data for the function - including function arguments, class instance, and result value
// RandomValueGenerators - A tuple that holds a set of random value generators, one for each of the function arguments (including class instance)
// Note that _RESULTTYPE is set to 'void' for RandomValueGenerators, as results don't need to be initialized
//
template < typename TYPE >
struct FunctionTraits;
// A class method has the same traits as a function with an extra argument of the same type as the class - They differ only by function signature and the IsClassMethod field
// -- const and non-const methods have the same traits
// __VA_ARGS__ is used for an optional Visual C++ calling convention, for instance __fastcall or __vectorcall. This is necessary because calling convention changes a function's signature.
#define FUNCTION_TRAITS_WITH_CONVENTION( _N, ... ) \
template < typename _RESULTTYPE TEMPLATE_ARGS_POST( _N ) > \
struct FunctionTraits< _RESULTTYPE (__VA_ARGS__ *)( ARGLIST( _N ) ) > \
{ \
typedef _RESULTTYPE ResultType; \
typedef _RESULTTYPE (__VA_ARGS__ *Signature)( ARGLIST( _N ) ); \
static const bool IsClassMethod = false; \
static const int NumArgs = _N; \
static const bool HasReturnValue = !G4::is_same< _RESULTTYPE, void >::value; \
typedef typename ArgListTraits< NumArgs >::template Traits< _RESULTTYPE ARGLIST_POST( _N ) >::ArgTypes ArgList; \
typedef typename ArgListTraits< NumArgs >::template Traits< void ARGLIST_POST( _N ) >::RandomValueGenerators RandomValueGenerators; \
}; \
template < typename _RESULTTYPE, typename _CLASS TEMPLATE_ARGS_POST( _N ) > \
struct FunctionTraits< _RESULTTYPE (__VA_ARGS__ _CLASS::*)( ARGLIST( _N ) ) > : public FunctionTraits< _RESULTTYPE (__VA_ARGS__ *)( _CLASS& ARGLIST_POST( _N ) ) > \
{ \
typedef _RESULTTYPE (__VA_ARGS__ _CLASS::*Signature)( ARGLIST( _N ) ); \
static const bool IsClassMethod = true; \
}; \
template < typename _RESULTTYPE, typename _CLASS TEMPLATE_ARGS_POST( _N ) > \
struct FunctionTraits< _RESULTTYPE (__VA_ARGS__ _CLASS::*)( ARGLIST( _N ) ) const > : public FunctionTraits< _RESULTTYPE (__VA_ARGS__ _CLASS::*)( ARGLIST( _N ) ) > \
{ \
typedef _RESULTTYPE (__VA_ARGS__ _CLASS::*Signature)( ARGLIST( _N ) ) const; \
};
#if ( G4_PLATFORM == G4_PLATFORM_DURANGO )
// Xbox One version of Visual C++ supports the __vectorcall calling convention
#define FUNCTION_TRAITS_WITH_VECTORCALL( _N ) FUNCTION_TRAITS_WITH_CONVENTION( _N, __vectorcall )
#else
#define FUNCTION_TRAITS_WITH_VECTORCALL( _N )
#endif
#define FUNCTION_TRAITS( _N ) \
FUNCTION_TRAITS_WITH_CONVENTION( _N ) \
FUNCTION_TRAITS_WITH_VECTORCALL( _N )
FUNCTION_TRAITS( 0 )
FUNCTION_TRAITS( 1 )
FUNCTION_TRAITS( 2 )
FUNCTION_TRAITS( 3 )
FUNCTION_TRAITS( 4 )
FUNCTION_TRAITS( 5 )
FUNCTION_TRAITS( 6 )
FUNCTION_TRAITS( 7 )
FUNCTION_TRAITS( 8 )
FUNCTION_TRAITS( 9 )
} // namespace G4
#endif // _GEAR_TESTING__PERFTEST_TRAITS_H_