// -*- mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- // vi: set et ts=4 sw=4 sts=4: /***************************************************************************** * See the file COPYING for full copying permissions. * * * * 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 3 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 * * MERCHANTABILITY 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 * \ingroup Properties * \ingroup TypeTraits * \author Timo Koch * \brief The Opm property system, traits with inheritance */ #ifndef OPM_PROPERTY_SYSTEM_HH #define OPM_PROPERTY_SYSTEM_HH #include #include #include #include #include namespace Opm { namespace Properties { //! a tag to mark properties as undefined struct UndefinedProperty {}; template struct Splices { using type = std::tuple<>; }; //! implementation details for template meta programming namespace Detail { //! check if a property P is defined template constexpr auto isDefinedProperty(int) -> decltype(std::integral_constant::value>{}) { return {}; } //! fall back if a Property is defined template constexpr std::true_type isDefinedProperty(...) { return {}; } //! check if a TypeTag inherits from other TypeTags template constexpr auto hasParentTypeTag(int) -> decltype(std::declval(), std::true_type{}) { return {}; } //! fall back if a TypeTag doesn't inherit template constexpr std::false_type hasParentTypeTag(...) { return {}; } //! helper alias to concatenate multiple tuples template using ConCatTuples = decltype(std::tuple_cat(std::declval()...)); //! helper struct to get the first property that is defined in the TypeTag hierarchy template class Property, class TTagList> struct GetDefined; //! helper struct to iterate over the TypeTag hierarchy template class Property, class TTagList, class Enable> struct GetNextTypeTag; template class Property, class LastTypeTag> struct GetNextTypeTag, std::enable_if_t(int{}), void>> { using type = typename GetDefined::type; }; template class Property, class LastTypeTag> struct GetNextTypeTag, std::enable_if_t(int{}), void>> { using type = UndefinedProperty; }; template class Property, class FirstTypeTag, class ...Args> struct GetNextTypeTag, std::enable_if_t(int{}), void>> { using type = typename GetDefined>>::type; }; template class Property, class FirstTypeTag, class ...Args> struct GetNextTypeTag, std::enable_if_t(int{}), void>> { using type = typename GetDefined>::type; }; template class Property, class LastTypeTag> struct GetDefined> { // For clang, the following alias triggers compiler warnings if instantiated // from something like `GetPropType<..., DeprecatedProperty>`, even if that is // contained in a diagnostic pragma construct that should prevent these warnings. // As a workaround, also add the pragmas around this line. // See the discussion in MR 1647 for more details. #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif using LastType = Property; #ifdef __clang__ #pragma clang diagnostic pop #endif using type = std::conditional_t(int{}), LastType, typename GetNextTypeTag, void>::type>; }; template class Property, class FirstTypeTag, class ...Args> struct GetDefined> { // See the comment above. #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif using FirstType = Property; #ifdef __clang__ #pragma clang diagnostic pop #endif using type = std::conditional_t(int{}), FirstType, typename GetNextTypeTag, void>::type>; }; //! helper struct to get the first property that is defined in the TypeTag hierarchy template struct GetDefinedSplice; //! helper struct to iterate over the TypeTag hierarchy template struct GetNextSpliceTypeTag; template struct GetNextSpliceTypeTag, std::enable_if_t(int{}), void>> { using type = typename GetDefinedSplice::type; }; template struct GetNextSpliceTypeTag, std::enable_if_t(int{}), void>> { using type = std::tuple<>; }; template struct GetNextSpliceTypeTag, std::enable_if_t(int{}), void>> { using type = typename GetDefinedSplice>>::type; }; template struct GetNextSpliceTypeTag, std::enable_if_t(int{}), void>> { using type = typename GetDefinedSplice>::type; }; //! check if a splice S is defined template constexpr auto isDefinedSplice(int) -> decltype(std::integral_constant>::value>{}) { return {}; } //! fall back if a splice is defined template constexpr std::true_type isDefinedSplice(...) { return {}; } template struct GetDefinedSplice> { using LastSplice = Splices; using nexttuple = typename GetNextSpliceTypeTag, typename LastSplice::type >, void>::type; using type = std::conditional_t(int{}), ConCatTuples, nexttuple>; }; template struct GetDefinedSplice> { using FirstSplice = Splices; using nexttuple = typename GetNextSpliceTypeTag, typename FirstSplice::type >, void>::type; using type = std::conditional_t(int{}), ConCatTuples, nexttuple>; }; //! helper struct to extract get the Property specilization given a TypeTag, asserts that the property is defined template class Property> struct GetPropImpl { using tuple = typename Detail::GetDefinedSplice>::type; using type = typename Detail::GetDefined, tuple> >::type; static_assert(!std::is_same::value, "Property is undefined!"); }; template class Property> struct GetSplicePropImpl { using type = typename Detail::GetDefined>::type; static_assert(!std::is_same>::value, "Splice is undefined!"); }; } // end namespace Detail } // end namespace Property //! get the type of a property (equivalent to old macro GET_PROP(...)) template class Property> using GetProp = typename Properties::Detail::GetPropImpl::type; // See the comment above. #ifdef __clang__ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wdeprecated-declarations" #endif //! get the type alias defined in the property (equivalent to old macro GET_PROP_TYPE(...)) template class Property> using GetPropType = typename Properties::Detail::GetPropImpl::type::type; template class Property> using GetSplicePropType = typename Properties::Detail::GetSplicePropImpl::type::type; //! get the value data member of a property template class Property> constexpr auto getPropValue() { return Properties::Detail::GetPropImpl::type::value; } #ifdef __clang__ #pragma clang diagnostic pop #endif } // end namespace Opm #endif