Bolt  1.3
C++ template library with support for OpenCL
Classes | Macros | Functions
ClCode: Traits and Helper Macros

Classes

struct  TypeName< TypeNameType >
 
struct  ClCode< Type >
 The definition of a type trait for the definition of a type, which could be arbitrarily complex. More...
 

Macros

#define STRINGIFY_CODE2(...)   #__VA_ARGS__
 Macro that wraps around arbitrary text, and creates a string out of it This macro is helpful to write inline OpenCL programs, as it avoids wrapping every line of OpenCL line with "XXX"
.
 
#define STRINGIFY_CODE(...)   STRINGIFY_CODE2( __VA_ARGS__ )
 
#define BOLT_CODE_STRING(...)   STRINGIFY_CODE( __VA_ARGS__ ); __VA_ARGS__;
 
#define BOLT_HOST_DEVICE_DEFINITION(...)   "namespace bolt { namespace cl {\n" STRINGIFY_CODE( __VA_ARGS__ ) "\n } } \n" ; __VA_ARGS__;
 
#define BOLT_CREATE_TYPENAME(...)   template<> struct TypeName< __VA_ARGS__ > { static std::string get( ) { return #__VA_ARGS__; } };
 
#define BOLT_CREATE_CLCODE(Type, CODE_STRING)
 
#define BOLT_TEMPLATE_REGISTER_NEW_TYPE(CONTAINER, OLDTYPE, NEWTYPE)
 This macro specializes a template with a new type using the template definition of a previously defined type This is a convenience macro to specialize a template for a new type, using the generic template definition from a previosly defined type.
 
#define BOLT_TEMPLATE_REGISTER_NEW_ITERATOR(CONTAINER, OLDTYPE, NEWTYPE)
 This macro specializes a template iterator with a new type using the template definition of a previously defined iterator type This is a convenience macro to specialize an iterator for a new type, using the generic template definition from a previosly defined iterator.
 
#define BOLT_CREATE_DEFINE(DefineName, D,...)
 This macro defines a macro on the kernel code.
 
#define BOLT_TEMPLATE_REGISTER_NEW_TRANSFORM_ITERATOR(FUNCTOR, DATATYPE)
 This macro creates a TypeName and the ClCode data structure for the transform iterator associated with FUNCTOR and DATA_TYPE. The use of this macro is necessary if transform iterator is used in the algorithm This macro creates a TypeName and the ClCode data structure for the transform iterator associated with FUNCTOR and DATA_TYPE. The use of this macro is necessary if transform iterator is used in the algorithm.
 
#define BOLT_TEMPLATE_REGISTER_NEW_PERMUTATION_ITERATOR(ELEMENT_ITERATOR, INDEX_ITERATOR)
 A Permutation iterator is associated with an ELEMENT_ITERATOR and INDEX_ITERATOR. This Macro creates a ClCode and TypeName for the permutation iterator. A Permutation iterator is associated with an ELEMENT_ITERATOR and INDEX_ITERATOR. This Macro creates a ClCode and TypeName for the permutation iterator. Note that the data type associated with the element and index iterators must be declared within the BOLT_FUNCTOR macro. Only device vector iterators can be used with permutation iterators. Both the iterators has to be either std iterators or device vector iterators. Combination of the two is not supported.
 
#define BOLT_FUNCTOR(T,...)
 
#define BOLT_TEMPLATE_FUNCTOR1(CONTAINER, TYPE1,...)
 
#define BOLT_TEMPLATE_FUNCTOR2(CONTAINER, TYPE1, TYPE2,...)
 
#define BOLT_TEMPLATE_FUNCTOR3(CONTAINER, TYPE1, TYPE2, TYPE3,...)
 
#define BOLT_TEMPLATE_FUNCTOR4(CONTAINER, TYPE1, TYPE2, TYPE3, TYPE4,...)
 
#define BOLT_CREATE_CODE_SNIPPET(Name,...)
 
