]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Patterns for arithmetic types and container types.
authorLuca Heltai <luca.heltai@sissa.it>
Tue, 18 Jul 2017 18:15:12 +0000 (20:15 +0200)
committerLuca Heltai <luca.heltai@sissa.it>
Sun, 23 Jul 2017 14:57:13 +0000 (16:57 +0200)
include/deal.II/base/patterns_tools.h
source/base/patterns_tools.cc

index cc4bb028a1cbd5bccdcd84e42fdb6d62b14750bc..92549022b9528abc94d5359d91f4ca77c905c917 100644 (file)
@@ -45,6 +45,55 @@ DEAL_II_NAMESPACE_OPEN
 namespace PatternsTools
 {
   using namespace Patterns;
+
+
+  /**
+   * Store information about the rank types of the given class.
+   *
+   * A class has Rank equal to the number of different separators
+   * that are required to specify its element(s) in a string.
+   *
+   * This class is used to detect wether the class T is compatible
+   * with a Patterns::List pattern or with a Patterns::Map pattern, and
+   * to choose among a default list of separators for complex types,
+   * like vectors of vectors.
+   *
+   * Objects like Point<dim> or std::complex<double> are vector-likes, and
+   * have vector_rank 1. Elementary types, like `int`, `unsigned int`, `double`, etc.
+   * have vector_rank 0. `std::vector`, `std::list` and in general containers have rank
+   * equal to 1 + vector_rank of the contained type. Similarly for map types.
+   *
+   * A class with vector_rank_type::value = 0 is either elementary or a
+   * map. A class with map_rank_type::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<dim>(), 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.
+   */
+  template<class T>
+  struct RankInfo
+  {
+    typedef std::integral_constant<int, 0>::type vector_rank_type;
+  };
+
+
+  /**
+   * Return the default list separator for an object with the given vector rank.
+   *
+   * Objects like Point<dim> or std::complex<double> are vector-likes, and
+   * have rank 1. Elementary types, like `int`, `unsigned int`, `double`, etc.
+   * have rank 0. `std::vector`, `std::list` and in general containers have rank
+   * equal to 1 + rank of the contained type.
+   *
+   * This function helps in constructing patterns for non elementary types,
+   * like for example std::vector<std::vector<std::complex<double>>>.
+   */
+  std::string default_list_separator(unsigned int);
+
+
+
   /**
    * Converter class. This class is used to generate strings and Patterns associated to
    * the given type, and to convert from a string to the given type and viceversa.
@@ -75,6 +124,19 @@ namespace PatternsTools
                       std::unique_ptr<PatternBase> p = Convert<T>::to_pattern()) = delete;
   };
 
+  /**
+   * @addtogroup Exceptions
+   * @{
+   */
+
+  /**
+   * Exception.
+   */
+  DeclException2 (ExcNoMatch,
+                  std::string, PatternBase &,
+                  << "The string " << arg1 << " does not match the pattern \""
+                  << arg2.description() << "\"");
+  //@}
 
 }
 
