From 90550c62488a7c38ffe46b06f4acda3533d00a41 Mon Sep 17 00:00:00 2001
From: Timo Koch <timokoch@math.uio.no>
Date: Thu, 28 Sep 2023 08:10:29 +0000
Subject: [PATCH] [propsystem] add inheritsFrom query

---
 CHANGELOG.md                                  |  2 +-
 dumux/common/properties/propertysystem.hh     | 29 +++++++++++++++++++
 .../propertysystem/test_propertysystem.cc     |  5 ++++
 3 files changed, 35 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index ab7277f33d..496998179e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -18,7 +18,7 @@ from the parameter input file. The constructor takes the expression and an array
 be evaluated with the function values provided in the same order as the names where specified. An arbitrary number of arguments is supported. ExprTK support very complex expressions, see https://www.partow.net/programming/exprtk/.
 - __Time loop__: Fixed a bug when the time is chosen to be negative and/or the end time is set to zero. (Before we assume time is always positive and endtime never zero.)
 - __Hyperelastic__: Added a hyperelastic model (large deformations) and a test (in geomechanics)
-
+- __Property system__: Added a function `inheritsFrom` that allows to query whether a type tag is present in the inheritance hierarchy of another type tag
 
 ### Immediate interface changes not allowing/requiring a deprecation period:
 
diff --git a/dumux/common/properties/propertysystem.hh b/dumux/common/properties/propertysystem.hh
index 916e6dc78e..d28cbb58d2 100644
--- a/dumux/common/properties/propertysystem.hh
+++ b/dumux/common/properties/propertysystem.hh
@@ -218,6 +218,25 @@ struct GetPropOrImpl
     using type = std::conditional_t<std::is_same_v<PT, UndefinedProperty>, WrapperT, PT>;
 };
 
+template<class ParentTag, class TypeTag, bool hasParents = hasParentTypeTag<TypeTag>(int{})>
+struct InheritsFrom;
+
+template<class ParentTag, class TypeTag>
+struct InheritsFrom<ParentTag, TypeTag, false> {
+    static constexpr bool value = std::is_same_v<ParentTag, TypeTag>;
+};
+
+template<class ParentTag, class TypeTag>
+struct InheritsFrom<ParentTag, TypeTag, true> {
+    static constexpr bool value = std::is_same_v<ParentTag, TypeTag>
+        || InheritsFrom<ParentTag, typename TypeTag::InheritsFrom, false>::value;
+};
+
+template<class ParentTag, class... TypeTags>
+struct InheritsFrom<ParentTag, std::tuple<TypeTags...>, false> {
+    static constexpr bool value = (InheritsFrom<ParentTag, TypeTags>::value || ...);
+};
+
 } // end namespace Dumux::Properties::Detail
 
 #endif // DOXYGEN
@@ -235,6 +254,16 @@ inline constexpr bool hasDefinedType()
     return !std::is_same_v<type, UndefinedProperty>;
 }
 
+/*!
+ * \ingroup Properties
+ * \brief Return true if the given type tag inherits from the given parent type tag
+ */
+template<class ParentTypeTag, class TypeTag>
+inline constexpr bool inheritsFrom()
+{
+    return Detail::InheritsFrom<ParentTypeTag, TypeTag>::value;
+}
+
 } // end namespace Dumux::Properties
 
 namespace Dumux {
diff --git a/test/common/propertysystem/test_propertysystem.cc b/test/common/propertysystem/test_propertysystem.cc
index 38328c381e..47acac0631 100644
--- a/test/common/propertysystem/test_propertysystem.cc
+++ b/test/common/propertysystem/test_propertysystem.cc
@@ -115,6 +115,11 @@ int main(int argc, char* argv[])
             DUNE_THROW(Dune::InvalidStateException, "Property UseTpfaFlux in TTag::CCTpfaDisc should be true!");
     }
 
+    static_assert(inheritsFrom<TTag::Base, TTag::CCTpfaDisc>());
+    static_assert(!inheritsFrom<TTag::CCTpfaDisc, TTag::Base>());
+    static_assert(inheritsFrom<TTag::Base, TTag::OnePTest>());
+    static_assert(!inheritsFrom<TTag::OnePTest, TTag::Base>());
+
     std::cout << "All tests passed!" << std::endl;
     return 0;
 }
-- 
GitLab