#define BOLT_ADD_DEPENDENCY(Type, DependingType)   ClCode<Type>::addDependency(ClCode<DependingType>::get());
 

Functions

static std::string TypeName< TypeNameType >::get ()
 
static std::string ClCode< Type >::get ()
 

Detailed Description

Macro Definition Documentation

#define BOLT_ADD_DEPENDENCY (   Type,
  DependingType 
)    ClCode<Type>::addDependency(ClCode<DependingType>::get());

This macro is used to specify an A-depends-on-B type relationship between types. Bolt will ensure that whenever the definition of the A type is needed, the definition for the B type is also included

Parameters
TypeThe A type
DependingTypeThe B type

An example:

#define EPS CL_FLT_EPSILON
// Copies macro the to kernel code.
BOLT_CREATE_DEFINE( BOLT_EPSILON, EPS, CL_FLT_EPSILON );
// A simple functor to multiply by e
BOLT_FUNCTOR( MultiplyE,
struct MultiplyE
{
double operator( )( double x )
{
return x * EPS;
};
};
);
int main( )
{
BOLT_ADD_DEPENDENCY( MultiplyE, BOLT_EPSILON );
bolt::cl::transform( Ci, Ci + 10 , Dest.begin( ), MultiplyE( ) );
return 0;
}
#define BOLT_CODE_STRING (   ...)    STRINGIFY_CODE( __VA_ARGS__ ); __VA_ARGS__;

Return a string with the specified function F, and also create code that is fed to the host compiler.

#define BOLT_CREATE_CLCODE (   Type,
  CODE_STRING 
)
Value:
template<> struct ClCode< Type > { static std::vector< std::string > dependencies;\
static void addDependency(std::string s) { dependencies.push_back(s); }; \
static std::string getDependingCodeString() { \
std::string c;\
for (std::vector< std::string >::iterator i = dependencies.begin(); i != dependencies.end(); i++) { c = c + *i; } \
return c; \
};\
static std::string getCodeString() { return CODE_STRING; }; \
static std::string get() { return getDependingCodeString() + getCodeString(); }; };\
__attribute__((weak)) std::vector< std::string > ClCode< Type >::dependencies;

Creates the ClCode trait that associates the specified type T with the string CODE_STRING.

Parameters
TypeA fully specified type name
CODE_STRINGThe definition of the type, which could be a template definition

An example:

