2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2020, by the GROMACS development team, led by
5 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6 * and including many others, as listed in the AUTHORS file in the
7 * top-level source directory and at http://www.gromacs.org.
9 * GROMACS is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public License
11 * as published by the Free Software Foundation; either version 2.1
12 * of the License, or (at your option) any later version.
14 * GROMACS is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with GROMACS; if not, see
21 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * If you want to redistribute modifications to GROMACS, please
25 * consider that scientific software is very special. Version
26 * control is crucial - bugs must be traceable. We will be happy to
27 * consider code for inclusion in the official distribution, but
28 * derived work must not be called official GROMACS. Details are found
29 * in the README & COPYING files - if they are missing, get the
30 * official version at http://www.gromacs.org.
32 * To help us fund GROMACS development, we humbly ask that you cite
33 * the research papers on the package. Check out http://www.gromacs.org.
35 /*! \inpublicapi \file
37 * Implements general purpose STL-like type traits
39 * \author Victor Holanda <victor.holanda@cscs.ch>
40 * \author Joe Jordan <ejjordan@kth.se>
41 * \author Prashanth Kanduri <kanduri@cscs.ch>
42 * \author Sebastian Keller <keller@cscs.ch>
43 * \author Artem Zhmurov <zhmurov@gmail.com>
46 #ifndef NBLIB_UTIL_TRAITS_HPP
47 #define NBLIB_UTIL_TRAITS_HPP
54 #include <type_traits>
61 //! \brief Base template for a holder of entries of different data types
69 //! \brief unimplemented base template
70 template<template<class...> class P, class L>
71 struct [[maybe_unused]] Map_;
73 /*! \brief Implementation of Map_
75 * This is a specialization of the Map_ base template
76 * for the case that the L template parameter itself has template parameters
77 * in this case, the template parameters of L are caught in Ts...
80 template<template<class...> class P, template<class...> class L, class... Ts>
81 struct Map_<P, L<Ts...>>
83 // resulting type is a TypeList of the P-template instantiated
84 // with all template parameters of L
85 typedef TypeList<P<Ts>...> type;
88 //! \brief unimplemented base template
89 template<template<class...> class P, class L>
90 struct [[maybe_unused]] Reduce_;
92 //! \brief Implementation of Reduce_
93 template<template<class...> class P, template<class...> class L, class... Ts>
94 struct Reduce_<P, L<Ts...>>
96 typedef P<Ts...> type;
99 //! \brief unimplemented base template
100 template<class L1, class L2>
101 struct [[maybe_unused]] FuseTwo_;
103 //! \brief implementation of FuseTwo_
104 template<template<class...> class L1, template<class...> class L2, class... Ts1, class... Ts2>
105 struct FuseTwo_<L1<Ts1...>, L2<Ts2...>>
107 typedef TypeList<Ts1..., Ts2...> type;
110 //! \brief unimplemented base template
111 template<class... Ls>
112 struct [[maybe_unused]] Fuse_;
114 //! \brief recursion endpoint
121 //! \brief recurse until only one type is left
122 template<class L1, class L2, class... Ls>
123 struct Fuse_<L1, L2, Ls...>
125 typedef typename Fuse_<typename FuseTwo_<L1, L2>::type, Ls...>::type type;
129 //! \brief keep adding the template parameter pack to the type list
130 template<class L, int N, class... Ts>
133 typedef typename RepeatHelper_<typename FuseTwo_<L, TypeList<Ts...>>::type, N - 1, Ts...>::type type;
136 //! \brief stop recurision
137 template<class L, class... Ts>
138 struct RepeatHelper_<L, 1, Ts...>
144 template<class L, int N, class = void>
149 //! \brief capture original template parameter pack, protect against N < 1
150 template<template<class...> class L, int N, class... Ts>
151 struct Repeat_<L<Ts...>, N, std::enable_if_t<N >= 1>>
153 typedef typename RepeatHelper_<L<Ts...>, N, Ts...>::type type;
157 // Like std::void_t but for values
159 using void_value_t = void;
161 template<class T, class = void>
162 struct HasValueMember : std::false_type
167 struct HasValueMember<T, void_value_t<T::value>> : std::true_type
171 template<class T, class = void>
172 struct AccessTypeMemberIfPresent
178 struct AccessTypeMemberIfPresent<T, typename std::void_t<typename T::type>>
180 typedef typename T::type type;
184 using AccessTypeMemberIfPresent_t = typename AccessTypeMemberIfPresent<T>::type;
186 /*! \brief Comparison meta function that compares T to Tuple[N]
188 * This trait evaluates to std::true_type if T is the same as Tuple[N]
189 * OR if T is the same as the type member of Tuple[N]
191 template<int N, typename T, typename Tuple>
192 struct MatchTypeOrTypeMember :
193 std::disjunction<std::is_same<T, std::tuple_element_t<N, Tuple>>,
194 std::is_same<T, AccessTypeMemberIfPresent_t<std::tuple_element_t<N, Tuple>>>>
198 //! \brief Recursion to check the next field N+1
199 template<int N, class T, class Tuple, template<int, class, class> class Comparison, class Match = void>
200 struct MatchField_ : std::integral_constant<size_t, MatchField_<N + 1, T, Tuple, Comparison>{}>
204 //! \brief recursion stop when Comparison<N, T, Tuple>::value is true
205 template<int N, class T, class Tuple, template<int, class, class> class Comparison>
206 struct MatchField_<N, T, Tuple, Comparison, std::enable_if_t<Comparison<N, T, Tuple>{}>> :
207 std::integral_constant<size_t, N>
211 } // namespace detail
213 /*! \brief Create a TypeList of P instantiated with each template parameter of L
215 * returns TypeList<P<Ts>...>, with Ts... = template parameters of L
216 * does not compile if L has no template parameters
218 template<template<class...> class P, class L>
219 using Map = typename detail::Map_<P, L>::type;
221 /*! \brief Base template for expressing a datatype P templated with all the entries in type list L
223 * The result is P instantiated with all the template parameters of L
225 template<template<class...> class P, class L>
226 using Reduce = typename detail::Reduce_<P, L>::type;
228 //! \brief Concatenates template parameters of two variadic templates into a TypeList
229 template<class... Ls>
230 using FuseTwo = typename detail::FuseTwo_<Ls...>::type;
232 /*! \brief This traits concatenates an arbitrary number of variadic templates into a single TypeList
234 * For clarity reasons, the fuse operation to fuse two lists into one has been decoupled
235 * into a separate trait from the handling of the recursion over the variadic arguments.
237 template<class... Ls>
238 using Fuse = typename detail::Fuse_<Ls...>::type;
240 /*! \brief Repeat the template parameters of L N times
242 * L must have template parameters
243 * N must be bigger than 0
244 * Repeated types are put in a TypeList
246 template<class L, int N>
247 using Repeat = typename detail::Repeat_<L, N>::type;
249 /*! \brief Meta function to return the first index in Tuple whose type matches T
251 * If there are more than one, the first occurrence will be returned.
252 * If there is no such type, the size of Tuple will be returned.
253 * Note that the default comparison operation supplied here also matches if the type member Tuple[N]::type matches T
255 template<typename T, class TL, template<int, class, class> class Comparison = detail::MatchTypeOrTypeMember>
260 /*! \brief Specialization to only enable this trait if TL has template parameters
262 * \tparam T a type to look for in the template parameters of TL
263 * \tparam TL a template template parameter, e.g. std::tuple or nblib::TypeList
264 * \tparam Ts template parameters of TL
265 * \tparam Comparison comparison operation
267 * Note that \a T is added to \a TL as a sentinel to terminate the recursion
268 * and prevent an out of bounds tuple access compiler error.
270 template<typename T, template<class...> class TL, class... Ts, template<int, class, class> class Comparison>
271 struct FindIndex<T, TL<Ts...>, Comparison> : detail::MatchField_<0, T, std::tuple<Ts..., T>, Comparison>
275 /*! \brief Meta function to return the element in Tuple whose type matches T
277 * If there are more than one, the first occurrence will be returned
278 * If there is no such that, a compiler error is generated due to accessing
279 * the tuple out of bounds
281 template<typename T, typename Tuple>
282 decltype(auto) pickType(Tuple& tup)
284 return std::get<FindIndex<T, std::decay_t<Tuple>>{}>(tup);
287 //! \brief template meta function to determine whether T is contained in TL
288 template<class T, class TL>
293 /*! \brief implementation of the Contains trait to look for T in TL
295 * \tparam T type to look for in TL
296 * \tparam TL a variadic type, such as std::tuple or TypeList
297 * \tparam Ts the template parameters of TL
299 * Note that this clang-format enforced formatting is unfortunate, it should be:
300 * struct Contains<T, TL<Ts...>> : std::bool_constant<FindIndex<T, TL<Ts...>>{} < sizeof...(Ts)>
302 template<class T, template<class...> class TL, class... Ts>
303 struct Contains<T, TL<Ts...>> : std::bool_constant < FindIndex<T, TL<Ts...>>{}<sizeof...(Ts)>
309 #endif // NBLIB_UTIL_TRAITS_HPP