PrefixHelpers.hpp
1 // Distributed under the MIT License.
2 // See LICENSE.txt for details.
3 
4 #pragma once
5 
6 #include "Utilities/TMPL.hpp"
7 #include "Utilities/TypeTraits.hpp"
8 #include "Utilities/TypeTraits/IsA.hpp"
9 
10 /// \cond
11 namespace db {
12 struct PrefixTag;
13 struct SimpleTag;
14 } // namespace db
15 
16 namespace Tags {
17 template <typename TagsList>
18 struct Variables;
19 } // namespace Tags
20 /// \endcond
21 
22 namespace db {
23 
24 /// \ingroup DataBoxTagsGroup
25 /// \brief Create a new list of Tags by wrapping each tag in `TagList` using the
26 /// `Wrapper`.
27 template <template <typename...> class Wrapper, typename TagList,
28  typename... Args>
29 using wrap_tags_in =
30  tmpl::transform<TagList, tmpl::bind<Wrapper, tmpl::_1, tmpl::pin<Args>...>>;
31 
32 namespace DataBox_detail {
33 enum class DispatchTagType {
34  Variables,
35  Prefix,
36  Other,
37 };
38 
39 template <typename Tag>
40 constexpr DispatchTagType tag_type =
41  tt::is_a_v<Tags::Variables, Tag>
42  ? DispatchTagType::Variables
43  : std::is_base_of_v<db::PrefixTag, Tag> ? DispatchTagType::Prefix
44  : DispatchTagType::Other;
45 
46 template <DispatchTagType TagType>
47 struct add_tag_prefix_impl;
48 
49 // Call the appropriate impl based on the type of the tag being
50 // prefixed.
51 template <template <typename...> class Prefix, typename Tag, typename... Args>
52 using dispatch_add_tag_prefix_impl =
53  typename add_tag_prefix_impl<tag_type<Tag>>::template f<Prefix, Tag,
54  Args...>;
55 
56 template <>
57 struct add_tag_prefix_impl<DispatchTagType::Other> {
58  template <template <typename...> class Prefix, typename Tag, typename... Args>
59  using f = Tag;
60 };
61 
62 template <>
63 struct add_tag_prefix_impl<DispatchTagType::Prefix> {
64  template <template <typename...> class Prefix, typename Tag, typename... Args>
65  struct prefix_wrapper_helper;
66 
67  template <template <typename...> class Prefix,
68  template <typename...> class InnerPrefix, typename InnerTag,
69  typename... InnerArgs, typename... Args>
70  struct prefix_wrapper_helper<Prefix, InnerPrefix<InnerTag, InnerArgs...>,
71  Args...> {
72  static_assert(
73  std::is_same_v<typename InnerPrefix<InnerTag, InnerArgs...>::tag,
74  InnerTag>,
75  "Inconsistent values of prefixed tag");
76  using type =
77  InnerPrefix<dispatch_add_tag_prefix_impl<Prefix, InnerTag, Args...>,
78  InnerArgs...>;
79  };
80 
81  template <template <typename...> class Prefix, typename Tag, typename... Args>
82  using f = typename prefix_wrapper_helper<Prefix, Tag, Args...>::type;
83 };
84 
85 template <>
86 struct add_tag_prefix_impl<DispatchTagType::Variables> {
87  template <template <typename...> class Prefix, typename Tag, typename... Args>
88  using f =
89  Tags::Variables<wrap_tags_in<Prefix, typename Tag::tags_list, Args...>>;
90 };
91 
92 // Implementation of remove_tag_prefix
93 template <typename>
94 struct remove_tag_prefix_impl;
95 
96 template <DispatchTagType TagType>
97 struct remove_variables_prefix;
98 
99 template <typename Tag>
100 using dispatch_remove_variables_prefix =
101  typename remove_variables_prefix<tag_type<Tag>>::template f<Tag>;
102 
103 template <>
104 struct remove_variables_prefix<DispatchTagType::Other> {
105  template <typename Tag>
106  using f = Tag;
107 };
108 
109 template <>
110 struct remove_variables_prefix<DispatchTagType::Prefix> {
111  template <typename Tag>
112  struct helper;
113 
114  template <template <typename...> class Prefix, typename Tag, typename... Args>
115  struct helper<Prefix<Tag, Args...>> {
116  using type = Prefix<dispatch_remove_variables_prefix<Tag>, Args...>;
117  };
118 
119  template <typename Tag>
120  using f = typename helper<Tag>::type;
121 };
122 
123 template <>
124 struct remove_variables_prefix<DispatchTagType::Variables> {
125  template <typename Tag>
126  using f = Tags::Variables<tmpl::transform<typename Tag::tags_list,
127  remove_tag_prefix_impl<tmpl::_1>>>;
128 };
129 
130 template <typename UnprefixedTag, template <typename...> class Prefix,
131  typename... Args>
132 struct remove_tag_prefix_impl<Prefix<UnprefixedTag, Args...>> {
133  static_assert(std::is_base_of_v<db::SimpleTag, UnprefixedTag>,
134  "Unwrapped tag is not a DataBoxTag");
135  using type = dispatch_remove_variables_prefix<UnprefixedTag>;
136 };
137 } // namespace DataBox_detail
138 
139 /// \ingroup DataBoxTagsGroup
140 /// Wrap `Tag` in `Prefix<_, Args...>`, also wrapping variables tags
141 /// if `Tag` is a `Tags::Variables`.
142 template <template <typename...> class Prefix, typename Tag, typename... Args>
143 using add_tag_prefix =
144  Prefix<DataBox_detail::dispatch_add_tag_prefix_impl<Prefix, Tag, Args...>,
145  Args...>;
146 
147 /// \ingroup DataBoxTagsGroup
148 /// Remove a prefix from `Tag`, also removing it from the variables
149 /// tags if the unwrapped tag is a `Tags::Variables`.
150 template <typename Tag>
151 using remove_tag_prefix =
152  typename DataBox_detail::remove_tag_prefix_impl<Tag>::type;
153 
154 namespace DataBox_detail {
155 template <class Tag, bool IsPrefix>
156 struct remove_all_prefixes_impl;
157 } // namespace DataBox_detail
158 
159 /// \ingroup DataBoxGroup
160 /// Completely remove all prefix tags from a Tag
161 template <typename Tag>
162 using remove_all_prefixes = typename DataBox_detail::remove_all_prefixes_impl<
163  Tag, std::is_base_of_v<db::PrefixTag, Tag>>::type;
164 
165 namespace DataBox_detail {
166 template <class Tag>
167 struct remove_all_prefixes_impl<Tag, false> {
168  using type = Tag;
169 };
170 
171 template <class Tag>
172 struct remove_all_prefixes_impl<Tag, true> {
174 };
175 
176 // Implementation of variables_tag_with_tags_list
177 template <DispatchTagType TagType>
178 struct variables_tag_with_tags_list_impl;
179 } // namespace DataBox_detail
180 
181 /// \ingroup DataBoxGroup
182 /// Change the tags contained in a possibly prefixed Variables tag.
183 /// \example
184 /// \snippet Test_PrefixHelpers.cpp variables_tag_with_tags_list
185 template <typename Tag, typename NewTagsList>
187  typename DataBox_detail::variables_tag_with_tags_list_impl<
188  DataBox_detail::tag_type<Tag>>::template f<Tag, NewTagsList>;
189 
190 namespace DataBox_detail {
191 // Implementation of variables_tag_with_tags_list
192 template <>
193 struct variables_tag_with_tags_list_impl<DispatchTagType::Variables> {
194  template <typename Tag, typename NewTagsList>
196 };
197 
198 template <>
199 struct variables_tag_with_tags_list_impl<DispatchTagType::Prefix> {
200  template <typename Tag, typename NewTagsList>
201  struct helper;
202 
203  template <template <typename...> class Prefix, typename Tag, typename... Args,
204  typename NewTagsList>
205  struct helper<Prefix<Tag, Args...>, NewTagsList> {
206  using type =
207  Prefix<variables_tag_with_tags_list<Tag, NewTagsList>, Args...>;
208  };
209 
210  template <typename Tag, typename NewTagsList>
211  using f = typename helper<Tag, NewTagsList>::type;
212 };
213 
214 // Implementation of get_variables_tags_list
215 template <DispatchTagType TagType>
216 struct get_variables_tags_list_impl;
217 } // namespace DataBox_detail
218 
219 template <typename Tag>
220 using get_variables_tags_list =
221  typename DataBox_detail::get_variables_tags_list_impl<
222  DataBox_detail::tag_type<Tag>>::template f<Tag>;
223 
224 namespace DataBox_detail {
225 // Implementation of get_variables_tags_list
226 template <>
227 struct get_variables_tags_list_impl<DispatchTagType::Variables> {
228  template <typename Tag>
229  using f = typename Tag::tags_list;
230 };
231 
232 template <>
233 struct get_variables_tags_list_impl<DispatchTagType::Prefix> {
234  template <typename Tag>
235  using f = get_variables_tags_list<typename Tag::tag>;
236 };
237 } // namespace DataBox_detail
238 } // namespace db
db::remove_tag_prefix
typename DataBox_detail::remove_tag_prefix_impl< Tag >::type remove_tag_prefix
Definition: PrefixHelpers.hpp:152
Tags::Variables
Definition: VariablesTag.hpp:21
db::add_tag_prefix
Prefix< DataBox_detail::dispatch_add_tag_prefix_impl< Prefix, Tag, Args... >, Args... > add_tag_prefix
Definition: PrefixHelpers.hpp:145
db::wrap_tags_in
tmpl::transform< TagList, tmpl::bind< Wrapper, tmpl::_1, tmpl::pin< Args >... > > wrap_tags_in
Create a new list of Tags by wrapping each tag in TagList using the Wrapper.
Definition: PrefixHelpers.hpp:30
db::variables_tag_with_tags_list
typename DataBox_detail::variables_tag_with_tags_list_impl< DataBox_detail::tag_type< Tag > >::template f< Tag, NewTagsList > variables_tag_with_tags_list
Definition: PrefixHelpers.hpp:188
db::remove_all_prefixes
typename DataBox_detail::remove_all_prefixes_impl< Tag, std::is_base_of_v< db::PrefixTag, Tag > >::type remove_all_prefixes
Definition: PrefixHelpers.hpp:163
TMPL.hpp
db
Namespace for DataBox related things.
Definition: DataBox.hpp:42