// Manually create code string inline and associate with class IsOdd:
BOLT_CREATE_CLCODE(IsOdd, "struct IsOdd { bool operator(int val) { return val & 0x1; }; };"

Another approach is to define the code string in a file (so host and string are identical), then pass the string read from the file to BOLT_CREATE_CLCODE. (See clCodeFromFile)

#define BOLT_CREATE_CODE_SNIPPET (   Name,
  ... 
)
Value:
__VA_ARGS__;\
struct Name {};\
BOLT_CREATE_CLCODE(Name, std::string("#ifndef ") + std::string(#Name) +std::string(" \n") \
+ std::string("#define ") + std::string(#Name) + std::string(" \n") \
+ std::string(#__VA_ARGS__) + std::string(" \n") \
+ std::string("#endif \n"));

Registers code used on both host and device. It is used to help define complex relationships between user defined types, such as when one type contains instances of another. BOLT_CREATE_CODE_SNIPPET defines new types and BOLT_ADD_DEPENDENCY is used to specify the relationship to Bolt how the definition of one type relies on the definition of the other.

Parameters
NameAn identifier to associate with the trailing code
...Arbitrary user defined code
#define BOLT_CREATE_DEFINE (   DefineName,
  D,
  ... 
)
Value:
struct DefineName {}; BOLT_CREATE_CLCODE( DefineName, std::string("#ifndef ") + std::string(#D) + std::string(" \n")\
+ std::string("#define ") + std::string(#D) + std::string(" ") + std::string(#__VA_ARGS__) + std::string(" \n")\
+ std::string("#endif \n"));

This macro defines a macro on the kernel code.

Parameters
DefineNameName of the macro. Can be used with other Bolt macros.
DThe macro
...Value of the macro ( Arbitrary type definition to associate with the type ) See ClCodeTraits
#define BOLT_CREATE_TYPENAME (   ...)    template<> struct TypeName< __VA_ARGS__ > { static std::string get( ) { return #__VA_ARGS__; } };

A convenience macro to create the TypeName trait for a specified class T.

Parameters
T: Class for which TypeName trait will be defined.
// Example that shows use of BOLT_CREATE_TYPENAME macro:
class MyClass { ... };
// Associate string "MyClass" with class MyClass

See TypeName for more information.

#define BOLT_FUNCTOR (   T,
  ... 
)
Value:
__VA_ARGS__; \
BOLT_CREATE_TYPENAME( T ); \
BOLT_CREATE_CLCODE( T, std::string("#ifndef ") + std::string("BOLT_FUNCTOR_") + std::string(#T) + std::string(" \n")\
+ std::string("#define ") + std::string("BOLT_FUNCTOR_") + std::string(#T) + std::string(" \n")\
+ std::string(#__VA_ARGS__) + std::string(" \n")\
+ std::string("#endif \n"));

Creates a string and a regular version of the functor F, and automatically defines the ClCode trait to associate the code string with the specified class T.

Parameters
TypeA fully specified type name
...Arbitrary type definition to associate with the type. See ClCodeTraits

An example:

// Create a new cube root functor on host and copy to kernel
BOLT_FUNCTOR( CbrtFunctor,
class CbrtFunctor
{
...
};
);
int main( )
{
...
CbrtFunctor cbrt_func;
bolt::cl::transform( Src.begin( ), Src.end( ), Dest.begin( ), cbrt_func );
}
#define BOLT_HOST_DEVICE_DEFINITION (   ...)    "namespace bolt { namespace cl {\n" STRINGIFY_CODE( __VA_ARGS__ ) "\n } } \n" ; __VA_ARGS__;

/brief Types that are defined within the bolt::cl namespace in host code should also be defined within the same namespace within the kernel code /detail This is a convenience macro, intended to only be used by the Bolt library itself, to wrap internal types in the appropriate bolt namespaces

#define BOLT_TEMPLATE_FUNCTOR1 (   CONTAINER,
  TYPE1,
  ... 
)
Value:
__VA_ARGS__; \
BOLT_CREATE_TYPENAME( CONTAINER<TYPE1> ) \
BOLT_CREATE_CLCODE( CONTAINER<TYPE1>, #__VA_ARGS__ )

Helper macro to define and specialize a template type for Bolt. The code given as the macro vararg should be a template container that requires 1 template paramter. The type passed into the TYPE1 argument is used to fully specialize the template container into a concrete type for Bolt.

Parameters
CONTAINERName to associate with the code given in the macro variable argument
TYPE1Type used to fully specialize the template code given in the macro variable argument
...Arbitrary user defined code; expected to be a 1 argument template type

An example:

// Create a new user-defined type UDD on host and copy to kernel
// In this example, BOLT_TEMPLATE_FUNCTOR1 enables integer templatization of UDD - UDD<int>
template<typename T>
struct UDD
{
....
};
);
BOLT_TEMPLATE_FUNCTOR1( UDDNegate, int,
template<typename T>
struct UDDNegate
{
UDD< T > operator( ) ( const UDD< T > &x, const UDD< T > &y ) const
{
...
}
};
);
BOLT_CREATE_TYPENAME( bolt::cl::device_vector< UDD< int > >::iterator );
bolt::cl::deviceVectorIteratorTemplate );
int main( )
{
...
bolt::cl::device_vector< UDD< int > > Src( 10, UDD< int >( ) );
UDDNegate<int> udd_negate;
bolt::cl::transform( Src.begin( ), Src.end( ), Dest.begin( ), udd_negate );
}
#define BOLT_TEMPLATE_FUNCTOR2 (   CONTAINER,
  TYPE1,
  TYPE2,
  ... 
)
Value:
__VA_ARGS__; \
BOLT_CREATE_TYPENAME( CONTAINER<TYPE1> ) \
BOLT_CREATE_CLCODE( CONTAINER<TYPE1>, #__VA_ARGS__ ) \
BOLT_TEMPLATE_REGISTER_NEW_TYPE( CONTAINER, TYPE1, TYPE2 )

Helper macro to define and specialize a template type for Bolt. The code given as the macro vararg should be a template container that requires 1 template paramter. The types passed into TYPE1 & TYPE2 are used to fully specialize the template container into concrete types for Bolt use with two different types

Parameters
CONTAINERName to associate with the code given in the macro variable argument
TYPE1Type used to fully specialize the template code given in the macro variable argument
TYPE2Second type used to fully specialize the template code, independant of 1st type
...Arbitrary user defined code; expected to be a 1 argument template type
#define BOLT_TEMPLATE_FUNCTOR3 (   CONTAINER,
  TYPE1,
  TYPE2,
  TYPE3,
  ... 
)
Value:
__VA_ARGS__; \
BOLT_CREATE_TYPENAME( CONTAINER<TYPE1> ) \
BOLT_CREATE_CLCODE( CONTAINER<TYPE1>, #__VA_ARGS__ ) \
BOLT_TEMPLATE_REGISTER_NEW_TYPE( CONTAINER, TYPE1, TYPE2 ) \
BOLT_TEMPLATE_REGISTER_NEW_TYPE( CONTAINER, TYPE1, TYPE3 )

Helper macro to define and specialize a template type for Bolt. The code given as the macro vararg should be a template container that requires 1 template paramter. The types passed into TYPE1 & TYPE2 & TYPE3 are used to fully specialize the template container into concrete types for Bolt use with two different types

Parameters
CONTAINERName to associate with the code given in the macro variable argument
TYPE1Type used to fully specialize the template code given in the macro variable argument
TYPE2Second type used to fully specialize the template code , independant of other types
TYPE3Third type used to fully specialize the template code, independant of other types
...Arbitrary user defined code; expected to be a 1 argument template type
#define BOLT_TEMPLATE_FUNCTOR4 (   CONTAINER,
  TYPE1,
  TYPE2,
  TYPE3,
  TYPE4,
  ... 
)
Value:
__VA_ARGS__; \
BOLT_CREATE_TYPENAME( CONTAINER<TYPE1> ) \
BOLT_CREATE_CLCODE( CONTAINER<TYPE1>, #__VA_ARGS__ ) \
BOLT_TEMPLATE_REGISTER_NEW_TYPE( CONTAINER, TYPE1, TYPE2 ) \
BOLT_TEMPLATE_REGISTER_NEW_TYPE( CONTAINER, TYPE1, TYPE3 ) \
BOLT_TEMPLATE_REGISTER_NEW_TYPE( CONTAINER, TYPE1, TYPE4 )

Helper macro to define and specialize a template type for Bolt. The code given as the macro vararg should be a template container that requires 1 template paramter. The types passed into TYPE1 & TYPE2 & TYPE3 & type4 are used to fully specialize the template container into concrete types for Bolt use with two different types

Parameters
CONTAINERName to associate with the code given in the macro variable argument
TYPE1Type used to fully specialize the template code given in the macro variable argument
TYPE2Second type used to fully specialize the template code , independant of other types
TYPE3Third type used to fully specialize the template code, independant of other types
TYPE4Fourth type used to fully specialize the template code, independant of other types
...Arbitrary user defined code; expected to be a 1 argument template type
#define BOLT_TEMPLATE_REGISTER_NEW_ITERATOR (   CONTAINER,
  OLDTYPE,
  NEWTYPE 
)
Value:
BOLT_CREATE_TYPENAME( CONTAINER< NEWTYPE >::iterator ) \
BOLT_CREATE_CLCODE( CONTAINER< NEWTYPE >::iterator, ClCode< CONTAINER< OLDTYPE >::iterator >::get( ) )

This macro specializes a template iterator with a new type using the template definition of a previously defined iterator type This is a convenience macro to specialize an iterator for a new type, using the generic template definition from a previosly defined iterator.

Parameters
CONTAINERA template template parameter, such as std::vector without the type specified
OLDTYPEA type that has already been registered with the container template definition
NEWTYPEA new type to register with the template definition

An example:

// Create a new user-defined type UDD on host and copy to kernel
class UDD
{
...
};
);
// Create a new negation functor for UDD
BOLT_FUNCTOR( UDDNegate,
class UDDNegate
{
...
};
);
// Create an UDD instance of device_vector
int main( )
{
...
bolt::cl::device_vector< UDD > Src( 10, UDD( ) );
UDDNegate udd_negate_functor;
bolt::cl::transform( Src.begin( ), Src.end( ), Dest.begin( ), udd_negate_functor );
}
#define BOLT_TEMPLATE_REGISTER_NEW_PERMUTATION_ITERATOR (   ELEMENT_ITERATOR,
  INDEX_ITERATOR 
)
Value:
template<> struct ClCode< bolt::cl::permutation_iterator< ELEMENT_ITERATOR, INDEX_ITERATOR > > { static std::vector< std::string > dependencies;\
static void addDependency(std::string s) { dependencies.push_back(s); }; \
static std::string getDependingCodeString() { \
std::string c;\
for (std::vector< std::string >::iterator i = dependencies.begin(); i != dependencies.end(); i++) { c = c + *i; } \
return c; \
};\
static std::string getCodeString() { return ClCode<ELEMENT_ITERATOR>::get() + ClCode<INDEX_ITERATOR>::get() + bolt::cl::devicePermutationIteratorTemplate; }; \
static std::string get() { return getDependingCodeString() + getCodeString(); }; };\
__attribute__((weak)) std::vector< std::string > ClCode< bolt::cl::permutation_iterator< ELEMENT_ITERATOR, INDEX_ITERATOR > >::dependencies;

A Permutation iterator is associated with an ELEMENT_ITERATOR and INDEX_ITERATOR. This Macro creates a ClCode and TypeName for the permutation iterator. A Permutation iterator is associated with an ELEMENT_ITERATOR and INDEX_ITERATOR. This Macro creates a ClCode and TypeName for the permutation iterator. Note that the data type associated with the element and index iterators must be declared within the BOLT_FUNCTOR macro. Only device vector iterators can be used with permutation iterators. Both the iterators has to be either std iterators or device vector iterators. Combination of the two is not supported.

Parameters
ELEMENT_ITERATORThis specifies the iterator for elements
INDEX_ITERATORThis specifies the iterator for the index elements

An example:

#include <bolt/cl/iterator/premutation_iterator.h>
#include <bolt/cl/transform.h
// Create a new user-defined type UDD on host and copy to kernel
BOLT_FUNCTOR( UDD,
struct UDD
{
int i;
float f;
...
};
);
// Create a new permutation iterator with both index and element iterators as device_vector iterators for int data type.
BOLT_TEMPLATE_REGISTER_NEW_PERMUTATION_ITERATOR( bolt::cl::device_vector<int>::iterator, bolt::cl::device_vector<int>::iterator);
// Create a new permutation iterator with both index and element iterators as device_vector iterators for UDD data type.
// Create a new transform iterator with square as a functor and UDD as a data type.
int main( )
{
...
{
const int length = 1<<10;
std::vector< int > svIndexVec( length );
std::vector< int > svElementVec( length );
std::vector< int > svOutVec( length );
bolt::BCKND::device_vector< int > dvIndexVec( length );
bolt::BCKND::device_vector< int > dvElementVec( length );
bolt::BCKND::device_vector< int > dvOutVec( length );
typedef std::vector< int >::const_iterator sv_itr;
typedef bolt::BCKND::device_vector< int >::iterator dv_itr;
typedef bolt::BCKND::permutation_iterator< sv_itr,
sv_itr> sv_perm_itr;
typedef bolt::BCKND::permutation_iterator< dv_itr,
dv_itr> dv_perm_itr;
//Create Iterators
dv_perm_itr dv_perm_begin (dvElementVec.begin(), dvIndexVec.begin()), dv_perm_end (dvElementVec.end(), dvIndexVec.end());
// Generate the inputs for the input vectors svIndexVec, svElementVec, dvIndexVec, dvElementVec.
// Call the transform routine with permutation iterators
bolt::cl::transform(dv_perm_begin, dv_perm_end, dvOutVec.begin(), add3);
}
}
#define BOLT_TEMPLATE_REGISTER_NEW_TRANSFORM_ITERATOR (   FUNCTOR,
  DATATYPE 
)
Value:
template<> struct ClCode< bolt::cl::transform_iterator< FUNCTOR, bolt::cl::device_vector< DATATYPE >::iterator > > { static std::vector< std::string > dependencies;\
static void addDependency(std::string s) { dependencies.push_back(s); }; \
static std::string getDependingCodeString() { \
std::string c;\
for (std::vector< std::string >::iterator i = dependencies.begin(); i != dependencies.end(); i++) { c = c + *i; } \
return c; \
};\
static std::string getCodeString() { return ClCode<DATATYPE>::get() + ClCode<FUNCTOR>::get() + bolt::cl::deviceTransformIteratorTemplate; }; \
static std::string get() { return getDependingCodeString() + getCodeString(); }; };\
__attribute__((weak)) std::vector< std::string > ClCode< bolt::cl::transform_iterator< FUNCTOR, bolt::cl::device_vector< DATATYPE >::iterator > >::dependencies;

