SpECTRE Documentation Coverage Report
Current view: top level - DataStructures/DataBox - DataBoxTag.hpp Hit Total Coverage
Commit: 2db722c93a8e9b106e406b439b79c8e05c2057fb Lines: 2 4 50.0 %
Date: 2021-03-03 22:01:00
Legend: Lines: hit not hit

          Line data    Source code
       1           1 : // Distributed under the MIT License.
       2             : // See LICENSE.txt for details.
       3             : 
       4             : /// \file
       5             : /// Defines classes SimpleTag, PrefixTag, ComputeTag and several
       6             : /// functions for retrieving tag info
       7             : 
       8             : #pragma once
       9             : 
      10             : #include <cstddef>
      11             : #include <ostream>
      12             : #include <string>
      13             : 
      14             : #include "DataStructures/DataBox/Subitems.hpp"
      15             : #include "DataStructures/DataBox/Tag.hpp"
      16             : #include "DataStructures/DataBox/TagTraits.hpp"
      17             : #include "DataStructures/VariablesTag.hpp"
      18             : #include "Utilities/ConstantExpressions.hpp"
      19             : #include "Utilities/ErrorHandling/Assert.hpp"
      20             : #include "Utilities/NoSuchType.hpp"
      21             : #include "Utilities/PrettyType.hpp"
      22             : #include "Utilities/Requires.hpp"
      23             : #include "Utilities/TMPL.hpp"
      24             : #include "Utilities/TypeTraits.hpp"
      25             : #include "Utilities/TypeTraits/CreateIsCallable.hpp"
      26             : #include "Utilities/TypeTraits/IsA.hpp"
      27             : 
      28           0 : namespace Tags {
      29             : /*!
      30             :  * \ingroup DataBoxTagsGroup
      31             :  * \brief Tag used to retrieve the DataBox from the `db::get` function
      32             :  *
      33             :  * The main use of this tag is to allow fetching the DataBox from itself. The
      34             :  * primary use case is to allow an invokable to take a DataBox as an argument
      35             :  * when called through `db::apply`.
      36             :  *
      37             :  * \snippet Test_DataBox.cpp databox_self_tag_example
      38             :  */
      39           1 : struct DataBox {
      40             :   // Trick to get friend function declaration to compile but a const void& is
      41             :   // rather useless
      42           0 :   using type = void;
      43             : };
      44             : }  // namespace Tags
      45             : 
      46             : namespace db {
      47             : 
      48             : namespace detail {
      49             : template <typename TagList, typename Tag>
      50             : using list_of_matching_tags = tmpl::conditional_t<
      51             :     std::is_same_v<Tag, ::Tags::DataBox>, tmpl::list<::Tags::DataBox>,
      52             :     tmpl::filter<TagList, std::is_base_of<tmpl::pin<Tag>, tmpl::_1>>>;
      53             : 
      54             : template <typename Tag, typename TagList,
      55             :           typename MatchingTagsList = list_of_matching_tags<TagList, Tag>>
      56             : struct first_matching_tag_impl {
      57             :   using type = tmpl::front<MatchingTagsList>;
      58             : };
      59             : 
      60             : template <typename Tag, typename TagList>
      61             : struct first_matching_tag_impl<Tag, TagList, tmpl::list<>> {
      62             :   static_assert(std::is_same<Tag, NoSuchType>::value,
      63             :                 "Could not find the DataBox tag in the list of DataBox tags. "
      64             :                 "The first template parameter of 'first_matching_tag_impl' is "
      65             :                 "the tag that cannot be found and the second is the list of "
      66             :                 "tags being searched.");
      67             :   using type = NoSuchType;
      68             : };
      69             : 
      70             : template <typename TagList, typename Tag>
      71             : using first_matching_tag = typename first_matching_tag_impl<Tag, TagList>::type;
      72             : 
      73             : template <typename TagList, typename Tag>
      74             : constexpr auto number_of_matching_tags =
      75             :     tmpl::size<list_of_matching_tags<TagList, Tag>>::value;
      76             : 
      77             : template <typename TagList, typename Tag>
      78             : struct has_unique_matching_tag
      79             :     : std::integral_constant<bool, number_of_matching_tags<TagList, Tag> == 1> {
      80             : };
      81             : 
      82             : template <typename TagList, typename Tag>
      83             : using has_unique_matching_tag_t =
      84             :     typename has_unique_matching_tag<TagList, Tag>::type;
      85             : 
      86             : template <typename TagList, typename Tag>
      87             : constexpr bool has_unique_matching_tag_v =
      88             :     has_unique_matching_tag<TagList, Tag>::value;
      89             : 
      90             : template <typename TagList, typename Tag>
      91             : struct has_no_matching_tag
      92             :     : std::integral_constant<bool, number_of_matching_tags<TagList, Tag> == 0> {
      93             : };
      94             : 
      95             : template <typename TagList, typename Tag>
      96             : using has_no_matching_tag_t = typename has_no_matching_tag<TagList, Tag>::type;
      97             : 
      98             : template <typename TagList, typename Tag>
      99             : constexpr bool has_no_matching_tag_v = has_no_matching_tag<TagList, Tag>::value;
     100             : 
     101             : template <class T, class = void>
     102             : struct has_return_type_member : std::false_type {};
     103             : template <class T>
     104             : struct has_return_type_member<T, std::void_t<typename T::return_type>>
     105             :     : std::true_type {};
     106             : 
     107             : /*!
     108             :  * \brief `true` if `T` has nested type alias named `return_type`
     109             :  */
     110             : template <class T>
     111             : constexpr bool has_return_type_member_v = has_return_type_member<T>::value;
     112             : 
     113             : template <typename T>
     114             : struct ConvertToConst {
     115             :   using type = const T&;
     116             : };
     117             : 
     118             : template <typename T>
     119             : struct ConvertToConst<std::unique_ptr<T>> {
     120             :   using type = const T&;
     121             : };
     122             : 
     123             : template <typename T>
     124             : const T& convert_to_const_type(const T& item) noexcept {
     125             :   return item;
     126             : }
     127             : 
     128             : template <typename T>
     129             : const T& convert_to_const_type(const std::unique_ptr<T>& item) noexcept {
     130             :   return *item;
     131             : }
     132             : 
     133             : template <typename TagList, typename Tag>
     134             : struct storage_type_impl;
     135             : 
     136             : template <int SelectTagType>
     137             : struct dispatch_storage_type;
     138             : 
     139             : template <typename ArgsList>
     140             : struct compute_item_type;
     141             : 
     142             : template <typename TagList, typename Tag>
     143             : struct storage_type_impl {
     144             :   // storage_type_impl is intentionally a lazy metafunction rather than a
     145             :   // metaclosure or a metacontinuation. The reason is that it is quite likely we
     146             :   // call `db::item_type<Tag>` multiple times within the same translation unit
     147             :   // and so we want to memoize the resulting type. However, we do not want to
     148             :   // memoize the dispatch calls.
     149             :   using type = typename dispatch_storage_type<
     150             :       is_base_tag_v<Tag>
     151             :           ? 4
     152             :           : (is_compute_tag_v<Tag>and has_return_type_member_v<Tag>)
     153             :                 ? 3
     154             :                 : is_immutable_item_tag_v<Tag>
     155             :                       ? 2
     156             :                       : std::is_base_of_v<db::SimpleTag, Tag> ? 1 : 0>::
     157             :       template f<TagList, Tag>;
     158             : };
     159             : 
     160             : template <>
     161             : struct dispatch_storage_type<0> {
     162             :   // Tag is not a tag. This is necessary for SFINAE friendliness, specifically
     163             :   // if someone calls Requires<tt::is_a_v<std::vector, db::item_type<Tag>>>
     164             :   // with, say Tag = double, then this should probably SFINAE away, not fail to
     165             :   // compile.
     166             :   template <typename TagList, typename Tag>
     167             :   using f = NoSuchType;
     168             : };
     169             : 
     170             : template <>
     171             : struct dispatch_storage_type<1> {
     172             :   // simple item
     173             :   template <typename TagList, typename Tag>
     174             :   using f = typename Tag::type;
     175             : };
     176             : 
     177             : template <>
     178             : struct dispatch_storage_type<2> {
     179             :   // compute item
     180             :   template <typename TagList, typename Tag>
     181             :   using f = typename compute_item_type<typename Tag::argument_tags>::template f<
     182             :       TagList, Tag>;
     183             : };
     184             : 
     185             : template <>
     186             : struct dispatch_storage_type<3> {
     187             :   // mutating compute item
     188             :   template <typename TagList, typename Tag>
     189             :   using f = typename Tag::return_type;
     190             : };
     191             : 
     192             : template <typename TagList, typename Tag>
     193             : struct get_first_derived_tag_for_base_tag {
     194             :   static_assert(
     195             :       not std::is_same_v<TagList, NoSuchType>,
     196             :       "Can't retrieve the storage type of a base tag without the full tag "
     197             :       "list. If you're using 'item_type' or 'const_item_type' then make sure "
     198             :       "you pass the DataBox's tag list as the second template parameter to "
     199             :       "those metafunctions. The base tag for which the storage type is being"
     200             :       "retrieved is listed as the second template argument to the "
     201             :       "'get_first_derived_tag_for_base_tag' class below");
     202             :   using type = first_matching_tag<TagList, Tag>;
     203             : };
     204             : 
     205             : template <>
     206             : struct dispatch_storage_type<4> {
     207             :   // base tag item: retrieve the derived tag from the tag list then call
     208             :   // storage_type_impl on the result.
     209             :   // We do not check that there is only one matching tag in the DataBox because
     210             :   // the uniqueness is only checked in get and mutate. The reason for that is
     211             :   // that it is fine to have multiple derived tags in the DataBox as long as
     212             :   // they all have the same type. We do not check that the types are all the
     213             :   // same, it is undefined behavior if they are not and the user's
     214             :   // responsibility.
     215             :   template <typename TagList, typename Tag>
     216             :   using f = typename storage_type_impl<
     217             :       TagList,
     218             :       tmpl::type_from<get_first_derived_tag_for_base_tag<TagList, Tag>>>::type;
     219             : };
     220             : 
     221             : // The type internally stored in a simple or compute item.  For
     222             : // convenience in implementing the various tag type metafunctions,
     223             : // this will also look up types for db::BaseTags, even though they
     224             : // cannot actually store anything.
     225             : template <typename Tag, typename TagList>
     226             : using storage_type = typename storage_type_impl<TagList, Tag>::type;
     227             : 
     228             : template <typename TagList, typename Tag>
     229             : struct item_type_impl {
     230             :   static_assert(not is_compute_tag_v<Tag>,
     231             :                 "Can't call item_type on a compute item because compute items "
     232             :                 "cannot be modified.  You probably wanted const_item_type.");
     233             :   using type = detail::storage_type<Tag, TagList>;
     234             : };
     235             : 
     236             : // Get the type that is returned by `get<Tag>`. If it is a base tag then a
     237             : // `TagList` must be passed as a second argument.
     238             : template <typename Tag, typename TagList = NoSuchType>
     239             : using const_item_type =
     240             :     typename ConvertToConst<std::decay_t<storage_type<Tag, TagList>>>::type;
     241             : 
     242             : // Get the type that can be written to the `Tag`. If it is a base tag then a
     243             : // `TagList` must be passed as a second argument.
     244             : template <typename Tag, typename TagList = NoSuchType>
     245             : using item_type = typename item_type_impl<TagList, Tag>::type;
     246             : 
     247             : CREATE_IS_CALLABLE(get)
     248             : CREATE_IS_CALLABLE_V(get)
     249             : 
     250             : template <typename Tag, typename TagList, typename TagTypesList>
     251             : struct check_compute_item_is_invokable;
     252             : 
     253             : template <typename Tag, typename... Tags, typename... TagTypes>
     254             : struct check_compute_item_is_invokable<Tag, tmpl::list<Tags...>,
     255             :                                        tmpl::list<TagTypes...>> {
     256             :   static_assert(
     257             :       is_get_callable_v<Tag, TagTypes...>,
     258             :       "The compute item is not callable with the types that the tags hold. The "
     259             :       "compute item tag that is the problem should be shown in the first line "
     260             :       " after the static assert error: "
     261             :       "'check_compute_item_is_invokable<TheItemThatsFailingToBeCalled, "
     262             :       "brigand::list<PassedTags...>, "
     263             :       "brigand::list<const_item_type<PassedTags>...>>'");
     264             : };
     265             : 
     266             : template <typename... Args>
     267             : struct compute_item_type<tmpl::list<Args...>> {
     268             :   template <typename TagList, typename Tag>
     269             :   using f = decltype(
     270             : #ifdef SPECTRE_DEBUG
     271             :       (void)check_compute_item_is_invokable<
     272             :           Tag, tmpl::list<Args...>,
     273             :           tmpl::list<const_item_type<Args, TagList>...>>{},
     274             : #endif  // SPECTRE_DEBUG
     275             :       Tag::get(std::declval<const_item_type<Args, TagList>>()...));
     276             : };
     277             : }  // namespace detail
     278             : }  // namespace db

Generated by: LCOV version 1.14