From e1bc9888d211e45af37c583879b6e31e8af42147 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Wed, 19 Jul 2017 20:56:00 +0200 Subject: [PATCH] Added tensor and point types. Moved some functions to internal namespaces. --- include/deal.II/base/patterns_tools.h | 378 +++++++++++++++++++------- source/base/parameter_handler.cc | 3 +- 2 files changed, 277 insertions(+), 104 deletions(-) diff --git a/include/deal.II/base/patterns_tools.h b/include/deal.II/base/patterns_tools.h index 23b51d1a49..b15f5569d9 100644 --- a/include/deal.II/base/patterns_tools.h +++ b/include/deal.II/base/patterns_tools.h @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -50,74 +51,85 @@ DEAL_II_NAMESPACE_OPEN +using namespace Patterns; /** - * Namespace for a few class and functions that act on values and patterns. + * Namespace for a few classes and functions that act on values and patterns, and + * allow to convert from non elementary types to strings and viceversa. + * + * A typical usage of these tools is in the following example: + * + * @code + * typedef std::vector T; + * + * T vec(3); + * vec[0] = 1; + * vec[1] = 3; + * vec[2] = 5; + * + * auto pattern = PatternsTools::Convert::to_pattern(); + * + * std::cout << pattern->description() << std::endl; + * // [List of <[Integer]> of length 0...4294967295 (inclusive)] + * + * auto s = PatternsTools::Convert::to_string(vec); + * std::cout << s << std::endl; + * // 1, 2, 3 + * + * auto vec = PatternsTools::Convert::to_value("2,3,4,5"); + * // now vec has size 4, and contains the elements 2,3,4,5 + * + * std::cout << internal::RankInfo::list_rank << std::endl; // Outputs 1 + * std::cout << internal::RankInfo::map_rank << std::endl; // Outputs 0 + * @endcode + * + * Convert is used by the function PatternsTools::add_parameter() in this + * namespace. Internally it uses the internal::RankInfo class to decide how + * many different separators are required to convert the given type to a string. + * + * For example, to write vectors of vectors, the default is to use "," for the first + * (inner) separator, and ";" for the second (outer) separator, i.e. + * + * @code + * std::vector> vec; + * vec = Convert::to_value("1,2,3 ; 4,5,6"); + * + * s = convert::to_string(vec[0]); + * // s now contains the string "1,2,3" + * @endcode + * + * Separators for List and Map compatible types are selected according to the + * rank of the list and map objects, using the arrays + * PatternsTools::internal::default_list_separator and + * PatternsTools::internal::default_map_separator. + * + * They are currently set to: + * + * @code + * default_list_separator{{" ", "," , ";" , "|" , "%"}}; + * default_map_separator {{" ", ":" , "=" , "@" , "#"}}; + * @endcode + * + * When one needs a mixture of Lists and Map types, their RankInfo is computed by taking + * the maximum of the vector_rank of the Key and of the Value type, so that, for example, + * it is possible to have the following + * @code + * ... // Build compare class + * std::map, std::vector, compare> map; + * + * map = convert::to_value("1,2,3 : 5.0,6.0,7.0 ; 8,9,10 : 11.0,12.0,13.0"); + * + * @endcode + * + * Some non elementary types are supported, like Point(), or std::complex. + * If you wish to support more types, you have to specialize the Convert struct as well + * as the RankInfo struct. * * @ingroup input + * @author Luca Heltai, 2017 */ 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 or std::complex 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(), or std::complex, 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 - struct RankInfo - { - typedef std::integral_constant::type vector_rank_type; - typedef std::integral_constant::type map_rank_type; - }; - - - /** - * Return the default list separator for an object with the given vector rank. - * - * Objects like Point or std::complex 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::string default_list_separator(unsigned int); - - - - /** - * Return the default map separator for an object with the given map rank. - * - * This function helps in constructing patterns for non elementary types, - * like for example std::map> - */ - std::string default_map_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. @@ -136,13 +148,16 @@ namespace PatternsTools /** * Return a string containing a textual version of the variable s. Use the pattern * passed to perform the conversion, or create and use a default one. + * + * The created string is */ static std::string to_string(const T &s, const std::unique_ptr &p = Convert::to_pattern()) = delete; /** - * Convert a string to a value, using the given pattern, or a default one. + * 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. */ static T to_value(const std::string &s, const std::unique_ptr &p = Convert::to_pattern()) = delete; @@ -177,7 +192,40 @@ namespace PatternsTools << "The string " << arg1 << " does not match the pattern \"" << arg2.description() << "\""); //@} - + namespace internal + { + /** + * 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 uniquely identify 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. + * + * Objects like Point or std::complex 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 list_rank::value = 0 is either elementary or a + * 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, 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 + */ + template + struct RankInfo + { + static constexpr int list_rank = 0; + static constexpr int map_rank = 0; + }; + } } // ---------------------- inline and template functions -------------------- @@ -193,7 +241,7 @@ namespace PatternsTools if (std::is_integral::value) return std_cxx14::make_unique(std::numeric_limits::min(), std::numeric_limits::max()); else if (std::is_floating_point::value) - return std_cxx14::make_unique(std::numeric_limits::min(), std::numeric_limits::max()); + return std_cxx14::make_unique(-std::numeric_limits::max(), std::numeric_limits::max()); else { AssertThrow(false, ExcNotImplemented()); @@ -203,10 +251,13 @@ namespace PatternsTools static std::string to_string(const T &value, const std::unique_ptr &p = Convert::to_pattern()) { - std::stringstream str; - str << value; - AssertThrow(p->match(str.str()), ExcNoMatch(str.str(), *p)); - return str.str(); + std::string str; + if (std::is_same()) + str = std::to_string((int)value); + else + str = std::to_string(value); + AssertThrow(p->match(str), ExcNoMatch(str, *p)); + return str; } static T to_value(const std::string &s, @@ -214,17 +265,28 @@ namespace PatternsTools { AssertThrow(p->match(s), ExcNoMatch(s, *p)); std::istringstream is(s); - T i; - is >> i; + T value; + if (std::is_same::value) + { + int i; + is >> i; + value=i; + } + else + is >> value; AssertThrow(!is.fail(), ExcMessage("Failed to convert from \"" + s + "\" to the type \"" +boost::core::demangle(typeid(T).name()) + "\"")); - return i; + return value; } }; - //specialize a type for all of the STL containers and maps + namespace internal { + const std::array default_list_separator {{" ", "," , ";" , "|" , "%"}}; + const std::array default_map_separator {{" ", ":" , "=" , "@" , "#"}}; + + //specialize a type for all of the STL containers and maps template struct is_stl_container:std::false_type {}; template struct is_stl_container> :std::true_type {}; template struct is_stl_container>:std::true_type {}; @@ -258,26 +320,39 @@ namespace PatternsTools static constexpr bool const value = internal::is_stl_map>::value; }; - - // Rank of vector types - template - struct RankInfo::value>::type > + namespace internal { - typedef typename std::integral_constant::vector_rank_type::value+1>::type vector_rank_type; - typedef typename std::integral_constant::type map_rank_type; - }; + // Rank of vector types + template + struct RankInfo::value>::type > + { + static constexpr int list_rank = RankInfo::list_rank + 1; + static constexpr int map_rank = RankInfo::map_rank; + }; - // Rank of vector types - template - struct RankInfo::value>::type > - { - typedef typename std::integral_constant::vector_rank_type::value, - RankInfo::vector_rank_type::value)+1>::type vector_rank_type; - typedef typename std::integral_constant::map_rank_type::value, - RankInfo::map_rank_type::value)+1>::type map_rank_type; - }; + // Rank of map types + template + struct RankInfo::value>::type > + { + static constexpr int list_rank = std::max(RankInfo::list_rank, + RankInfo::list_rank) + 1; + static constexpr int map_rank = std::max(RankInfo::map_rank, + RankInfo::map_rank) + 1; + }; + + // Rank of Tensor types + template + struct RankInfo> + { + static constexpr int list_rank = rank + RankInfo::list_rank; + static constexpr int map_rank = RankInfo::map_rank; + }; + template + struct RankInfo>:RankInfo> {}; + + } template @@ -286,8 +361,9 @@ namespace PatternsTools static std::unique_ptr to_pattern() { return std_cxx14::make_unique(*Convert::to_pattern(), - 0, std::numeric_limits::max(), - default_list_separator(RankInfo::vector_rank_type::value)); + std::numeric_limits::min(), + std::numeric_limits::max(), + internal::default_list_separator[internal::RankInfo::list_rank]); } static std::string to_string(const T &t, @@ -309,8 +385,7 @@ namespace PatternsTools for (unsigned int i=1; iget_separator() + " " + vec[i]; - Assert(p->match(s), ExcMessage("No match for " + s + - " with pattern " + p->description())); + AssertThrow(pattern->match(s), ExcNoMatch(s, *p)); return s; } @@ -321,8 +396,7 @@ namespace PatternsTools const std::unique_ptr &pattern = Convert::to_pattern()) { - AssertThrow(pattern->match(s), ExcMessage("No match for " + s + - " using pattern " + pattern->description())); + AssertThrow(pattern->match(s), ExcNoMatch(s, *pattern)); auto p = dynamic_cast(pattern.get()); AssertThrow(p, ExcMessage("I need a List pattern to convert a string to a List type.")); @@ -347,8 +421,8 @@ namespace PatternsTools return std_cxx14::make_unique(*Convert::to_pattern(), *Convert::to_pattern(), 0, std::numeric_limits::max(), - default_list_separator(RankInfo::vector_rank_type::value), - default_map_separator(RankInfo::map_rank_type::value) + internal::default_list_separator[internal::RankInfo::list_rank], + internal::default_map_separator[internal::RankInfo::map_rank] ); } @@ -375,20 +449,15 @@ namespace PatternsTools for (unsigned int i=1; iget_separator() + " " + vec[i]; - Assert(p->match(s), ExcMessage("No match for " + s + - " with pattern " + p->description())); + AssertThrow(p->match(s), ExcNoMatch(s, *p)); 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 &pattern = Convert::to_pattern()) { - AssertThrow(pattern->match(s), ExcMessage("No match for " + s + - " using pattern " + pattern->description())); + AssertThrow(pattern->match(s), ExcNoMatch(s, *pattern)); auto p = dynamic_cast(pattern.get()); AssertThrow(p, ExcMessage("I need a Map pattern to convert a string to a List type.")); @@ -410,8 +479,111 @@ namespace PatternsTools } }; + + template + struct Convert> + { + typedef Tensor T; + static std::unique_ptr to_pattern() + { + return std_cxx14::make_unique(*Convert::to_pattern(), + dim, dim, + internal::default_list_separator[internal::RankInfo::list_rank]); + } + + static std::string to_string(const T &t, + const std::unique_ptr &pattern = Convert::to_pattern()) + { + + auto p = dynamic_cast(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 vec(dim); + + for (unsigned int i=0; i::to_string(t[i], base_p); + + std::string s; + if (vec.size() > 0) + s = vec[0]; + for (unsigned int i=1; iget_separator() + " " + vec[i]; + + AssertThrow(p->match(s), ExcNoMatch(s, *p)); + return s; + } + + static T to_value(const std::string &s, + const std::unique_ptr &pattern = Convert::to_pattern()) + { + + AssertThrow(pattern->match(s), ExcNoMatch(s, *pattern)); + + auto p = dynamic_cast(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(); + T t; + + auto v = Utilities::split_string_list(s,p->get_separator()); + unsigned int i=0; + for (auto str : v) + t[i++] = Convert::to_value(str, base_p); + + return t; + } + }; + + + template + struct Convert> + { + + typedef Point T; + + static std::unique_ptr to_pattern() + { + return Convert>::to_pattern(); + } + + static std::string to_string(const T &t, + const std::unique_ptr &pattern = Convert::to_pattern()) + { + return Convert>::to_string(Tensor<1,dim,Number>(t),pattern); + } + + static T to_value(const std::string &s, + const std::unique_ptr &pattern = Convert::to_pattern()) + { + return T(Convert>::to_value(s,pattern)); + } + }; + + + template + void add_parameter(const std::string &entry, + ParameterType ¶meter, + ParameterHandler &prm, + const std::string &documentation, + const Patterns::PatternBase &pattern) + { + + static_assert(std::is_const::value == false, + "You tried to add a parameter using a type " + "that is const. Use a non-const type."); + + prm.declare_entry(entry, PatternsTools::Convert::to_string(parameter, pattern.clone()), + pattern, documentation); + + auto action = [&] (const std::string &val) + { + parameter = PatternsTools::Convert::to_value(val, pattern.clone()); + }; + prm.add_action(entry, action); + } } + DEAL_II_NAMESPACE_CLOSE #endif diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index 5aab9be8f7..c8626df734 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -305,7 +305,8 @@ namespace Patterns std::istringstream str(test_string); double d; - if (!(str >> d)) + str >> d; + if (str.fail()) return false; if (!has_only_whitespace (str)) -- 2.39.5