This macro creates a TypeName and the ClCode data structure for the transform iterator associated with FUNCTOR and DATA_TYPE. The use of this macro is necessary if transform iterator is used in the algorithm This macro creates a TypeName and the ClCode data structure for the transform iterator associated with FUNCTOR and DATA_TYPE. The use of this macro is necessary if transform iterator is used in the algorithm.

Parameters
FUNCTORThis defines the unary function for the transform iterator. FUNCTOR should be previously defined using BOLT_FUNCTOR. The FUNCTOR is used to transform the objects of type DATA_TYPE. The FUNCTOR should also define an associated type result_type.
DATATYPEThis is the type of the data which the transform iterator points to and the unary function FUNCTOR operates on.

An example:

#include <bolt/cl/iterator/transform_iterator.h>
#include <bolt/cl/transform.h
// Create a new user-defined type UDD on host and copy to kernel
BOLT_FUNCTOR( UDD,
struct UDD
{
int i;
float f;
...
};
);
// Create a new square functor takes int and return int
BOLT_FUNCTOR(square,
struct square
{
int operator() (const int x) const { return x + 2; }
typedef int result_type;
};
);
// Create a new negation functor for UDD
BOLT_FUNCTOR( UDDNegate,
class UDDNegate
{
...
};
);
// Create a new transform iterator with square as a functor and UDD as a data type.
BOLT_TEMPLATE_REGISTER_NEW_TRANSFORM_ITERATOR( square, int);
// Create a new transform iterator with square as a functor and UDD as a data type.
BOLT_FUNCTOR(squareUDD,
struct squareUDD
{
UDD operator() (const UDD& x) const
{
UDD tmp;
tmp.i = x.i * x.i;
tmp.f = x.f * x.f;
return tmp;
}
typedef UDD result_type;
};
);
BOLT_TEMPLATE_REGISTER_NEW_TRANSFORM_ITERATOR( square, UDD);
int main( )
{
...
{
typedef bolt::BCKND::transform_iterator< square, bolt::BCKND::device_vector< int >::iterator> dv_trf_itr;
typedef bolt::BCKND::transform_iterator< square, std::vector< int >::const_iterator> sv_trf_itr;
std::vector< int > svInVec( length );
bolt::cl::device_vector< int > dvInVec( length );
std::vector< int > svOutVec( length );
bolt::cl::device_vector< int > dvOutVec( length );
// Initialize svInVec and dvInVec ...
//Declare the required functors
UDDNegate udd_negate_functor;
bolt::cl::negate<int>() neg;
sv_trf_itr sv_trf_begin (svInVec.begin(), sq), sv_trf_end (svInVec.end(), sq);
dv_trf_itr dv_trf_begin (dvInVec.begin(), sq), dv_trf_end (dvInVec.end(), sq);
bolt::cl::transform( sv_trf_begin, sv_trf_end, svOutVec.begin(), neg );
bolt::cl::transform( dv_trf_begin, dv_trf_end, dvOutVec.begin(), neg );
}
{
typedef bolt::BCKND::transform_iterator< squareUDD, bolt::BCKND::device_vector< UDD >::iterator> dv_udd_trf_itr;
typedef bolt::BCKND::transform_iterator< squareUDD, std::vector< UDD >::const_iterator> sv_udd_trf_itr;
std::vector< UDD > svInVec( length );
bolt::cl::device_vector< UDD > dvInVec( length );
std::vector< UDD > svOutVec( length );
bolt::cl::device_vector< UDD > dvOutVec( length );
// Initialize svInVec and dvInVec ...
//Declare the required functors
UDDNegate udd_negate_functor;
squareUDD sq_udd;
sv_udd_trf_itr sv_trf_begin (svInVec.begin(), sq_udd), sv_trf_end (svInVec.end(), sq_udd);
dv_udd_trf_itr dv_trf_begin (dvInVec.begin(), sq_udd), dv_trf_end (dvInVec.end(), sq_udd);
bolt::cl::transform( sv_trf_begin, sv_trf_end, svOutVec.begin(), udd_negate_functor );
bolt::cl::transform( dv_trf_begin, dv_trf_end, dvOutVec.begin(), udd_negate_functor );
}
}
#define BOLT_TEMPLATE_REGISTER_NEW_TYPE (   CONTAINER,
  OLDTYPE,
  NEWTYPE 
)
Value:
BOLT_CREATE_TYPENAME( CONTAINER< NEWTYPE > ) \
BOLT_CREATE_CLCODE( CONTAINER< NEWTYPE >, ClCode< CONTAINER< OLDTYPE > >::get( ) )

This macro specializes a template with a new type using the template definition of a previously defined type This is a convenience macro to specialize a template for a new type, using the generic template definition from a previosly defined type.

Parameters
CONTAINERA template template parameter, such as std::vector without the type specified
OLDTYPEA type that has already been registered with the container template definition
NEWTYPEA new type to register with the template definition

An example:

// Create a new user-defined type UDD on host and copy to kernel
class UDD
{
...
};
);
// Create an instance of bolt::cl::negate of type UDD
BOLT_TEMPLATE_REGISTER_NEW_TYPE( bolt::cl::negate, int, UDD );
int main( )
{
...
bolt::cl::device_vector< UDD > Src( 10, UDD( ) );
bolt::cl::transform( Src.begin( ), Src.end( ), Dest.begin( ), bolt::cl::negate< UDD >( ) );
}
#define STRINGIFY_CODE2 (   ...)    #__VA_ARGS__

Macro that wraps around arbitrary text, and creates a string out of it This macro is helpful to write inline OpenCL programs, as it avoids wrapping every line of OpenCL line with "XXX"
.

Returns
The contents of the macro wrapped in an ASCII string