]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Support for std::pair
authorLuca Heltai <luca.heltai@sissa.it>
Thu, 20 Jul 2017 10:18:51 +0000 (12:18 +0200)
committerLuca Heltai <luca.heltai@sissa.it>
Sun, 23 Jul 2017 14:57:29 +0000 (16:57 +0200)
include/deal.II/base/pattern_tools.h
tests/base/pattern_tools_02.cc
tests/base/pattern_tools_02.output

index fccce279cf6ae87221962504448d23401c60d347..80945534a7278fd16d021e2d17a7c36263fe9a9f 100644 (file)
@@ -128,6 +128,8 @@ namespace PatternTools
    * The second template parameter is used internally to allow for advanced
    * SFINAE (substitution failure is not an error) tricks used to specialise
    * this class for arbitrary STL containers and maps.
+   *
+   * @author Luca Heltai, 2017
    */
   template <class T, class Enable = void>
   struct Convert
@@ -136,6 +138,10 @@ namespace PatternTools
     /**
      * Return a std::unique_ptr to a Pattern that can be used to interpret a
      * string as the type of the template argument, and the other way around.
+     *
+     * While the current function (in the general Convert template) is deleted,
+     * it is implemented and available in the specializations of the Convert
+     * class template for particular kinds of template arguments @p T.
      */
     static std::unique_ptr<Patterns::PatternBase> to_pattern() = delete;
 
@@ -144,7 +150,9 @@ namespace PatternTools
      * pattern passed to perform the conversion, or create and use a default
      * one.
      *
-     * The created string is
+     * While the current function (in the general Convert template) is deleted,
+     * it is implemented and available in the specializations of the Convert
+     * class template for particular kinds of template arguments @p T.
      */
     static std::string to_string(const T &s,
                                  const std::unique_ptr<Patterns::PatternBase>
@@ -153,6 +161,10 @@ namespace PatternTools
     /**
      * Convert a string to a value, using the given pattern. Use the pattern
      * passed to perform the conversion, or create and use a default one.
+     *
+     * While the current function (in the general Convert template) is deleted,
+     * it is implemented and available in the specializations of the Convert
+     * class template for particular kinds of template arguments @p T.
      */
     static T to_value(const std::string &s,
                       const std::unique_ptr<Patterns::PatternBase> &p =
@@ -217,10 +229,10 @@ namespace PatternTools
      * map. A class with map_rank::value = 0 is either a List compatible
      * class, or an elementary type.
      *
-     * Elementary types are not compatible with Patterns::List, but
-     * non elementary types, like Point(), or std::complex<double>, are
-     * compatible with the List type. Adding more compatible types is a matter
-     * of adding a specialization of this struct for the given type.
+     * Elementary types are not compatible with Patterns::List, but non
+     * elementary types, like Point(), or std::complex<double>, are compatible
+     * with the List type. Adding more compatible types is a matter of adding a
+     * specialization of this struct for the given type.
      *
      * @author Luca Heltai, 2017
      */
@@ -275,6 +287,13 @@ namespace PatternTools
         }
       else
         is >> value;
+
+      // If someone passes "123 abc" to the function, the method yelds an
+      // integer 123 alright, but the space terminates the read from the string
+      // although there is more to come. This case, however, is checked for in
+      // the call p->match(s) at the beginning of this function, and would
+      // throw earlier. Here it is safe to assume that if we didn't fail the
+      // conversion with the operator >>, then we are good to go.
       AssertThrow(!is.fail(),
                   ExcMessage("Failed to convert from \"" + s +
                              "\" to the type \"" +
@@ -368,6 +387,13 @@ namespace PatternTools
       static constexpr int list_rank = RankInfo<Number>::list_rank + 1;
       static constexpr int map_rank = RankInfo<Number>::map_rank;
     };
+
+    template <class Key, class Value>
+    struct RankInfo<std::pair<Key,Value>>
+    {
+      static constexpr int list_rank = std::max(RankInfo<Key>::list_rank, RankInfo<Value>::list_rank);
+      static constexpr int map_rank = std::max(RankInfo<Key>::map_rank, RankInfo<Value>::map_rank)+1;
+    };
   }
 
   // stl containers
@@ -412,9 +438,6 @@ namespace PatternTools
       return s;
     }
 
