SpECTRE Documentation Coverage Report
Current view: top level - Options - OptionsDetails.hpp Hit Total Coverage
Commit: 3c072f0ce967e2e56649d3fa12aa2a0e4fe2a42e Lines: 1 2 50.0 %
Date: 2024-04-23 20:50:18
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 helpers for the Parser<T> class
       6             : 
       7             : #pragma once
       8             : 
       9             : #include <algorithm>
      10             : #include <array>
      11             : #include <iomanip>
      12             : #include <list>
      13             : #include <map>
      14             : #include <memory>
      15             : #include <sstream>
      16             : #include <string>
      17             : #include <type_traits>
      18             : #include <unordered_set>
      19             : #include <utility>
      20             : #include <variant>
      21             : #include <vector>
      22             : 
      23             : #include "Options/Options.hpp"
      24             : #include "Utilities/CallWithDynamicType.hpp"
      25             : #include "Utilities/MakeString.hpp"
      26             : #include "Utilities/PrettyType.hpp"
      27             : #include "Utilities/Requires.hpp"
      28             : #include "Utilities/TMPL.hpp"
      29             : #include "Utilities/TypeTraits.hpp"
      30             : #include "Utilities/TypeTraits/IsA.hpp"
      31             : #include "Utilities/WrapText.hpp"
      32             : 
      33             : namespace Options::Options_detail {
      34             : 
      35             : template <typename Tag>
      36             : struct flatten_alternatives {
      37             :   using type = Tag;
      38             : };
      39             : 
      40             : template <typename... Tags>
      41             : struct flatten_alternatives<tmpl::list<Tags...>> {
      42             :   using type =
      43             :       tmpl::flatten<tmpl::list<typename flatten_alternatives<Tags>::type...>>;
      44             : };
      45             : 
      46             : template <typename... Tags>
      47             : struct flatten_alternatives<Options::Alternatives<Tags...>> {
      48             :   using type = tmpl::list<typename flatten_alternatives<Tags>::type...>;
      49             : };
      50             : 
      51             : // Traverses the group hierarchy of `Tag`, returning the topmost group that is
      52             : // a subgroup of `Root`. Directly returns `Tag` if it has no group.
      53             : // This means that the returned type is always the direct child node of `Root`
      54             : // that contains `Tag` in its hierarchy.
      55             : // If `Root` is not in the group hierarchy of `Tag`, this function returns the
      56             : // topmost group of `Tag` (meaning that `Root` is treated as the root of its
      57             : // group hierarchy).
      58             : template <typename Tag, typename Root, typename = std::void_t<>>
      59             : struct find_subgroup {
      60             :   using type = Tag;
      61             : };
      62             : 
      63             : template <typename Tag>
      64             : struct find_subgroup<Tag, typename Tag::group,
      65             :                      std::void_t<typename Tag::group>> {
      66             :   using type = Tag;
      67             : };
      68             : 
      69             : template <typename Tag, typename Root>
      70             : struct find_subgroup<Tag, Root, std::void_t<typename Tag::group>> {
      71             :   using type = typename find_subgroup<typename Tag::group, Root>::type;
      72             : };
      73             : 
      74             : /// Checks if `Tag` is within the group hierarchy of `Group`.
      75             : template <typename Tag, typename Group, typename = std::void_t<>>
      76             : struct is_in_group : std::false_type {};
      77             : 
      78             : template <typename Tag>
      79             : struct is_in_group<Tag, typename Tag::group, std::void_t<typename Tag::group>>
      80             :     : std::true_type {};
      81             : 
      82             : template <typename Tag, typename Group>
      83             : struct is_in_group<Tag, Group, std::void_t<typename Tag::group>>
      84             :     : is_in_group<typename Tag::group, Group> {};
      85             : 
      86             : /// The subset of tags in `OptionList` that are in the hierarchy of `Group`
      87             : template <typename OptionList, typename Group>
      88             : using options_in_group =
      89             :     tmpl::filter<OptionList, is_in_group<tmpl::_1, tmpl::pin<Group>>>;
      90             : 
      91             : // Display a type in a pseudo-YAML form, leaving out likely irrelevant
      92             : // information.
      93             : template <typename T>
      94             : struct yaml_type {
      95             :   static std::string value() { return pretty_type::name<T>(); }
      96             : };
      97             : 
      98             : template <typename T>
      99             : struct yaml_type<std::unique_ptr<T>> {
     100             :   static std::string value() { return yaml_type<T>::value(); }
     101             : };
     102             : 
     103             : template <typename T>
     104             : struct yaml_type<std::vector<T>> {
     105             :   static std::string value() { return "[" + yaml_type<T>::value() + ", ...]"; }
     106             : };
     107             : 
     108             : template <typename T>
     109             : struct yaml_type<std::list<T>> {
     110             :   static std::string value() { return "[" + yaml_type<T>::value() + ", ...]"; }
     111             : };
     112             : 
     113             : template <typename T, size_t N>
     114             : struct yaml_type<std::array<T, N>> {
     115             :   static std::string value() {
     116             :     return "[" + yaml_type<T>::value() + " x" + std::to_string(N) + "]";
     117             :   }
     118             : };
     119             : 
     120             : template <typename K, typename V, typename C>
     121             : struct yaml_type<std::map<K, V, C>> {
     122             :   static std::string value() {
     123             :     return "{" + yaml_type<K>::value() + ": " + yaml_type<V>::value() + "}";
     124             :   }
     125             : };
     126             : 
     127             : template <typename K, typename V, typename H, typename E>
     128             : struct yaml_type<std::unordered_map<K, V, H, E>> {
     129             :   static std::string value() {
     130             :     return "{" + yaml_type<K>::value() + ": " + yaml_type<V>::value() + "}";
     131             :   }
     132             : };
     133             : 
     134             : template <typename T, typename U>
     135             : struct yaml_type<std::pair<T, U>> {
     136             :   static std::string value() {
     137             :     return "[" + yaml_type<T>::value() + ", " + yaml_type<U>::value() + "]";
     138             :   }
     139             : };
     140             : 
     141             : template <typename... T>
     142             : struct yaml_type<std::variant<T...>> {
     143             :   static std::string value() {
     144             :     bool first = true;
     145             :     std::string result;
     146             :     const auto add_type = [&first, &result](auto alternative) {
     147             :       if (not first) {
     148             :         result += " or ";
     149             :       }
     150             :       first = false;
     151             :       result += yaml_type<tmpl::type_from<decltype(alternative)>>::value();
     152             :     };
     153             :     EXPAND_PACK_LEFT_TO_RIGHT(add_type(tmpl::type_<T>{}));
     154             :     return result;
     155             :   }
     156             : };
     157             : 
     158             : template <typename S, typename = std::void_t<>>
     159             : struct has_suggested : std::false_type {};
     160             : template <typename S>
     161             : struct has_suggested<
     162             :     S, std::void_t<decltype(std::declval<S>().suggested_value())>>
     163             :     : std::true_type {};
     164             : 
     165             : template <typename S, typename = std::void_t<>>
     166             : struct has_lower_bound : std::false_type {};
     167             : template <typename S>
     168             : struct has_lower_bound<S,
     169             :                        std::void_t<decltype(std::declval<S>().lower_bound())>>
     170             :     : std::true_type {};
     171             : 
     172             : template <typename S, typename = std::void_t<>>
     173             : struct has_upper_bound : std::false_type {};
     174             : template <typename S>
     175             : struct has_upper_bound<S,
     176             :                        std::void_t<decltype(std::declval<S>().upper_bound())>>
     177             :     : std::true_type {};
     178             : 
     179             : template <typename S, typename = std::void_t<>>
     180             : struct has_lower_bound_on_size : std::false_type {};
     181             : template <typename S>
     182             : struct has_lower_bound_on_size<
     183             :     S, std::void_t<decltype(std::declval<S>().lower_bound_on_size())>>
     184             :     : std::true_type {};
     185             : 
     186             : template <typename S, typename = std::void_t<>>
     187             : struct has_upper_bound_on_size : std::false_type {};
     188             : template <typename S>
     189             : struct has_upper_bound_on_size<
     190             :     S, std::void_t<decltype(std::declval<S>().upper_bound_on_size())>>
     191             :     : std::true_type {};
     192             : 
     193             : template <typename Tag>
     194             : std::string print_tag(const std::string& indent) {
     195             :   const std::string new_line = "\n" + indent + "  ";
     196             :   std::ostringstream ss;
     197             :   ss << indent << pretty_type::name<Tag>() << ":" << new_line
     198             :      << "type=" << yaml_type<typename Tag::type>::value();
     199             :   if constexpr (has_suggested<Tag>::value) {
     200             :     if constexpr (tt::is_a_v<std::unique_ptr, typename Tag::type>) {
     201             :       call_with_dynamic_type<
     202             :           void, typename Tag::type::element_type::creatable_classes>(
     203             :           Tag::suggested_value().get(), [&new_line, &ss](const auto* derived) {
     204             :             ss << new_line << "suggested=" << std::boolalpha
     205             :                << pretty_type::short_name<decltype(*derived)>();
     206             :           });
     207             :     } else {
     208             :       ss << new_line << "suggested="
     209             :          << (MakeString{} << std::boolalpha << Tag::suggested_value());
     210             :     }
     211             :   }
     212             :   if constexpr (has_lower_bound<Tag>::value) {
     213             :     ss << new_line << "min=" << (MakeString{} << Tag::lower_bound());
     214             :   }
     215             :   if constexpr (has_upper_bound<Tag>::value) {
     216             :     ss << new_line << "max=" << (MakeString{} << Tag::upper_bound());
     217             :   }
     218             :   if constexpr (has_lower_bound_on_size<Tag>::value) {
     219             :     ss << new_line << "min size=" << Tag::lower_bound_on_size();
     220             :   }
     221             :   if constexpr (has_upper_bound_on_size<Tag>::value) {
     222             :     ss << new_line << "max size=" << Tag::upper_bound_on_size();
     223             :   }
     224             :   ss << "\n" << wrap_text(Tag::help, 77, indent + "  ") << "\n\n";
     225             :   return ss.str();
     226             : }
     227             : 
     228             : template <typename OptionList, typename TagsAndSubgroups>
     229             : struct print;
     230             : 
     231             : template <typename Tag, typename OptionList>
     232             : struct print_impl {
     233             :   static std::string apply(const std::string& indent) {
     234             :     if constexpr (tmpl::list_contains_v<OptionList, Tag>) {
     235             :       return print_tag<Tag>(indent);
     236             :     } else {
     237             :       // A group
     238             :       std::ostringstream ss;
     239             :       ss << indent << pretty_type::name<Tag>() << ":\n"
     240             :          << wrap_text(Tag::help, 77, indent + "  ") << "\n\n";
     241             :       return ss.str();
     242             :     }
     243             :   }
     244             : };
     245             : 
     246             : template <typename... Alternatives>
     247             : std::string print_alternatives(const std::string& header,
     248             :                                const std::string& indent) {
     249             :   return (
     250             :       indent + header + "\n" + ... +
     251             :       (print<tmpl::list<Alternatives...>, Alternatives>::apply(indent + "  ")));
     252             : }
     253             : 
     254             : template <typename FirstAlternative, typename... OtherAlternatives,
     255             :           typename OptionList>
     256             : struct print_impl<Alternatives<FirstAlternative, OtherAlternatives...>,
     257             :                   OptionList> {
     258             :   static std::string apply(const std::string& indent) {
     259             :     return print_alternatives<FirstAlternative>("EITHER", indent) +
     260             :            print_alternatives<OtherAlternatives...>("OR", indent);
     261             :   }
     262             : };
     263             : 
     264             : template <typename OptionList, typename... TagsAndSubgroups>
     265             : struct print<OptionList, tmpl::list<TagsAndSubgroups...>> {
     266             :   static std::string apply(const std::string& indent) {
     267             :     return ("" + ... +
     268             :             (print_impl<TagsAndSubgroups, OptionList>::apply(indent)));
     269             :   }
     270             : };
     271             : 
     272             : template <typename T, typename Metavariables>
     273             : struct CreateWrapper {
     274             :   using metavariables = Metavariables;
     275             :   T data{};
     276             : };
     277           0 : #define CREATE_WRAPPER_FORWARD_OP(op)                          \
     278             :   template <typename T, typename Metavariables>                \
     279             :   bool operator op(const CreateWrapper<T, Metavariables>& a,   \
     280             :                    const CreateWrapper<T, Metavariables>& b) { \
     281             :     return a.data op b.data;                                   \
     282             :   }
     283             : CREATE_WRAPPER_FORWARD_OP(==)
     284             : CREATE_WRAPPER_FORWARD_OP(!=)
     285             : CREATE_WRAPPER_FORWARD_OP(<)
     286             : CREATE_WRAPPER_FORWARD_OP(>)
     287             : CREATE_WRAPPER_FORWARD_OP(<=)
     288             : CREATE_WRAPPER_FORWARD_OP(>=)
     289             : #undef CREATE_WRAPPER_FORWARD_OP
     290             : 
     291             : template <typename T, typename = std::nullptr_t>
     292             : struct wrap_create_types_impl;
     293             : 
     294             : template <typename T, typename Metavariables>
     295             : using wrap_create_types =
     296             :     typename wrap_create_types_impl<T>::template wrapped_type<Metavariables>;
     297             : 
     298             : template <typename T>
     299             : auto unwrap_create_types(T wrapped) {
     300             :   return wrap_create_types_impl<T>::unwrap(std::move(wrapped));
     301             : }
     302             : 
     303             : template <typename T, typename>
     304             : struct wrap_create_types_impl {
     305             :   template <typename Metavariables>
     306             :   using wrapped_type = CreateWrapper<T, Metavariables>;
     307             : };
     308             : 
     309             : template <typename T, typename Metavariables>
     310             : struct wrap_create_types_impl<CreateWrapper<T, Metavariables>> {
     311             :   // Never actually used, but instantiated during unwrapping
     312             :   template <typename /*Metavars*/>
     313             :   using wrapped_type = void;
     314             : 
     315             :   static T unwrap(CreateWrapper<T, Metavariables> wrapped) {
     316             :     return std::move(wrapped.data);
     317             :   }
     318             : };
     319             : 
     320             : template <typename T>
     321             : struct wrap_create_types_impl<T, Requires<std::is_fundamental<T>::value>> {
     322             :   template <typename Metavariables>
     323             :   using wrapped_type = T;
     324             : 
     325             :   static T unwrap(T wrapped) { return wrapped; }
     326             : };
     327             : 
     328             : // Classes convertible by yaml-cpp
     329             : template <>
     330             : struct wrap_create_types_impl<std::string> {
     331             :   template <typename Metavariables>
     332             :   using wrapped_type = std::string;
     333             : 
     334             :   static std::string unwrap(std::string wrapped) { return wrapped; }
     335             : };
     336             : 
     337             : template <typename K, typename V>
     338             : struct wrap_create_types_impl<std::map<K, V>> {
     339             :   template <typename Metavariables>
     340             :   using wrapped_type = std::map<wrap_create_types<K, Metavariables>,
     341             :                                 wrap_create_types<V, Metavariables>>;
     342             : 
     343             :   static auto unwrap(std::map<K, V> wrapped) {
     344             :     using UnwrappedK = decltype(unwrap_create_types<K>(std::declval<K>()));
     345             :     using UnwrappedV = decltype(unwrap_create_types<V>(std::declval<V>()));
     346             :     std::map<UnwrappedK, UnwrappedV> result;
     347             :     for (auto it = wrapped.begin(); it != wrapped.end();) {
     348             :       auto node = wrapped.extract(it++);
     349             :       result.emplace(unwrap_create_types<K>(std::move(node.key())),
     350             :                      unwrap_create_types<V>(std::move(node.mapped())));
     351             :     }
     352             :     return result;
     353             :   }
     354             : };
     355             : 
     356             : template <typename T>
     357             : struct wrap_create_types_impl<std::vector<T>> {
     358             :   template <typename Metavariables>
     359             :   using wrapped_type = std::vector<wrap_create_types<T, Metavariables>>;
     360             : 
     361             :   static auto unwrap(std::vector<T> wrapped) {
     362             :     using UnwrappedT = decltype(unwrap_create_types<T>(std::declval<T>()));
     363             :     std::vector<UnwrappedT> result;
     364             :     result.reserve(wrapped.size());
     365             :     for (auto& w : wrapped) {
     366             :       result.push_back(unwrap_create_types<T>(std::move(w)));
     367             :     }
     368             :     return result;
     369             :   }
     370             : };
     371             : 
     372             : template <typename T>
     373             : struct wrap_create_types_impl<std::list<T>> {
     374             :   template <typename Metavariables>
     375             :   using wrapped_type = std::list<wrap_create_types<T, Metavariables>>;
     376             : 
     377             :   static auto unwrap(std::list<T> wrapped) {
     378             :     using UnwrappedT = decltype(unwrap_create_types<T>(std::declval<T>()));
     379             :     std::list<UnwrappedT> result;
     380             :     for (auto& w : wrapped) {
     381             :       result.push_back(unwrap_create_types<T>(std::move(w)));
     382             :     }
     383             :     return result;
     384             :   }
     385             : };
     386             : 
     387             : template <typename T, size_t N>
     388             : struct wrap_create_types_impl<std::array<T, N>> {
     389             :   template <typename Metavariables>
     390             :   using wrapped_type = std::array<wrap_create_types<T, Metavariables>, N>;
     391             : 
     392             :   static auto unwrap(std::array<T, N> wrapped) {
     393             :     return unwrap_helper(std::move(wrapped), std::make_index_sequence<N>{});
     394             :   }
     395             : 
     396             :   template <size_t... Is>
     397             :   static auto unwrap_helper(std::array<T, N> wrapped,
     398             :                             std::integer_sequence<size_t, Is...> /*meta*/) {
     399             :     using UnwrappedT = decltype(unwrap_create_types<T>(std::declval<T>()));
     400             :     static_cast<void>(wrapped);  // Work around broken GCC warning
     401             :     return std::array<UnwrappedT, N>{
     402             :         {unwrap_create_types<T>(std::move(wrapped[Is]))...}};
     403             :   }
     404             : };
     405             : 
     406             : template <typename T, typename U>
     407             : struct wrap_create_types_impl<std::pair<T, U>> {
     408             :   template <typename Metavariables>
     409             :   using wrapped_type = std::pair<wrap_create_types<T, Metavariables>,
     410             :                                  wrap_create_types<U, Metavariables>>;
     411             : 
     412             :   static auto unwrap(std::pair<T, U> wrapped) {
     413             :     using UnwrappedT = decltype(unwrap_create_types<T>(std::declval<T>()));
     414             :     using UnwrappedU = decltype(unwrap_create_types<U>(std::declval<U>()));
     415             :     return std::pair<UnwrappedT, UnwrappedU>(
     416             :         unwrap_create_types<T>(std::move(wrapped.first)),
     417             :         unwrap_create_types<U>(std::move(wrapped.second)));
     418             :   }
     419             : };
     420             : }  // namespace Options::Options_detail

Generated by: LCOV version 1.14