From d5770b92eaef55e67626e4f9e1594e166fc3bb48 Mon Sep 17 00:00:00 2001 From: Andreas Lauser Date: Thu, 22 Aug 2013 16:23:14 +0200 Subject: [PATCH] Import the property system from eWoms --- opm/core/utility/PropertySystem.hpp | 1199 +++++++++++++++++++++++++++ 1 file changed, 1199 insertions(+) create mode 100644 opm/core/utility/PropertySystem.hpp diff --git a/opm/core/utility/PropertySystem.hpp b/opm/core/utility/PropertySystem.hpp new file mode 100644 index 00000000..8da8ddab --- /dev/null +++ b/opm/core/utility/PropertySystem.hpp @@ -0,0 +1,1199 @@ +// -*- 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 constexpr 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 constexpr 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 constexpr bool explicitlyUnset = propertyExplicitlyUnset::value; + + template + struct unsetOnAllChildren + { static constexpr bool value = true; }; + + template + struct unsetOnAllChildren > + { static constexpr bool value = + propertyExplicitlyUnsetOnTree::value + && unsetOnAllChildren >::value; }; + +public: + static constexpr 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. this is not a very nice solution, but it works... +template +struct RevertedTuple; + +template <> +struct RevertedTuple<> +{ typedef std::tuple<> type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +struct RevertedTuple +{ typedef std::tuple type; }; + +template +class TypeTag +{ +public: + typedef SelfT SelfType; + + typedef typename RevertedTuple::type ChildrenTuple; + static constexpr 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 + +// retrieve a property which is not defined on a splice +template +struct GetDirectProperty_ +{ + // set the ::type attribute to the type tag for which the + // requested property was defined. First check whether the + // property is directly defined for the type tag, and if not, + // check all splices, then check all children + template ::value > + struct GetEffectiveTypeTag_; + + // set the ::type attribute to the child type tag for which the + // requested property was defined. The first child is ignored. + template + struct TraverseRemainingChildren_; + + // if the first argument != void this is the value of the ::type member, ... + template + struct StopAtFirstChildElseTraverseRemaining_ + { typedef EffTypeTag type; }; + + // ... or else the type tag is defined by the remaining children + template + struct StopAtFirstChildElseTraverseRemaining_ + { typedef typename TraverseRemainingChildren_ >::type type; }; + + // set the ::type attribute to the type tag to the child for which + // the requested property was defined, or ... + template + struct TraverseRemainingChildren_ > + { typedef typename StopAtFirstChildElseTraverseRemaining_::type, RemainingChildren...>::type type; }; + + // ... if there there are no children which we did not check + // anymore, the ::type attribute is void (i.e. the property was + // not defined for a given subtree) + template + struct TraverseRemainingChildren_ > + { typedef void type; }; + + template + struct GetEffectiveTypeTag_ + { typedef CurTree type; }; + + template + struct GetEffectiveTypeTag_ + { typedef typename TraverseRemainingChildren_::type type; }; + +public: + typedef Property::type, PropertyTag> p; +}; + +template +struct GetProperty +{ + // set the ::type attribute to the type tag for which the + // requested property was defined. First check whether the + // property is directly defined for the type tag, and if not, + // check all splices, then check all children + template ::value > + struct GetEffectiveTypeTag_; + + // set the ::type attribute to the child type tag for which the + // requested property was defined. The first child is ignored. + template + struct TraverseRemainingChildren_; + + // set the ::type attribute to the type tag for which the + // requested property was defined. First check all splices of the + // type tag, then check all children. The first splice is ignored. + template + struct TraverseRemainingSplicesAndChildren_; + + // if the first argument != void this is the value of the ::type member, ... + template + struct StopAtFirstChildElseTraverseRemaining_ + { typedef EffTypeTag type; }; + + // ... or else the type tag is defined by the remaining children + template + struct StopAtFirstChildElseTraverseRemaining_ + { typedef typename TraverseRemainingChildren_ >::type type; }; + + // set the ::type attribute to the type tag to the child for which + // the requested property was defined, or ... + template + struct TraverseRemainingChildren_ > + { typedef typename StopAtFirstChildElseTraverseRemaining_::type, RemainingChildren...>::type type; }; + + // ... if there there are no children which we did not check + // anymore, the ::type attribute is void (i.e. the property was + // not defined for a given subtree) + template + struct TraverseRemainingChildren_ > + { typedef void type; }; + + template + struct StopAtSpliceIfPropDefinedElseTraverseRemaining_ + { typedef EffTypeTag type; }; + + template + struct StopAtSpliceIfPropDefinedElseTraverseRemaining_ + { typedef typename TraverseRemainingSplicesAndChildren_ >::type type; }; + + // if the property was defined for the current splice, stop + // here. If not... + template + struct StopAtFirstSpliceElseTraverseRemaining_ + { typedef typename StopAtSpliceIfPropDefinedElseTraverseRemaining_::type, + RemainingSplices...>::type type; }; + + // ... check the remaining splices. + template + struct StopAtFirstSpliceElseTraverseRemaining_ + { typedef typename TraverseRemainingSplicesAndChildren_ >::type type; }; + + // check whether the property is defined on the remaining splices + // of a list (i.e. discard its first member) ... + template + struct TraverseRemainingSplicesAndChildren_ > + { typedef typename StopAtFirstSpliceElseTraverseRemaining_, RemainingSplices...>::type type; }; + + // ... or if there are no splices left to check, proceed with the + // children of the type tag. + template + struct TraverseRemainingSplicesAndChildren_ > + { typedef typename TraverseRemainingChildren_::type type; }; + + template + struct GetEffectiveTypeTag_ + { typedef CurTree type; }; + + template + struct GetEffectiveTypeTag_ + { typedef typename TraverseRemainingSplicesAndChildren_::tuple >::type type; }; + +public: + typedef Property::type, PropertyTag> p; + typedef typename GetEffectiveTypeTag_::type q; +}; + +#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