-    /**
-     * Convert a string to a value, using the given pattern, or a default one.
-     */
     static T to_value(const std::string &s,
                       const std::unique_ptr<Patterns::PatternBase> &pattern =
                         Convert<T>::to_pattern())
@@ -463,7 +486,6 @@ namespace PatternTools
                                  const std::unique_ptr<Patterns::PatternBase>
                                  &pattern = Convert<T>::to_pattern())
     {
-
       auto p = dynamic_cast<const Patterns::Map *>(pattern.get());
       AssertThrow(
         p,
@@ -706,6 +728,48 @@ namespace PatternTools
     }
   };
 
+
+  // Pairs
+  template <class Key, class Value>
+  struct Convert<std::pair<Key,Value>>
+  {
+    typedef std::pair<Key,Value> T;
+
+    static std::unique_ptr<Patterns::PatternBase> to_pattern()
+    {
+      static_assert(internal::RankInfo<T>::map_rank > 0,
+                    "Cannot use this class for non Map-compatible types.");
+      return std_cxx14::make_unique<Patterns::Map>(
+               *Convert<Key>::to_pattern(),
+               *Convert<Value>::to_pattern(),
+               1, 1,
+               // We keep the same list separator of the previous level, as this is
+               // a map with only 1 possible entry
+               internal::default_list_separator[internal::RankInfo<T>::list_rank],
+               internal::default_map_separator[internal::RankInfo<T>::map_rank - 1]);
+    }
+
+    static std::string to_string(const T &t,
+                                 const std::unique_ptr<Patterns::PatternBase>
+                                 &pattern = Convert<T>::to_pattern())
+    {
+      std::unordered_map<Key, Value> m;
+      m.insert(t);
+      std:: string s = Convert<decltype(m)>::to_string(m, pattern);
+      AssertThrow(pattern->match(s), ExcNoMatch(s, *pattern));
+      return s;
+    }
+
+    static T to_value(const std::string &s,
+                      const std::unique_ptr<Patterns::PatternBase> &pattern =
+                        Convert<T>::to_pattern())
+    {
+      std::unordered_map<Key, Value> m;
+      m = Convert<decltype(m)>::to_value(s, pattern);
+      return *m.begin();
+    }
+  };
+
   template <class ParameterType>
   void add_parameter(const std::string &entry,
                      ParameterType &parameter,
index 00f015fce2683e306e5d7b7f50259ce6df09d284..4c9ee966216613bd195f0ed87db4e82a579d34d1 100644 (file)
@@ -60,6 +60,7 @@ int main()
   Tensor<3,3> t53;
 
   std::complex<double> t6(1,2);
+  auto t7 = std::make_pair(1, 2.0);
 
   test(t0);
   test(t1);
@@ -68,6 +69,7 @@ int main()
   test(t4);
   test(t5);
   test(t6);
+  test(t7);
   test(t32);
   test(t42);
   test(t52);
index be28c44a3612ff0635fd37235a9f7f23b6b89639..1db60afdd56b1d887f6227dfb64b40746569a7ef 100644 (file)
@@ -20,6 +20,9 @@ DEAL::To value : 0.000000, 0.000000, 0.000000
 DEAL::Pattern  : [List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 2...2 (inclusive)]
 DEAL::To String: 1.000000, 2.000000
 DEAL::To value : 1.000000, 2.000000
+DEAL::Pattern  : [Map of <[Integer range -2147483648...2147483647 (inclusive)]>:<[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 1...1 (inclusive)]
+DEAL::To String: 1:2.000000
+DEAL::To value : 1:2.000000
 DEAL::Pattern  : [List of <[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 1...1 (inclusive)]> of length 1...1 (inclusive) separated by <;>]
 DEAL::To String: 0.000000
 DEAL::To value : 0.000000

In the beginning the Universe was created. This has made a lot of people very angry and has been widely regarded as a bad move.

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.