@@ -83,33 +145,113 @@ namespace PatternsTools
 namespace PatternsTools
 {
   template<class T>
-  struct Convert<T, typename std::enable_if<std::is_integral<T>::value>::type>
+  struct Convert<T, typename std::enable_if<std::is_arithmetic<T>::value>::type>
   {
 
     static std::unique_ptr<PatternBase> to_pattern()
     {
-      return std_cxx14::make_unique<Integer>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
+      if(std::is_integral<T>::value)
+        return std_cxx14::make_unique<Integer>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
+      else if(std::is_floating_point<T>::value)
+        return std_cxx14::make_unique<Double>(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
+      else {
+        AssertThrow(false, ExcNotImplemented());
+        return std::unique_ptr<PatternBase>();
+        }
     }
 
     static std::string to_string(const T &value, std::unique_ptr<PatternBase> p = Convert<T>::to_pattern())
     {
       std::stringstream str;
       str << value;
-      AssertThrow(p->match(str.str()), ExcMessage("No match"));
+      AssertThrow(p->match(str.str()), ExcNoMatch(str.str(), *p));
       return str.str();
     }
 
     static T to_value(const std::string &s,
                       std::unique_ptr<PatternBase> p = Convert<T>::to_pattern())
     {
-      AssertThrow(p->match(s), ExcMessage("No match"));
+      AssertThrow(p->match(s), ExcNoMatch(s, *p));
       std::istringstream is(s);
       T i;
       is >> i;
-      AssertThrow(!is.fail(), ExcMessage("Failed to convert"));
+      AssertThrow(!is.fail(), ExcMessage("Failed to convert from \"" + s + "\" to the type \""
+                                         +boost::core::demangle(typeid(T).name()) + "\""));
       return i;
     }
   };
+
+  // Rank of vector types
+  template<template <class T1, class A1> class Container, class T, class Allocator>
+  struct RankInfo<Container<T,Allocator>>
+  {
+    typedef typename std::integral_constant<int, RankInfo<T>::vector_rank_type::value+1>::type vector_rank_type;
+  };
+
+
+
+
+
+  template<template <class T1, class A1> class Container, class T, class Allocator>
+  struct Convert<Container<T,Allocator>>
+  {
+    static std::unique_ptr<PatternBase> to_pattern()
+    {
+      return std_cxx14::make_unique<List>(*Convert<Container<T,Allocator>>::to_pattern(),
+                                          0, std::numeric_limits<int>::max,
+                                          default_list_separator(RankInfo<Container<T,Allocator>>::vector_rank_type::value));
+    }
+
+    static std::string to_string(const Container<T,Allocator> &t,
+                                 std::unique_ptr<PatternBase> pattern = Convert<Container<T,Allocator>>::to_pattern())
+    {
+
+      auto p = dynamic_cast<const Patterns::List *>(pattern.get());
+      AssertThrow(p, ExcMessage("I need a List pattern to convert a string to a List type."));
+      auto base_p = p->get_base_pattern().clone();
+      std::vector<std::string> vec(t.size());
+
+      unsigned int i=0;
+      for (auto &ti : t)
+        vec[i++] = Convert<T>::to_string(ti, base_p);
+
+      std::string s;
+      if (vec.size() > 0)
+        s = vec[0];
+      for (unsigned int i=1; i<vec.size(); ++i)
+        s += p->get_separator() + " " + vec[i];
+
+      Assert(p->match(s), ExcMessage("No match for " + s +
+                                     " with pattern " + p->description()));
+      return s;
+    }
+
+    /**
+     * Convert a string to a value, using the given pattern, or a default one.
+     */
+    static Container<T,Allocator>  to_value(const std::string &s,
+                                            std::unique_ptr<PatternBase> pattern = Convert<Container<T,Allocator>>::to_pattern())
+    {
+
+      AssertThrow(pattern->match(s), ExcMessage("No match for " + s +
+                                                " using pattern " + pattern->description()));
+
+      auto p = dynamic_cast<const Patterns::List *>(pattern.get());
+      AssertThrow(p, ExcMessage("I need a List pattern to convert a string to a List type."));
+
+      auto base_p = p->get_base_pattern().clone();
+      Container<T,Allocator> t;
+
+      auto v = Utilities::split_string_list(s,p->get_separator());
+      for (auto str : v)
+        t.insert(t.end(), Convert<T>::to_value(str, base_p));
+
+      return t;
+    }
+  };
+
+
+
 }
 
 DEAL_II_NAMESPACE_CLOSE
index 6612fdd0c439c145b297e9c64a1ce6cbb8d64e62..638c7de2063fe7c126383311e10ad19a88b74da5 100644 (file)
@@ -41,7 +41,7 @@ DEAL_II_NAMESPACE_OPEN
 
 //TODO[WB]: various functions here could be simplified by using namespace Utilities
 
-namespace Patterns
+namespace PatternsTools
 {
 
 

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.