HELLO·Android
系统源代码
IT资讯
技术文章
我的收藏
注册
登录
-
我收藏的文章
创建代码块
我的代码块
我的账号
Oreo
|
8.0.0_r4
下载
查看原文件
收藏
根目录
external
deqp
modules
glshared
glsBuiltinPrecisionTests.cpp
/*------------------------------------------------------------------------- * drawElements Quality Program OpenGL (ES) Module * ----------------------------------------------- * * Copyright 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *//*! * \file * \brief Precision and range tests for GLSL builtins and types. * *//*--------------------------------------------------------------------*/ #include "glsBuiltinPrecisionTests.hpp" #include "deMath.h" #include "deMemory.h" #include "deDefs.hpp" #include "deRandom.hpp" #include "deSTLUtil.hpp" #include "deStringUtil.hpp" #include "deUniquePtr.hpp" #include "deSharedPtr.hpp" #include "deArrayUtil.hpp" #include "tcuCommandLine.hpp" #include "tcuFloatFormat.hpp" #include "tcuInterval.hpp" #include "tcuTestCase.hpp" #include "tcuTestLog.hpp" #include "tcuVector.hpp" #include "tcuMatrix.hpp" #include "tcuResultCollector.hpp" #include "gluContextInfo.hpp" #include "gluVarType.hpp" #include "gluRenderContext.hpp" #include "glwDefs.hpp" #include "glsShaderExecUtil.hpp" #include
#include
#include
#include
#include
#include
// Uncomment this to get evaluation trace dumps to std::cerr // #define GLS_ENABLE_TRACE // set this to true to dump even passing results #define GLS_LOG_ALL_RESULTS false enum { // Computing reference intervals can take a non-trivial amount of time, especially on // platforms where toggling floating-point rounding mode is slow (emulated arm on x86). // As a workaround watchdog is kept happy by touching it periodically during reference // interval computation. TOUCH_WATCHDOG_VALUE_FREQUENCY = 4096 }; namespace deqp { namespace gls { namespace BuiltinPrecisionTests { using std::string; using std::map; using std::ostream; using std::ostringstream; using std::pair; using std::vector; using std::set; using de::MovePtr; using de::Random; using de::SharedPtr; using de::UniquePtr; using tcu::Interval; using tcu::FloatFormat; using tcu::MessageBuilder; using tcu::TestCase; using tcu::TestLog; using tcu::Vector; using tcu::Matrix; namespace matrix = tcu::matrix; using glu::Precision; using glu::RenderContext; using glu::VarType; using glu::DataType; using glu::ShaderType; using glu::ContextInfo; using gls::ShaderExecUtil::Symbol; typedef TestCase::IterateResult IterateResult; using namespace glw; using namespace tcu; /*--------------------------------------------------------------------*//*! * \brief Generic singleton creator. * * instance
() returns a reference to a unique default-constructed instance * of T. This is mainly used for our GLSL function implementations: each * function is implemented by an object, and each of the objects has a * distinct class. It would be extremely toilsome to maintain a separate * context object that contained individual instances of the function classes, * so we have to resort to global singleton instances. * *//*--------------------------------------------------------------------*/ template
const T& instance (void) { static const T s_instance = T(); return s_instance; } /*--------------------------------------------------------------------*//*! * \brief Dummy placeholder type for unused template parameters. * * In the precision tests we are dealing with functions of different arities. * To minimize code duplication, we only define templates with the maximum * number of arguments, currently four. If a function's arity is less than the * maximum, Void us used as the type for unused arguments. * * Although Voids are not used at run-time, they still must be compilable, so * they must support all operations that other types do. * *//*--------------------------------------------------------------------*/ struct Void { typedef Void Element; enum { SIZE = 0, }; template
explicit Void (const T&) {} Void (void) {} operator double (void) const { return TCU_NAN; } // These are used to make Voids usable as containers in container-generic code. Void& operator[] (int) { return *this; } const Void& operator[] (int) const { return *this; } }; ostream& operator<< (ostream& os, Void) { return os << "()"; } //! Returns true for all other types except Void template
bool isTypeValid (void) { return true; } template <> bool isTypeValid
(void) { return false; } //! Utility function for getting the name of a data type. //! This is used in vector and matrix constructors. template
const char* dataTypeNameOf (void) { return glu::getDataTypeName(glu::dataTypeOf
()); } template <> const char* dataTypeNameOf
(void) { DE_FATAL("Impossible"); return DE_NULL; } //! A hack to get Void support for VarType. template
VarType getVarTypeOf (Precision prec = glu::PRECISION_LAST) { return glu::varTypeOf
(prec); } template <> VarType getVarTypeOf
(Precision) { DE_FATAL("Impossible"); return VarType(); } /*--------------------------------------------------------------------*//*! * \brief Type traits for generalized interval types. * * We are trying to compute sets of acceptable values not only for * float-valued expressions but also for compound values: vectors and * matrices. We approximate a set of vectors as a vector of intervals and * likewise for matrices. * * We now need generalized operations for each type and its interval * approximation. These are given in the type Traits
. * * The type Traits
::IVal is the approximation of T: it is `Interval` for * scalar types, and a vector or matrix of intervals for container types. * * To allow template inference to take place, there are function wrappers for * the actual operations in Traits
. Hence we can just use: * * makeIVal(someFloat) * * instead of: * * Traits
::doMakeIVal(value) * *//*--------------------------------------------------------------------*/ template
struct Traits; //! Create container from elementwise singleton values. template
typename Traits
::IVal makeIVal (const T& value) { return Traits
::doMakeIVal(value); } //! Elementwise union of intervals. template
typename Traits
::IVal unionIVal (const typename Traits
::IVal& a, const typename Traits
::IVal& b) { return Traits
::doUnion(a, b); } //! Returns true iff every element of `ival` contains the corresponding element of `value`. template
bool contains (const typename Traits
::IVal& ival, const T& value) { return Traits
::doContains(ival, value); } //! Print out an interval with the precision of `fmt`. template
void printIVal (const FloatFormat& fmt, const typename Traits
::IVal& ival, ostream& os) { Traits
::doPrintIVal(fmt, ival, os); } template
string intervalToString (const FloatFormat& fmt, const typename Traits
::IVal& ival) { ostringstream oss; printIVal
(fmt, ival, oss); return oss.str(); } //! Print out a value with the precision of `fmt`. template
void printValue (const FloatFormat& fmt, const T& value, ostream& os) { Traits
::doPrintValue(fmt, value, os); } template
string valueToString (const FloatFormat& fmt, const T& val) { ostringstream oss; printValue(fmt, val, oss); return oss.str(); } //! Approximate `value` elementwise to the float precision defined in `fmt`. //! The resulting interval might not be a singleton if rounding in both //! directions is allowed. template
typename Traits
::IVal round (const FloatFormat& fmt, const T& value) { return Traits
::doRound(fmt, value); } template
typename Traits
::IVal convert (const FloatFormat& fmt, const typename Traits
::IVal& value) { return Traits
::doConvert(fmt, value); } //! Common traits for scalar types. template
struct ScalarTraits { typedef Interval IVal; static Interval doMakeIVal (const T& value) { // Thankfully all scalar types have a well-defined conversion to `double`, // hence Interval can represent their ranges without problems. return Interval(double(value)); } static Interval doUnion (const Interval& a, const Interval& b) { return a | b; } static bool doContains (const Interval& a, T value) { return a.contains(double(value)); } static Interval doConvert (const FloatFormat& fmt, const IVal& ival) { return fmt.convert(ival); } static Interval doRound (const FloatFormat& fmt, T value) { return fmt.roundOut(double(value), false); } }; template<> struct Traits
: ScalarTraits
{ static void doPrintIVal (const FloatFormat& fmt, const Interval& ival, ostream& os) { os << fmt.intervalToHex(ival); } static void doPrintValue (const FloatFormat& fmt, const float& value, ostream& os) { os << fmt.floatToHex(value); } }; template<> struct Traits
: ScalarTraits
{ static void doPrintValue (const FloatFormat&, const float& value, ostream& os) { os << (value != 0.0f ? "true" : "false"); } static void doPrintIVal (const FloatFormat&, const Interval& ival, ostream& os) { os << "{"; if (ival.contains(false)) os << "false"; if (ival.contains(false) && ival.contains(true)) os << ", "; if (ival.contains(true)) os << "true"; os << "}"; } }; template<> struct Traits
: ScalarTraits
{ static void doPrintValue (const FloatFormat&, const int& value, ostream& os) { os << value; } static void doPrintIVal (const FloatFormat&, const Interval& ival, ostream& os) { os << "[" << int(ival.lo()) << ", " << int(ival.hi()) << "]"; } }; //! Common traits for containers, i.e. vectors and matrices. //! T is the container type itself, I is the same type with interval elements. template
struct ContainerTraits { typedef typename T::Element Element; typedef I IVal; static IVal doMakeIVal (const T& value) { IVal ret; for (int ndx = 0; ndx < T::SIZE; ++ndx) ret[ndx] = makeIVal(value[ndx]); return ret; } static IVal doUnion (const IVal& a, const IVal& b) { IVal ret; for (int ndx = 0; ndx < T::SIZE; ++ndx) ret[ndx] = unionIVal
(a[ndx], b[ndx]); return ret; } static bool doContains (const IVal& ival, const T& value) { for (int ndx = 0; ndx < T::SIZE; ++ndx) if (!contains(ival[ndx], value[ndx])) return false; return true; } static void doPrintIVal (const FloatFormat& fmt, const IVal ival, ostream& os) { os << "("; for (int ndx = 0; ndx < T::SIZE; ++ndx) { if (ndx > 0) os << ", "; printIVal
(fmt, ival[ndx], os); } os << ")"; } static void doPrintValue (const FloatFormat& fmt, const T& value, ostream& os) { os << dataTypeNameOf
() << "("; for (int ndx = 0; ndx < T::SIZE; ++ndx) { if (ndx > 0) os << ", "; printValue
(fmt, value[ndx], os); } os << ")"; } static IVal doConvert (const FloatFormat& fmt, const IVal& value) { IVal ret; for (int ndx = 0; ndx < T::SIZE; ++ndx) ret[ndx] = convert
(fmt, value[ndx]); return ret; } static IVal doRound (const FloatFormat& fmt, T value) { IVal ret; for (int ndx = 0; ndx < T::SIZE; ++ndx) ret[ndx] = round(fmt, value[ndx]); return ret; } }; template
struct Traits
> : ContainerTraits
, Vector
::IVal, Size> > { }; template
struct Traits
> : ContainerTraits
, Matrix
::IVal, Rows, Cols> > { }; //! Void traits. These are just dummies, but technically valid: a Void is a //! unit type with a single possible value. template<> struct Traits
{ typedef Void IVal; static Void doMakeIVal (const Void& value) { return value; } static Void doUnion (const Void&, const Void&) { return Void(); } static bool doContains (const Void&, Void) { return true; } static Void doRound (const FloatFormat&, const Void& value) { return value; } static Void doConvert (const FloatFormat&, const Void& value) { return value; } static void doPrintValue (const FloatFormat&, const Void&, ostream& os) { os << "()"; } static void doPrintIVal (const FloatFormat&, const Void&, ostream& os) { os << "()"; } }; //! This is needed for container-generic operations. //! We want a scalar type T to be its own "one-element vector". template
struct ContainerOf { typedef Vector
Container; }; template
struct ContainerOf
{ typedef T Container; }; template
struct ContainerOf
{ typedef Void Container; }; // This is a kludge that is only needed to get the ExprP::operator[] syntactic sugar to work. template
struct ElementOf { typedef typename T::Element Element; }; template <> struct ElementOf
{ typedef void Element; }; template <> struct ElementOf
{ typedef void Element; }; template <> struct ElementOf
{ typedef void Element; }; /*--------------------------------------------------------------------*//*! * * \name Abstract syntax for expressions and statements. * * We represent GLSL programs as syntax objects: an Expr
represents an * expression whose GLSL type corresponds to the C++ type T, and a Statement * represents a statement. * * To ease memory management, we use shared pointers to refer to expressions * and statements. ExprP
is a shared pointer to an Expr
, and StatementP * is a shared pointer to a Statement. * * \{ * *//*--------------------------------------------------------------------*/ class ExprBase; class ExpandContext; class Statement; class StatementP; class FuncBase; template
class ExprP; template
class Variable; template
class VariableP; template
class DefaultSampling; typedef set
FuncSet; template
VariableP
variable (const string& name); StatementP compoundStatement (const vector
& statements); /*--------------------------------------------------------------------*//*! * \brief A variable environment. * * An Environment object maintains the mapping between variables of the * abstract syntax tree and their values. * * \todo [2014-03-28 lauri] At least run-time type safety. * *//*--------------------------------------------------------------------*/ class Environment { public: template
void bind (const Variable
& variable, const typename Traits
::IVal& value) { deUint8* const data = new deUint8[sizeof(value)]; deMemcpy(data, &value, sizeof(value)); de::insert(m_map, variable.getName(), SharedPtr
(data, de::ArrayDeleter
())); } template
typename Traits
::IVal& lookup (const Variable
& variable) const { deUint8* const data = de::lookup(m_map, variable.getName()).get(); return *reinterpret_cast
::IVal*>(data); } private: map
> m_map; }; /*--------------------------------------------------------------------*//*! * \brief Evaluation context. * * The evaluation context contains everything that separates one execution of * an expression from the next. Currently this means the desired floating * point precision and the current variable environment. * *//*--------------------------------------------------------------------*/ struct EvalContext { EvalContext (const FloatFormat& format_, Precision floatPrecision_, Environment& env_, int callDepth_ = 0) : format (format_) , floatPrecision (floatPrecision_) , env (env_) , callDepth (callDepth_) {} FloatFormat format; Precision floatPrecision; Environment& env; int callDepth; }; /*--------------------------------------------------------------------*//*! * \brief Simple incremental counter. * * This is used to make sure that different ExpandContexts will not produce * overlapping temporary names. * *//*--------------------------------------------------------------------*/ class Counter { public: Counter (int count = 0) : m_count(count) {} int operator() (void) { return m_count++; } private: int m_count; }; class ExpandContext { public: ExpandContext (Counter& symCounter) : m_symCounter(symCounter) {} ExpandContext (const ExpandContext& parent) : m_symCounter(parent.m_symCounter) {} template
VariableP
genSym (const string& baseName) { return variable
(baseName + de::toString(m_symCounter())); } void addStatement (const StatementP& stmt) { m_statements.push_back(stmt); } vector
getStatements (void) const { return m_statements; } private: Counter& m_symCounter; vector
m_statements; }; /*--------------------------------------------------------------------*//*! * \brief A statement or declaration. * * Statements have no values. Instead, they are executed for their side * effects only: the execute() method should modify at least one variable in * the environment. * * As a bit of a kludge, a Statement object can also represent a declaration: * when it is evaluated, it can add a variable binding to the environment * instead of modifying a current one. * *//*--------------------------------------------------------------------*/ class Statement { public: virtual ~Statement (void) { } //! Execute the statement, modifying the environment of `ctx` void execute (EvalContext& ctx) const { this->doExecute(ctx); } void print (ostream& os) const { this->doPrint(os); } //! Add the functions used in this statement to `dst`. void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); } protected: virtual void doPrint (ostream& os) const = 0; virtual void doExecute (EvalContext& ctx) const = 0; virtual void doGetUsedFuncs (FuncSet& dst) const = 0; }; ostream& operator<<(ostream& os, const Statement& stmt) { stmt.print(os); return os; } /*--------------------------------------------------------------------*//*! * \brief Smart pointer for statements (and declarations) * *//*--------------------------------------------------------------------*/ class StatementP : public SharedPtr
{ public: typedef SharedPtr
Super; StatementP (void) {} explicit StatementP (const Statement* ptr) : Super(ptr) {} StatementP (const Super& ptr) : Super(ptr) {} }; /*--------------------------------------------------------------------*//*! * \brief * * A statement that modifies a variable or a declaration that binds a variable. * *//*--------------------------------------------------------------------*/ template
class VariableStatement : public Statement { public: VariableStatement (const VariableP
& variable, const ExprP
& value, bool isDeclaration) : m_variable (variable) , m_value (value) , m_isDeclaration (isDeclaration) {} protected: void doPrint (ostream& os) const { if (m_isDeclaration) os << glu::declare(getVarTypeOf
(), m_variable->getName()); else os << m_variable->getName(); os << " = " << *m_value << ";\n"; } void doExecute (EvalContext& ctx) const { if (m_isDeclaration) ctx.env.bind(*m_variable, m_value->evaluate(ctx)); else ctx.env.lookup(*m_variable) = m_value->evaluate(ctx); } void doGetUsedFuncs (FuncSet& dst) const { m_value->getUsedFuncs(dst); } VariableP
m_variable; ExprP
m_value; bool m_isDeclaration; }; template
StatementP variableStatement (const VariableP
& variable, const ExprP
& value, bool isDeclaration) { return StatementP(new VariableStatement
(variable, value, isDeclaration)); } template
StatementP variableDeclaration (const VariableP
& variable, const ExprP
& definiens) { return variableStatement(variable, definiens, true); } template
StatementP variableAssignment (const VariableP
& variable, const ExprP
& value) { return variableStatement(variable, value, false); } /*--------------------------------------------------------------------*//*! * \brief A compound statement, i.e. a block. * * A compound statement is executed by executing its constituent statements in * sequence. * *//*--------------------------------------------------------------------*/ class CompoundStatement : public Statement { public: CompoundStatement (const vector
& statements) : m_statements (statements) {} protected: void doPrint (ostream& os) const { os << "{\n"; for (size_t ndx = 0; ndx < m_statements.size(); ++ndx) os << *m_statements[ndx]; os << "}\n"; } void doExecute (EvalContext& ctx) const { for (size_t ndx = 0; ndx < m_statements.size(); ++ndx) m_statements[ndx]->execute(ctx); } void doGetUsedFuncs (FuncSet& dst) const { for (size_t ndx = 0; ndx < m_statements.size(); ++ndx) m_statements[ndx]->getUsedFuncs(dst); } vector
m_statements; }; StatementP compoundStatement(const vector
& statements) { return StatementP(new CompoundStatement(statements)); } //! Common base class for all expressions regardless of their type. class ExprBase { public: virtual ~ExprBase (void) {} void printExpr (ostream& os) const { this->doPrintExpr(os); } //! Output the functions that this expression refers to void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); } protected: virtual void doPrintExpr (ostream&) const {} virtual void doGetUsedFuncs (FuncSet&) const {} }; //! Type-specific operations for an expression representing type T. template
class Expr : public ExprBase { public: typedef T Val; typedef typename Traits
::IVal IVal; IVal evaluate (const EvalContext& ctx) const; protected: virtual IVal doEvaluate (const EvalContext& ctx) const = 0; }; //! Evaluate an expression with the given context, optionally tracing the calls to stderr. template
typename Traits
::IVal Expr
::evaluate (const EvalContext& ctx) const { #ifdef GLS_ENABLE_TRACE static const FloatFormat highpFmt (-126, 127, 23, true, tcu::MAYBE, tcu::YES, tcu::MAYBE); EvalContext newCtx (ctx.format, ctx.floatPrecision, ctx.env, ctx.callDepth + 1); const IVal ret = this->doEvaluate(newCtx); if (isTypeValid
()) { std::cerr << string(ctx.callDepth, ' '); this->printExpr(std::cerr); std::cerr << " -> " << intervalToString
(highpFmt, ret) << std::endl; } return ret; #else return this->doEvaluate(ctx); #endif } template
class ExprPBase : public SharedPtr
> { public: }; ostream& operator<< (ostream& os, const ExprBase& expr) { expr.printExpr(os); return os; } /*--------------------------------------------------------------------*//*! * \brief Shared pointer to an expression of a container type. * * Container types (i.e. vectors and matrices) support the subscription * operator. This class provides a bit of syntactic sugar to allow us to use * the C++ subscription operator to create a subscription expression. *//*--------------------------------------------------------------------*/ template
class ContainerExprPBase : public ExprPBase
{ public: ExprP
operator[] (int i) const; }; template
class ExprP : public ExprPBase
{}; // We treat Voids as containers since the dummy parameters in generalized // vector functions are represented as Voids. template <> class ExprP
: public ContainerExprPBase
{}; template
class ExprP
> : public ContainerExprPBase
> {}; template
class ExprP
> : public ContainerExprPBase
> {}; template
ExprP
exprP (void) { return ExprP
(); } template
ExprP
exprP (const SharedPtr
>& ptr) { ExprP
ret; static_cast
>&>(ret) = ptr; return ret; } template
ExprP
exprP (const Expr
* ptr) { return exprP(SharedPtr
>(ptr)); } /*--------------------------------------------------------------------*//*! * \brief A shared pointer to a variable expression. * * This is just a narrowing of ExprP for the operations that require a variable * instead of an arbitrary expression. * *//*--------------------------------------------------------------------*/ template
class VariableP : public SharedPtr
> { public: typedef SharedPtr
> Super; explicit VariableP (const Variable
* ptr) : Super(ptr) {} VariableP (void) {} VariableP (const Super& ptr) : Super(ptr) {} operator ExprP
(void) const { return exprP(SharedPtr
>(*this)); } }; /*--------------------------------------------------------------------*//*! * \name Syntactic sugar operators for expressions. * * @{ * * These operators allow the use of C++ syntax to construct GLSL expressions * containing operators: e.g. "a+b" creates an addition expression with * operands a and b, and so on. * *//*--------------------------------------------------------------------*/ ExprP
operator-(const ExprP
& arg0); ExprP
operator+(const ExprP
& arg0, const ExprP
& arg1); ExprP
operator-(const ExprP
& arg0, const ExprP
& arg1); ExprP
operator*(const ExprP
& arg0, const ExprP
& arg1); ExprP
operator/(const ExprP
& arg0, const ExprP
& arg1); template
ExprP
> operator-(const ExprP
>& arg0); template
ExprP
> operator*(const ExprP
>& arg0, const ExprP
& arg1); template
ExprP
> operator*(const ExprP
>& arg0, const ExprP
>& arg1); template
ExprP
> operator-(const ExprP
>& arg0, const ExprP
>& arg1); template
ExprP
> operator* (const ExprP
>& left, const ExprP
>& right); template
ExprP
> operator* (const ExprP
>& left, const ExprP
>& right); template
ExprP
> operator* (const ExprP
>& left, const ExprP
>& right); template
ExprP
> operator* (const ExprP
>& left, const ExprP
& right); template
ExprP
> operator+ (const ExprP
>& left, const ExprP
>& right); template
ExprP
> operator- (const ExprP
>& mat); //! @} /*--------------------------------------------------------------------*//*! * \brief Variable expression. * * A variable is evaluated by looking up its range of possible values from an * environment. *//*--------------------------------------------------------------------*/ template
class Variable : public Expr
{ public: typedef typename Expr
::IVal IVal; Variable (const string& name) : m_name (name) {} string getName (void) const { return m_name; } protected: void doPrintExpr (ostream& os) const { os << m_name; } IVal doEvaluate (const EvalContext& ctx) const { return ctx.env.lookup
(*this); } private: string m_name; }; template
VariableP
variable (const string& name) { return VariableP
(new Variable
(name)); } template
VariableP
bindExpression (const string& name, ExpandContext& ctx, const ExprP
& expr) { VariableP
var = ctx.genSym
(name); ctx.addStatement(variableDeclaration(var, expr)); return var; } /*--------------------------------------------------------------------*//*! * \brief Constant expression. * * A constant is evaluated by rounding it to a set of possible values allowed * by the current floating point precision. *//*--------------------------------------------------------------------*/ template
class Constant : public Expr
{ public: typedef typename Expr
::IVal IVal; Constant (const T& value) : m_value(value) {} protected: void doPrintExpr (ostream& os) const { os << m_value; } IVal doEvaluate (const EvalContext&) const { return makeIVal(m_value); } private: T m_value; }; template
ExprP
constant (const T& value) { return exprP(new Constant
(value)); } //! Return a reference to a singleton void constant. const ExprP
& voidP (void) { static const ExprP
singleton = constant(Void()); return singleton; } /*--------------------------------------------------------------------*//*! * \brief Four-element tuple. * * This is used for various things where we need one thing for each possible * function parameter. Currently the maximum supported number of parameters is * four. *//*--------------------------------------------------------------------*/ template
struct Tuple4 { explicit Tuple4 (const T0 e0 = T0(), const T1 e1 = T1(), const T2 e2 = T2(), const T3 e3 = T3()) : a (e0) , b (e1) , c (e2) , d (e3) { } T0 a; T1 b; T2 c; T3 d; }; /*--------------------------------------------------------------------*//*! * \brief Function signature. * * This is a purely compile-time structure used to bundle all types in a * function signature together. This makes passing the signature around in * templates easier, since we only need to take and pass a single Sig instead * of a bunch of parameter types and a return type. * *//*--------------------------------------------------------------------*/ template
struct Signature { typedef R Ret; typedef P0 Arg0; typedef P1 Arg1; typedef P2 Arg2; typedef P3 Arg3; typedef typename Traits
::IVal IRet; typedef typename Traits
::IVal IArg0; typedef typename Traits
::IVal IArg1; typedef typename Traits
::IVal IArg2; typedef typename Traits
::IVal IArg3; typedef Tuple4< const Arg0&, const Arg1&, const Arg2&, const Arg3&> Args; typedef Tuple4< const IArg0&, const IArg1&, const IArg2&, const IArg3&> IArgs; typedef Tuple4< ExprP
, ExprP
, ExprP
, ExprP
> ArgExprs; }; typedef vector
BaseArgExprs; /*--------------------------------------------------------------------*//*! * \brief Type-independent operations for function objects. * *//*--------------------------------------------------------------------*/ class FuncBase { public: virtual ~FuncBase (void) {} virtual string getName (void) const = 0; //! Name of extension that this function requires, or empty. virtual string getRequiredExtension (void) const { return ""; } virtual void print (ostream&, const BaseArgExprs&) const = 0; //! Index of output parameter, or -1 if none of the parameters is output. virtual int getOutParamIndex (void) const { return -1; } void printDefinition (ostream& os) const { doPrintDefinition(os); } void getUsedFuncs (FuncSet& dst) const { this->doGetUsedFuncs(dst); } protected: virtual void doPrintDefinition (ostream& os) const = 0; virtual void doGetUsedFuncs (FuncSet& dst) const = 0; }; typedef Tuple4