// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /***************************************************************************** * Copyright (C) 2010-2013 by Andreas Lauser * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTBILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *****************************************************************************/ /*! * \file * \brief Provides the magic behind the OPM property system. * * Properties allow to associate arbitrary data types to * identifiers. A property is always defined on a pair (\c TypeTag, * \c PropertyTag) where \c TypeTag is the identifier for the object the * property is defined for and \c PropertyTag is an unique identifier of * the property. * * Type tags are hierarchic and inherit properties defined on their * ancesters. At each level, properties defined on lower levels can be * overwritten or even made undefined. * * Properties may use other properties for the respective type tag and * these properties can also be defined on an arbitrary level of the * hierarchy. The only restriction on this is that cycles are not * allowed when defining properties. */ #ifndef OPM_PROPERTIES_HH #define OPM_PROPERTIES_HH #include #include #include #include // required for 'is_base_of' #include #include #include #include #include #include #include #include //! \cond SKIP_THIS namespace Opm { namespace Properties { #define OPM_GET_HEAD_(Arg1, ...) Arg1 #if !defined NO_PROPERTY_INTROSPECTION //! Internal macro which is only required if the property introspection is enabled #define PROP_INFO_(EffTypeTagName, PropKind, PropTagName, ...) \ template <> \ struct PropertyInfo \ { \ static int init() { \ propertyName = #PropTagName; \ PropertyRegistryKey key( \ /*effTypeTagName=*/ Opm::className(), \ /*kind=*/PropKind, \ /*name=*/#PropTagName, \ /*value=*/#__VA_ARGS__, \ /*file=*/__FILE__, \ /*line=*/__LINE__); \ PropertyRegistry::addKey(key); \ return 0; \ } \ static std::string propertyName; \ static int foo; \ }; \ std::string PropertyInfo::propertyName; \ int PropertyInfo::foo = \ PropertyInfo::init(); //! Internal macro which is only required if the property introspection is enabled #define TTAG_INFO_(...) \ template <> \ struct TypeTagInfo \ { \ static int init() { \ TypeTagRegistry::addChildren<__VA_ARGS__>(); \ return 0; \ } \ static int foo; \ }; \ int TypeTagInfo::foo = \ TypeTagInfo::init(); //! Internal macro which is only required if the property introspection is enabled #define SPLICE_INFO_(...) \ template <> \ struct SpliceInfo \ { \ static int init() { \ TypeTagRegistry::addSplices<__VA_ARGS__>(); \ return 0; \ } \ static int foo; \ }; \ int SpliceInfo::foo = \ SpliceInfo::init(); #else //! Don't do anything if introspection is disabled #define PROP_INFO_(EffTypeTagName, PropKind, PropTagName, ...) #define TTAG_INFO_(EffTypeTagName, ...) #define SPLICE_INFO_(EffTypeTagName, ...) #endif // some macros for simplification //! \endcond /*! * \ingroup PropertySystem * \brief Convert a type tag name to a type * * The main advantage of the type of a \c TypeTag is that it can be * passed as a template argument. */ #define TTAG(TypeTagName) Opm::Properties::TTag::TypeTagName /*! * \ingroup PropertySystem * \brief Makes a type out of a property tag name * * Again property type names can be passed as template argument. This * is rarely needed, though. */ #define PTAG(PropTagName) Opm::Properties::PTag::PropTagName /*! * \ingroup PropertySystem * \brief Define a new type tag. * * A type tag can inherit the properties defined on up to five parent * type tags. Examples: * * \code * // The type tag doesn't inherit any properties from other type tags * NEW_TYPE_TAG(FooTypeTag); * * // BarTypeTag inherits all properties from FooTypeTag * NEW_TYPE_TAG(BarTypeTag, INHERITS_FROM(FooTypeTag)); * * // FooBarTypeTag inherits the properties of FooTypeTag as well as * // those of BarTypeTag. Properties defined on BarTypeTag have * // preceedence over those defined for FooTypeTag: * NEW_TYPE_TAG(FooBarTypeTag, INHERITS_FROM(FooTypeTag, BarTypeTag)); * \endcode */ #define NEW_TYPE_TAG(...) \ namespace TTag { \ struct OPM_GET_HEAD_(__VA_ARGS__, blubb) \ : public TypeTag<__VA_ARGS__> \ { }; \ TTAG_INFO_(__VA_ARGS__, void) \ } \ extern int semicolonHack_ /*! * \ingroup PropertySystem * \brief Define splices for a given type tag. * * Splices can be seen as children which can be overridden lower in * the hierarchy. It can thus be seen as a "deferred inheritance" * mechanism. Example: * * \code * // First, define type tags for two different linear solvers: * // BiCGStab and SuperLU. The first needs the "MaxIterations" * // property, the second defines the "UsePivoting" property. * NEW_TYPE_TAG(BiCGStabSolver); * NEW_PROP_TAG(MaxIterations); * SET_INT_PROP(BiCGStabSolver, MaxIterations, 100); * * NEW_TYPE_TAG(SuperLUSolver); * NEW_PROP_TAG(UsePivoting); * SET_BOOL_PROP(SuperLUSolver, UsePivoting, true); * * // The model type tag defines the splice 'LinearSolver' and sets it * // to the 'BiCGStabSolver' type tag. * NEW_TYPE_TAG(ModelTypeTag); * NEW_PROP_TAG(LinearSolver); * SET_SPLICES(ModelTypeTag, LinearSolver); * SET_TAG_PROP(ModelTypeTag, LinearSolver, BiCGStabSolver); * * // The problem type tag is derived from the model type tag, but uses * // the SuperLU solver. Since this is done using a splice, all properties * // defined for the "SuperLUSolver" are inherited and the ones for the * // BiCGStabSolver type tag are undefined * NEW_TYPE_TAG(ProblemTypeTag, INHERITS_FROM(ModelTypeTag)); * SET_TAG_PROP(ProblemTypeTag, LinearSolver, SuperLUSolver); * \endcode */ #define SET_SPLICES(TypeTagName, ...) \ namespace PTag { \ template<> \ struct Splices \ { \ typedef RevertedTuple<__VA_ARGS__>::type tuple; \ }; \ SPLICE_INFO_(TTAG(TypeTagName), __VA_ARGS__) \ } \ extern int semicolonHack_ /*! * \ingroup PropertySystem * \brief Syntactic sugar for NEW_TYPE_TAG. * * See the documentation for NEW_TYPE_TAG. */ #define INHERITS_FROM(...) __VA_ARGS__ /*! * \ingroup PropertySystem * \brief Define a property tag. * * A property tag is the unique identifier for a property. It may only * be declared once in your program. There is also no hierarchy of * property tags as for type tags. * * Examples: * * \code * NEW_PROP_TAG(blubbPropTag); * NEW_PROP_TAG(blabbPropTag); * \endcode */ #define NEW_PROP_TAG(PTagName) \ namespace PTag { \ struct PTagName; } extern int semicolonHack_ //! \cond SKIP_THIS #define SET_PROP_(EffTypeTagName, PropKind, PropTagName, ...) \ template \ struct Property; \ PROP_INFO_(EffTypeTagName, \ /*kind=*/PropKind, \ PropTagName, \ /*value=*/__VA_ARGS__) \ template \ struct Property //! \endcond /*! * \ingroup PropertySystem * \brief Set a property for a specific type tag. * * After this macro, you must to specify a complete body of a class * template, including the trailing semicolon. If you need to retrieve * another property within the class body, you can use \c TypeTag as the * argument for the type tag for the \c GET_PROP macro. * * Example: * * \code * SET_PROP(FooTypeTag, blubbPropTag) * { * static int value = 10; * static int calculate(int arg) * { calculateInternal_(arg); } * * private: * // retrieve the blabbProp property for the TypeTag the * // property is defined on. Note that blabbProb does not need to * // be defined on FooTypeTag, but can also be defined for some * // derived type tag. * typedef typename GET_PROP(TypeTag, blabbProp) blabb; * * static int calculateInternal_(int arg) * { return arg * blabb::value; }; * \endcode * }; */ #define SET_PROP(EffTypeTagName, PropTagName) \ template \ struct Property; \ PROP_INFO_(EffTypeTagName, \ /*kind=*/"opaque", \ PropTagName, \ /*value=*/"") \ template \ struct Property /*! * \ingroup PropertySystem * \brief Explicitly unset a property for a type tag. * * This means that the property will not be inherited from the type * tag's parents. * * Example: * * \code * // make the blabbPropTag property undefined for the BarTypeTag. * UNSET_PROP(BarTypeTag, blabbPropTag); * \endcode */ #define UNSET_PROP(EffTypeTagName, PropTagName) \ template <> \ struct PropertyUnset; \ PROP_INFO_(EffTypeTagName, \ /*kind=*/"withdraw", \ PropTagName, \ /*value=*/) \ template <> \ struct PropertyUnset \ : public PropertyExplicitlyUnset \ {} /*! * \ingroup PropertySystem * \brief Set a property to a simple constant integer value. * * The constant can be accessed by the \c value attribute. */ #define SET_INT_PROP(EffTypeTagName, PropTagName, /*Value*/...) \ SET_PROP_(EffTypeTagName, \ /*kind=*/"int ", \ PropTagName, \ /*value=*/__VA_ARGS__) \ { \ typedef int type; \ static const int value = __VA_ARGS__; \ } /*! * \ingroup PropertySystem * \brief Set a property to a simple constant boolean value. * * The constant can be accessed by the \c value attribute. */ #define SET_BOOL_PROP(EffTypeTagName, PropTagName, /*Value*/...) \ SET_PROP_(EffTypeTagName, \ /*kind=*/"bool ", \ PropTagName, \ /*value=*/__VA_ARGS__) \ { \ typedef bool type; \ static const bool value = __VA_ARGS__; \ } /*! * \ingroup PropertySystem * \brief Set a property which defines a type. * * The type can be accessed by the \c type attribute. */ #define SET_TYPE_PROP(EffTypeTagName, PropTagName, /*Value*/...) \ SET_PROP_(EffTypeTagName, \ /*kind=*/"type ", \ PropTagName, \ /*value=*/__VA_ARGS__) \ { \ typedef __VA_ARGS__ type; \ } /*! * \ingroup PropertySystem * \brief Set a property to a simple constant scalar value. * * The constant can be accessed by the \c value attribute. In order to * use this macro, the property tag \c Scalar needs to be defined for * the type tag. */ #define SET_SCALAR_PROP(EffTypeTagName, PropTagName, ...) \ SET_PROP_(EffTypeTagName, \ /*kind=*/"scalar", \ PropTagName, \ /*value=*/__VA_ARGS__) \ { \ typedef typename GET_PROP_TYPE(TypeTag, Scalar) Scalar; \ public: \ typedef Scalar type; \ static const Scalar value; \ }; \ template \ const typename Property::type \ Property::value(__VA_ARGS__) /*! * \ingroup PropertySystem * \brief Set a property to a simple constant string value. * * The constant can be accessed by the \c value attribute and is of * type std::string. */ #define SET_STRING_PROP(EffTypeTagName, PropTagName, ...) \ SET_PROP_(EffTypeTagName, \ /*kind=*/"string", \ PropTagName, \ /*value=*/__VA_ARGS__) \ { \ public: \ typedef std::string type; \ static const std::string value; \ }; \ template \ const typename Property::type \ Property::value(__VA_ARGS__) /*! * \ingroup PropertySystem * \brief Define a property containing a type tag. * * This is convenient for splices. */ #define SET_TAG_PROP(EffTypeTagName, PropTagName, ValueTypeTagName) \ SET_PROP_(EffTypeTagName, \ /*kind=*/"tag ", \ PropTagName, \ /*value=*/TTAG(ValueTypeTagName)) \ { \ typedef TTAG(ValueTypeTagName) type; \ } /*! * \ingroup PropertySystem * \brief Retrieve a property for a type tag. * * If you use \c GET_PROP within a template and want to refer to some * type (including the property itself), \c GET_PROP must be preceeded by * the '\c typename' keyword. */ #define GET_PROP(TypeTag, PropTagName) \ ::Opm::Properties::GetProperty::p //!\cond SKIP_THIS #define GET_PROP_(TypeTag, PropTag) \ ::Opm::Properties::GetProperty::p //!\endcond /*! * \ingroup PropertySystem * \brief Access the \c value attribute of a property for a type tag. * * This is just for convenience and equivalent to * GET_PROP(TypeTag, PropTag)::value . If the property doesn't * have an attribute named \c value, this yields a compiler error. */ #define GET_PROP_VALUE(TypeTag, PropTagName) \ ::Opm::Properties::GetProperty::p::value //!\cond SKIP_THIS #define GET_PROP_VALUE_(TypeTag, PropTag) \ ::Opm::Properties::GetProperty::p::value //!\endcond /*! * \ingroup PropertySystem * \brief Access the \c type attribute of a property for a type tag. * * This is just for convenience and equivalent to * GET_PROP(TypeTag, PropTag)::type. If the property doesn't * have an attribute named \c type, this yields a compiler error. Also, * if you use this macro within a template, it must be preceeded by * the \c typename keyword. */ #define GET_PROP_TYPE(TypeTag, PropTagName) \ ::Opm::Properties::GetProperty::p::type //!\cond SKIP_THIS #define GET_PROP_TYPE_(TypeTag, PropTag) \ ::Opm::Properties::GetProperty::p::type //!\endcond #if !defined NO_PROPERTY_INTROSPECTION /*! * \ingroup PropertySystem * \brief Return a human readable diagnostic message how exactly a * property was defined. * * This is only enabled if the \c NO_PROPERTY_INTROSPECTION macro is not * defined. * * Example: * * \code * int main() * { * std::cout << PROP_DIAGNOSTIC(FooBarTypeTag, blabbPropTag) << "\n"; * }; * \endcode */ #define PROP_DIAGNOSTIC(TypeTag, PropTagName) \ ::Opm::Properties::getDiagnostic(#PropTagName) #else #define PROP_DIAGNOSTIC(TypeTag, PropTagName) "Property introspection disabled by macro NO_PROPERTY_INTROSPECTION." #endif ////////////////////////////////////////////// // some serious template kung fu. Don't look at it too closely, it // might damage your brain! ////////////////////////////////////////////// //! \cond SKIP_THIS namespace PTag {} namespace TTag {} #if !defined NO_PROPERTY_INTROSPECTION namespace TTag { template struct TypeTagInfo {}; } namespace PTag { template struct SpliceInfo {}; } template struct PropertyInfo {}; class PropertyRegistryKey { public: PropertyRegistryKey() {} PropertyRegistryKey(const std::string &effTypeTagName, const std::string &propertyKind, const std::string &propertyName, const std::string &propertyValue, const std::string &fileDefined, int lineDefined) : effTypeTagName_(effTypeTagName) , propertyKind_(propertyKind) , propertyName_(propertyName) , propertyValue_(propertyValue) , fileDefined_(fileDefined) , lineDefined_(lineDefined) { } // copy constructor PropertyRegistryKey(const PropertyRegistryKey &v) : effTypeTagName_(v.effTypeTagName_) , propertyKind_(v.propertyKind_) , propertyName_(v.propertyName_) , propertyValue_(v.propertyValue_) , fileDefined_(v.fileDefined_) , lineDefined_(v.lineDefined_) {} const std::string &effTypeTagName() const { return effTypeTagName_; } const std::string &propertyKind() const { return propertyKind_; } const std::string &propertyName() const { return propertyName_; } const std::string &propertyValue() const { return propertyValue_; } const std::string &fileDefined() const { return fileDefined_; } int lineDefined() const { return lineDefined_; } private: std::string effTypeTagName_; std::string propertyKind_; std::string propertyName_; std::string propertyValue_; std::string fileDefined_; int lineDefined_; }; template struct GetProperty; class TypeTagRegistry { public: struct SpliceRegistryEntryBase { virtual ~SpliceRegistryEntryBase() {}; virtual std::string propertyName() const = 0; }; template struct SpliceRegistryEntry : public SpliceRegistryEntryBase { virtual std::string propertyName() const { return PropertyInfo::template GetEffectiveTypeTag_::type, PropTag>::propertyName; } }; typedef std::list SpliceList; typedef std::map SpliceListMap; typedef std::list ChildrenList; typedef std::map ChildrenListMap; // end of recursion. the last argument is not a child, but 'void' // which is required for the macro magic... template static void addChildren() {} // the last argument is not a child, but 'void' which is required // for the macro magic... template static void addChildren() { std::string typeTagName = Opm::className(); children_[typeTagName].push_front(Opm::className()); addChildren(); } // end of recursion. the last argument is not a child, but 'void' // which is required for the macro magic... template static void addSplices() { } // the last argument is not a child, but 'void' which is required // for the macro magic... template static void addSplices() { std::string typeTagName = Opm::className(); SpliceRegistryEntry *tmp = new SpliceRegistryEntry; splices_[typeTagName].push_front(tmp); addSplices(); } static const SpliceList &splices(const std::string &typeTagName) { return splices_[typeTagName]; } static const ChildrenList &children(const std::string &typeTagName) { return children_[typeTagName]; } private: static SpliceListMap splices_; static ChildrenListMap children_; }; TypeTagRegistry::SpliceListMap TypeTagRegistry::splices_; TypeTagRegistry::ChildrenListMap TypeTagRegistry::children_; class PropertyRegistry { public: typedef std::map KeyList; typedef std::map KeyListMap; static void addKey(const PropertyRegistryKey &key) { keys_[key.effTypeTagName()][key.propertyName()] = key; } static const std::string &getSpliceTypeTagName(const std::string &typeTagName, const std::string &propertyName) { const auto &keyIt = keys_.find(typeTagName); const auto &keyEndIt = keys_.end(); if (keyIt == keyEndIt) OPM_THROW(std::runtime_error, "Unknown type tag key '" << typeTagName << "'"); // check whether the propery is defined for the type tag // currently checked const auto &propIt = keyIt->second.find(propertyName); const auto &propEndIt = keyIt->second.end(); if (propIt != propEndIt) return propIt->second.propertyValue(); // if not, check all children typedef TypeTagRegistry::ChildrenList ChildrenList; const ChildrenList &children = TypeTagRegistry::children(typeTagName); ChildrenList::const_iterator ttagIt = children.begin(); for (; ttagIt != children.end(); ++ttagIt) { const auto &tmp = getSpliceTypeTagName(*ttagIt, propertyName); if (tmp != "") return tmp; } // if the property was not defined on a given type tag, return // the empty string. static std::string tmp(""); return tmp; } static const PropertyRegistryKey &getKey(const std::string &effTypeTagName, const std::string &propertyName) { return keys_[effTypeTagName][propertyName]; } static const KeyList &getKeys(const std::string &effTypeTagName) { return keys_[effTypeTagName]; } private: static KeyListMap keys_; }; PropertyRegistry::KeyListMap PropertyRegistry::keys_; #endif // !defined NO_PROPERTY_INTROSPECTION struct PropertyUndefined { }; class PropertyExplicitlyUnset {}; template struct Property : public PropertyUndefined {}; template struct PropertyUnset : public PropertyUndefined {}; template struct propertyExplicitlyUnset { const static bool value = std::is_base_of >::value; }; template class propertyExplicitlyUnsetOnTree { static const bool explicitlyUnset = propertyExplicitlyUnset::value; template struct unsetOnAllChildren { static const bool value = true; }; template struct unsetOnAllChildren > { static const bool value = propertyExplicitlyUnsetOnTree::value && unsetOnAllChildren >::value; }; public: static const bool value = (explicitlyUnset || (!Tree::isLeaf && unsetOnAllChildren::value)); }; template struct propertyExplicitlyUnsetOnTree { const static bool value = std::true_type::value; }; template struct propertyDefinedOnSelf { const static bool value = ! std::is_base_of >::value; }; // template class to revert the order or a std::tuple's // arguments. This is required to make the properties of children // defined on the right overwrite the properties of the previous // children. See https://sydius.me/2011/07/reverse-tuple-in-c/ template class RevertedTuple { private: template struct RevertedTupleOuter { template struct RevertedTupleInner: RevertedTupleOuter::template RevertedTupleInner { }; }; template struct RevertedTupleOuter<0, All...> { template struct RevertedTupleInner { typedef std::tuple type; }; }; public: typedef typename RevertedTupleOuter::template RevertedTupleInner::type type; }; template class TypeTag { public: typedef SelfT SelfType; typedef typename RevertedTuple::type ChildrenTuple; static const bool isLeaf = std::is_same >::value; }; namespace PTag { // this class needs to be located in the PTag namespace for reasons // you don't really want to know... template struct Splices { typedef typename std::tuple<> tuple; }; } // namespace PTag template struct GetProperty { template ::value> struct GetEffectiveTypeTag_; template struct SearchTypeTagList_; template struct SearchTypeTagList_FirstThenRemaining_; template struct SearchSpliceList_; template struct SearchSpliceList_FirstThenRemaining_; // find the first type tag in a tuple for which the property is // defined template struct SearchTypeTagTuple_ { typedef void type; }; template struct SearchTypeTagTuple_ > { typedef typename SearchTypeTagList_::type type; }; template struct SearchTypeTagList_ { typedef void type; }; template struct SearchTypeTagList_ { typedef typename SearchTypeTagList_FirstThenRemaining_< typename GetEffectiveTypeTag_::type, RemainingElements...>::type type; }; template struct SearchTypeTagList_FirstThenRemaining_ { typedef EffectiveTypeTag type; }; template struct SearchTypeTagList_FirstThenRemaining_ { typedef typename SearchTypeTagList_::type type; }; // find the first type tag in a tuple of splices for which the // property is defined template struct SearchSpliceTuple_ { typedef void type; }; template struct SearchSpliceTuple_ > { typedef typename SearchSpliceList_::type type; }; template struct SearchSpliceList_ { typedef void type; }; template struct SearchSpliceList_ { typedef typename SearchSpliceList_FirstThenRemaining_< typename GetEffectiveTypeTag_::p::type>::type, RemainingSplices...>::type type; }; template struct SearchSpliceList_FirstThenRemaining_ { typedef EffectiveTypeTag type; }; template struct SearchSpliceList_FirstThenRemaining_ { typedef typename SearchSpliceList_::type type; }; // find the splice or the child type tag for which the property is defined template ::tuple >::type > struct SearchSplicesThenChildren_ { typedef SpliceTypeTag type; }; template struct SearchSplicesThenChildren_ { typedef typename SearchTypeTagTuple_::type type; }; // find the type tag for which the property is defined template struct GetEffectiveTypeTag_ { typedef typename CurTree::SelfType type; }; template struct GetEffectiveTypeTag_ { typedef typename SearchSplicesThenChildren_::type type; }; public: typedef Property::type, PropertyTag> p; }; #if !defined NO_PROPERTY_INTROSPECTION int myReplaceAll_(std::string &s, const std::string &pattern, const std::string &replacement) { size_t pos; int i = 0; while ( (pos = s.find(pattern)) != s.npos) { s.replace(pos, pattern.size(), replacement); ++i; }; return i; } std::string canonicalTypeTagNameToName_(const std::string &canonicalName) { std::string result(canonicalName); myReplaceAll_(result, "Opm::Properties::TTag::", "TTAG("); myReplaceAll_(result, "::", ""); result += ")"; return result; } inline bool getDiagnostic_(const std::string &typeTagName, const std::string &propTagName, std::string &result, const std::string indent) { const PropertyRegistryKey *key = 0; const PropertyRegistry::KeyList &keys = PropertyRegistry::getKeys(typeTagName); PropertyRegistry::KeyList::const_iterator it = keys.begin(); for (; it != keys.end(); ++it) { if (it->second.propertyName() == propTagName) { key = &it->second; break; }; } if (key) { std::ostringstream oss; oss << indent << key->propertyKind() << " " << key->propertyName() << " defined on '" << canonicalTypeTagNameToName_(key->effTypeTagName()) << "' at " << key->fileDefined() << ":" << key->lineDefined() << "\n"; result = oss.str(); return true; } // print properties defined on children typedef TypeTagRegistry::ChildrenList ChildrenList; const ChildrenList &children = TypeTagRegistry::children(typeTagName); ChildrenList::const_iterator ttagIt = children.begin(); std::string newIndent = indent + " "; for (; ttagIt != children.end(); ++ttagIt) { if (getDiagnostic_(*ttagIt, propTagName, result, newIndent)) { result.insert(0, indent + "Inherited from " + canonicalTypeTagNameToName_(typeTagName) + "\n"); return true; } } return false; } template const std::string getDiagnostic(std::string propTagName) { std::string result; std::string TypeTagName(Opm::className()); propTagName.replace(0, strlen("PTag("), ""); int n = propTagName.length(); propTagName.replace(n - 1, 1, ""); //TypeTagName.replace(0, strlen("Opm::Properties::TTag::"), ""); return result; } inline void print_(const std::string &rootTypeTagName, const std::string &curTypeTagName, const std::string &splicePropName, std::ostream &os, const std::string indent, std::set &printedProperties) { if (indent == "") { os << indent << "###########\n"; os << indent << "# Properties\n"; os << indent << "###########\n"; os << indent << "Properties for " << canonicalTypeTagNameToName_(curTypeTagName) << ":"; } else if (splicePropName != "") os << indent << "Inherited from splice " << splicePropName << " (set to " << canonicalTypeTagNameToName_(curTypeTagName) << "):"; else os << indent << "Inherited from " << canonicalTypeTagNameToName_(curTypeTagName) << ":"; const PropertyRegistry::KeyList &keys = PropertyRegistry::getKeys(curTypeTagName); PropertyRegistry::KeyList::const_iterator it = keys.begin(); bool somethingPrinted = false; for (; it != keys.end(); ++it) { const PropertyRegistryKey &key = it->second; if (printedProperties.count(key.propertyName()) > 0) continue; // property already printed if (!somethingPrinted) { os << "\n"; somethingPrinted = true; } os << indent << " " << key.propertyKind() << " " << key.propertyName(); if (key.propertyKind() != "opaque") { std::string s(key.propertyValue()); myReplaceAll_(s, "typename ", ""); if (myReplaceAll_(s, "::Opm::Properties::TTag::", "TTAG(")) s += ')'; myReplaceAll_(s, "::Opm::Properties::PTag::", ""); myReplaceAll_(s, "::Opm::Properties::GetProperty<", "GET_PROP("); myReplaceAll_(s, ">::p::", ")::"); myReplaceAll_(s, "GET_PROP(TypeTag, Scalar)::type", "Scalar"); os << " = '" << s << "'"; } os << " defined at " << key.fileDefined() << ":" << key.lineDefined() << "\n"; printedProperties.insert(key.propertyName()); }; if (!somethingPrinted) os << " (none)\n"; // print properties defined on splices or children std::string newIndent = indent + " "; // first, iterate over the splices, ... typedef TypeTagRegistry::SpliceList SpliceList; const SpliceList &splices = TypeTagRegistry::splices(curTypeTagName); SpliceList::const_iterator spliceIt = splices.begin(); for (; spliceIt != splices.end(); ++ spliceIt) { const auto &spliceTypeTagName = PropertyRegistry::getSpliceTypeTagName(rootTypeTagName, (*spliceIt)->propertyName()); print_(rootTypeTagName, spliceTypeTagName, (*spliceIt)->propertyName(), os, newIndent, printedProperties); } // ... then, over the children typedef TypeTagRegistry::ChildrenList ChildrenList; const ChildrenList &children = TypeTagRegistry::children(curTypeTagName); ChildrenList::const_iterator ttagIt = children.begin(); for (; ttagIt != children.end(); ++ttagIt) { print_(rootTypeTagName, *ttagIt, /*splicePropName=*/"", os, newIndent, printedProperties); } } template void printValues(std::ostream &os = std::cout) { std::set printedProps; print_(Opm::className(), Opm::className(), /*splicePropertyName=*/"", os, /*indent=*/"", printedProps); } #else // !defined NO_PROPERTY_INTROSPECTION template void printValues(std::ostream &os = std::cout) { std::cout << "The eWoms property system was compiled with the macro\n" "NO_PROPERTY_INTROSPECTION defined.\n" "No diagnostic messages this time, sorry.\n"; } template const std::string getDiagnostic(std::string propTagName) { std::string result; result = "The eWoms property system was compiled with the macro\n" "NO_PROPERTY_INTROSPECTION defined.\n" "No diagnostic messages this time, sorry.\n"; return result; } #endif // !defined NO_PROPERTY_INTROSPECTION //! \endcond } // namespace Properties } // namespace Opm #endif