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

Generated by: LCOV version 1.14