From 807dfe5cda29377fad1222183c126942f1bfef06 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 20 Jul 2017 18:37:57 +0200 Subject: [PATCH] Moved Patterns namespace in its own file. --- include/deal.II/base/parameter_handler.h | 906 +-------------- include/deal.II/base/patterns.h | 946 +++++++++++++++ source/base/CMakeLists.txt | 1 + source/base/parameter_handler.cc | 1315 --------------------- source/base/patterns.cc | 1358 ++++++++++++++++++++++ 5 files changed, 2306 insertions(+), 2220 deletions(-) create mode 100644 include/deal.II/base/patterns.h create mode 100644 source/base/patterns.cc diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index d0806054dc..14c5f833c9 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -37,911 +38,6 @@ DEAL_II_NAMESPACE_OPEN class LogStream; class MultipleParameterLoop; -/** - * Namespace for a few classes that act as patterns for the ParameterHandler - * class. These classes implement an interface that checks whether a parameter - * in an input file matches a certain pattern, such as "being boolean", "an - * integer value", etc. - * - * @ingroup input - */ -namespace Patterns -{ - - /** - * Base class to declare common interface. The purpose of this class is - * mostly to define the interface of patterns, and to force derived classes - * to have a clone function. It is thus, in the languages of the - * "Design Patterns" book (Gamma et al.), a "prototype". - */ - class PatternBase - { - public: - /** - * Make destructor of this and all derived classes virtual. - */ - virtual ~PatternBase (); - - /** - * Return true if the given string matches the pattern. - */ - virtual bool match (const std::string &test_string) const = 0; - - /** - * List of possible description output formats. - * - * Capitalization chosen for similarity to ParameterHandler::OutputStyle. - */ - enum OutputStyle - { - /** - * Simple text suitable for machine parsing in the static public member - * functions for all of the built in inheriting classes. - * - * Preferably human readable, but machine parsing is more critical. - */ - Machine, - /** - * Easily human readable plain text format suitable for plain text - * documentation. - */ - Text, - /** - * Easily human readable LaTeX format suitable for printing in manuals. - */ - LaTeX - }; - - /** - * Return a string describing the pattern. - */ - virtual std::string description (const OutputStyle style=Machine) const = 0; - - /** - * Return a pointer to an exact copy of the object. This is necessary - * since we want to store objects of this type in containers, were we need - * to copy objects without knowledge of their actual data type (we only - * have pointers to the base class). - * - * Ownership of the objects returned by this function is passed to the - * caller of this function. - */ - virtual std::unique_ptr clone () const = 0; - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. To avoid unnecessary overhead, we do not force derived classes - * to provide this function as a virtual overloaded one, but rather try to - * cast the present object to one of the known derived classes and if that - * fails then take the size of this base class instead and add 32 byte - * (this value is arbitrary, it should account for virtual function - * tables, and some possible data elements). Since there are usually not - * many thousands of objects of this type around, and since the - * memory_consumption mechanism is used to find out where memory in the - * range of many megabytes is, this seems like a reasonable approximation. - * - * On the other hand, if you know that your class deviates from this - * assumption significantly, you can still overload this function. - */ - virtual std::size_t memory_consumption () const; - }; - - /** - * Return pointer to the correct derived class based on description. - */ - std::unique_ptr pattern_factory (const std::string &description); - - /** - * Test for the string being an integer. If bounds are given to the - * constructor, then the integer given also needs to be within the interval - * specified by these bounds. Note that unlike common convention in the C++ - * standard library, both bounds of this interval are inclusive; the reason - * is that in practice in most cases, one needs closed intervals, but these - * can only be realized with inclusive bounds for non-integer values. We - * thus stay consistent by always using closed intervals. - * - * If the upper bound given to the constructor is smaller than the - * lower bound, then every integer is allowed. - * - * Giving bounds may be useful if for example a value can only be positive - * and less than a reasonable upper bound (for example the number of - * refinement steps to be performed), or in many other cases. - */ - class Integer : public PatternBase - { - public: - /** - * Minimal integer value. If the numeric_limits class is available use - * this information to obtain the extremal values, otherwise set it so - * that this class understands that all values are allowed. - */ - static const int min_int_value; - - /** - * Maximal integer value. If the numeric_limits class is available use - * this information to obtain the extremal values, otherwise set it so - * that this class understands that all values are allowed. - */ - static const int max_int_value; - - /** - * Constructor. Bounds can be specified within which a valid - * parameter has to be. If the upper bound is smaller than the - * lower bound, then the entire set of integers is implied. The - * default values are chosen such that no bounds are enforced on - * parameters. - */ - Integer (const int lower_bound = min_int_value, - const int upper_bound = max_int_value); - - /** - * Return true if the string is an integer and its value is - * within the specified range. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. If bounds were specified to the constructor, then include them - * into this description. - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create (const std::string &description); - - private: - /** - * Value of the lower bound. A number that satisfies the - * @ref match - * operation of this class must be equal to this value or larger, if the - * bounds of the interval for a valid range. - */ - const int lower_bound; - - /** - * Value of the upper bound. A number that satisfies the - * @ref match - * operation of this class must be equal to this value or less, if the - * bounds of the interval for a valid range. - */ - const int upper_bound; - - /** - * Initial part of description - */ - static const char *description_init; - }; - - /** - * Test for the string being a double. If bounds are given to the - * constructor, then the integer given also needs to be within the interval - * specified by these bounds. Note that unlike common convention in the C++ - * standard library, both bounds of this interval are inclusive; the reason - * is that in practice in most cases, one needs closed intervals, but these - * can only be realized with inclusive bounds for non-integer values. We - * thus stay consistent by always using closed intervals. - * - * If the upper bound given to the constructor is smaller than the - * lower bound, then every double precision number is allowed. - * - * Giving bounds may be useful if for example a value can only be positive - * and less than a reasonable upper bound (for example damping parameters - * are frequently only reasonable if between zero and one), or in many other - * cases. - */ - class Double : public PatternBase - { - public: - /** - * Minimal double value used as default value, taken from - * std::numeric_limits. - */ - static const double min_double_value; - - /** - * Maximal double value used as default value, taken from - * std::numeric_limits. - */ - static const double max_double_value; - - /** - * Constructor. Bounds can be specified within which a valid - * parameter has to be. If the upper bound is smaller than the - * lower bound, then the entire set of double precision numbers is - * implied. The default values are chosen such that no bounds are - * enforced on parameters. - */ - Double (const double lower_bound = min_double_value, - const double upper_bound = max_double_value); - - /** - * Return true if the string is a number and its value is within - * the specified range. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. If bounds were specified to the constructor, then include them - * into this description. - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates a new object on the heap using @p new if the given - * @p description is a valid format (for example created by calling - * description() on an existing object), or @p nullptr otherwise. Ownership - * of the returned object is transferred to the caller of this function, - * which should be freed using @p delete. - */ - static std::unique_ptr create(const std::string &description); - - private: - /** - * Value of the lower bound. A number that satisfies the - * @ref match - * operation of this class must be equal to this value or larger, if the - * bounds of the interval form a valid range. - */ - const double lower_bound; - - /** - * Value of the upper bound. A number that satisfies the - * @ref match - * operation of this class must be equal to this value or less, if the - * bounds of the interval form a valid range. - */ - const double upper_bound; - - /** - * Initial part of description - */ - static const char *description_init; - }; - - /** - * Test for the string being one of a sequence of values given like a - * regular expression. For example, if the string given to the constructor - * is "red|blue|black", then the - * @ref match - * function returns true exactly if the string is either "red" or - * "blue" or "black". Spaces around the pipe signs do not matter and are - * eliminated. - */ - class Selection : public PatternBase - { - public: - /** - * Constructor. Take the given parameter as the specification of valid - * strings. - */ - Selection (const std::string &seq); - - /** - * Return true if the string is an element of the description - * list passed to the constructor. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. Here, this is the list of valid strings passed to the - * constructor. - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. - */ - std::size_t memory_consumption () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create (const std::string &description); - - private: - /** - * List of valid strings as passed to the constructor. We don't make this - * string constant, as we process it somewhat in the constructor. - */ - std::string sequence; - - /** - * Initial part of description - */ - static const char *description_init; - }; - - - /** - * This pattern matches a list of values separated by commas (or another - * string), each of which have to match a pattern given to the constructor. - * With two additional parameters, the number of elements this list has to - * have can be specified. If none is specified, the list may have zero or - * more entries. - */ - class List : public PatternBase - { - public: - /** - * Maximal integer value. If the numeric_limits class is available use - * this information to obtain the extremal values, otherwise set it so - * that this class understands that all values are allowed. - */ - static const unsigned int max_int_value; - - /** - * Constructor. Take the given parameter as the specification of valid - * elements of the list. - * - * The three other arguments can be used to denote minimal and maximal - * allowable lengths of the list, and the string that is used as a - * separator between elements of the list. - */ - List (const PatternBase &base_pattern, - const unsigned int min_elements = 0, - const unsigned int max_elements = max_int_value, - const std::string &separator = ","); - - - /** - * Return the internally stored separator. - */ - const std::string &get_separator() const; - - /** - * Return the internally stored base pattern. - */ - const PatternBase &get_base_pattern() const; - - /** - * Copy constructor. - */ - List (const List &other); - - /** - * Return true if the string is a comma-separated list of strings - * each of which match the pattern given to the constructor. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create (const std::string &description); - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. - */ - std::size_t memory_consumption () const; - - /** - * @addtogroup Exceptions - * @{ - */ - - /** - * Exception. - */ - DeclException2 (ExcInvalidRange, - int, int, - << "The values " << arg1 << " and " << arg2 - << " do not form a valid range."); - //@} - private: - /** - * Copy of the pattern that each element of the list has to satisfy. - */ - std::unique_ptr pattern; - - /** - * Minimum number of elements the list must have. - */ - const unsigned int min_elements; - - /** - * Maximum number of elements the list must have. - */ - const unsigned int max_elements; - - /** - * Separator between elements of the list. - */ - const std::string separator; - - /** - * Initial part of description - */ - static const char *description_init; - }; - - - /** - * This pattern matches a list of comma-separated values each of which - * denotes a pair of key and value. Both key and value have to match a - * pattern given to the constructor. For each entry of the map, parameters - * have to be entered in the form key: value. In other words, a - * map is described in the form key1: value1, key2: value2, key3: - * value3, .... Two constructor arguments allow to choose a delimiter - * between pairs other than the comma, and a delimeter between key and value - * other than column. - * - * With two additional parameters, the number of elements this list has to - * have can be specified. If none is specified, the map may have zero or - * more entries. - */ - class Map : public PatternBase - { - public: - /** - * Maximal integer value. If the numeric_limits class is available use - * this information to obtain the extremal values, otherwise set it so - * that this class understands that all values are allowed. - */ - static const unsigned int max_int_value; - - /** - * Constructor. Take the given parameter as the specification of valid - * elements of the list. - * - * The four other arguments can be used to denote minimal and maximal - * allowable lengths of the list as well as the separators used to delimit - * pairs of the map and the symbol used to separate keys and values. - */ - Map (const PatternBase &key_pattern, - const PatternBase &value_pattern, - const unsigned int min_elements = 0, - const unsigned int max_elements = max_int_value, - const std::string &separator = ",", - const std::string &key_value_separator = ":"); - - /** - * Copy constructor. - */ - Map (const Map &other); - - /** - * Return true if the string is a comma-separated list of strings - * each of which match the pattern given to the constructor. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create (const std::string &description); - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. - */ - std::size_t memory_consumption () const; - - /** - * Return a reference to the key pattern. - */ - const PatternBase &get_key_pattern() const; - - /** - * Return a reference to the value pattern. - */ - const PatternBase &get_value_pattern() const; - - /** - * Return the separator of the map entries. - */ - const std::string &get_separator() const; - - /** - * Return the key-value separator. - */ - const std::string &get_key_value_separator() const; - - /** - * @addtogroup Exceptions - * @{ - */ - - /** - * Exception. - */ - DeclException2 (ExcInvalidRange, - int, int, - << "The values " << arg1 << " and " << arg2 - << " do not form a valid range."); - //@} - private: - /** - * Copy of the patterns that each key and each value of the map has to - * satisfy. - */ - std::unique_ptr key_pattern; - std::unique_ptr value_pattern; - - /** - * Minimum number of elements the list must have. - */ - const unsigned int min_elements; - - /** - * Maximum number of elements the list must have. - */ - const unsigned int max_elements; - - /** - * Separator between elements of the list. - */ - const std::string separator; - - - /** - * Separator between keys and values. - */ - const std::string key_value_separator; - - /** - * Initial part of description - */ - static const char *description_init; - }; - - - /** - * This class is much like the Selection class, but it allows the input to - * be a comma-separated list of values which each have to be given in the - * constructor argument. The input is allowed to be empty or contain values - * more than once and have an arbitrary number of spaces around commas. Of - * course commas are not allowed inside the values given to the constructor. - * - * For example, if the string to the constructor was "ucd|gmv|eps", - * then the following would be legal inputs: "eps", "gmv, eps", or "". - */ - class MultipleSelection : public PatternBase - { - public: - /** - * Constructor. @p seq is a list of valid options separated by "|". - */ - MultipleSelection (const std::string &seq); - - /** - * Return true if the string is an element of the description - * list passed to the constructor. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. Here, this is the list of valid strings passed to the - * constructor. - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create (const std::string &description); - - /** - * Determine an estimate for the memory consumption (in bytes) of this - * object. - */ - std::size_t memory_consumption () const; - - /** - * @addtogroup Exceptions - * @{ - */ - - /** - * Exception. - */ - DeclException1 (ExcCommasNotAllowed, - int, - << "A comma was found at position " << arg1 - << " of your input string, but commas are not allowed here."); - //@} - private: - /** - * List of valid strings as passed to the constructor. We don't make this - * string constant, as we process it somewhat in the constructor. - */ - std::string sequence; - - /** - * Initial part of description - */ - static const char *description_init; - }; - - /** - * Test for the string being either "true" or "false". This is mapped to the - * Selection class. - */ - class Bool : public Selection - { - public: - /** - * Constructor. - */ - Bool (); - - /** - * Return a description of the pattern that valid strings are expected to - * match. - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create(const std::string &description); - - private: - /** - * Initial part of description - */ - static const char *description_init; - }; - - /** - * Always returns true when testing a string. - */ - class Anything : public PatternBase - { - public: - /** - * Constructor. (Allow for at least one non-virtual function in this - * class, as otherwise sometimes no virtual table is emitted.) - */ - Anything (); - - /** - * Return true if the string matches its constraints, i.e. - * always. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. Here, this is the string "[Anything]". - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create(const std::string &description); - - private: - /** - * Initial part of description - */ - static const char *description_init; - }; - - - /** - * A pattern that can be used to indicate when a parameter is intended to be - * the name of a file. By itself, this class does not check whether the - * string that is given in a parameter file actually corresponds to an - * existing file (it could, for example, be the name of a file to which you - * want to write output). Functionally, the class is therefore equivalent to - * the Anything class. However, it allows to specify the intent of a - * parameter. The flag given to the constructor also allows to specify - * whether the file is supposed to be an input or output file. - * - * The reason for the existence of this class is to support graphical user - * interfaces for editing parameter files. These may open a file selection - * dialog if the filename is supposed to represent an input file. - */ - class FileName : public PatternBase - { - public: - /** - * Files can be used for input or output. This can be specified in the - * constructor by choosing the flag type. - */ - enum FileType - { - /** - * Open for input. - */ - input = 0, - /** - * Open for output. - */ - output = 1 - }; - - /** - * Constructor. The type of the file can be specified by choosing the - * flag. - */ - FileName (const FileType type = input); - - /** - * Return true if the string matches its constraints, i.e. - * always. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. Here, this is the string "[Filename]". - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * file type flag - */ - FileType file_type; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create (const std::string &description); - - private: - /** - * Initial part of description - */ - static const char *description_init; - }; - - - /** - * A pattern that can be used to indicate when a parameter is intended to be - * the name of a directory. By itself, this class does not check whether the - * string that is given in a parameter file actually corresponds to an - * existing directory. Functionally, the class is therefore equivalent to - * the Anything class. However, it allows to specify the intent of a - * parameter. - * - * The reason for the existence of this class is to support graphical user - * interfaces for editing parameter files. These may open a file selection - * dialog to select or create a directory. - */ - class DirectoryName : public PatternBase - { - public: - /** - * Constructor. - */ - DirectoryName (); - - /** - * Return true if the string matches its constraints, i.e. - * always. - */ - virtual bool match (const std::string &test_string) const; - - /** - * Return a description of the pattern that valid strings are expected to - * match. Here, this is the string "[Filename]". - */ - virtual std::string description (const OutputStyle style=Machine) const; - - /** - * Return a copy of the present object, which is newly allocated on the - * heap. Ownership of that object is transferred to the caller of this - * function. - */ - virtual std::unique_ptr clone () const; - - /** - * Creates new object if the start of description matches - * description_init. Ownership of that object is transferred to the - * caller of this function. - */ - static std::unique_ptr create(const std::string &description); - - private: - /** - * Initial part of description - */ - static const char *description_init; - }; -} - - /** * The ParameterHandler class provides a standard interface to an input file * which provides at run-time for program parameters such as time step sizes, diff --git a/include/deal.II/base/patterns.h b/include/deal.II/base/patterns.h new file mode 100644 index 0000000000..905d8e7206 --- /dev/null +++ b/include/deal.II/base/patterns.h @@ -0,0 +1,946 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 1998 - 2017 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + +#ifndef dealii__patterns_h +#define dealii__patterns_h + + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +DEAL_II_NAMESPACE_OPEN + +// forward declarations for interfaces and friendship +class LogStream; +class MultipleParameterLoop; + +/** + * Namespace for a few classes that act as patterns for the ParameterHandler + * class. These classes implement an interface that checks whether a parameter + * in an input file matches a certain pattern, such as "being boolean", "an + * integer value", etc. + * + * @ingroup input + */ +namespace Patterns +{ + + /** + * Base class to declare common interface. The purpose of this class is + * mostly to define the interface of patterns, and to force derived classes + * to have a clone function. It is thus, in the languages of the + * "Design Patterns" book (Gamma et al.), a "prototype". + */ + class PatternBase + { + public: + /** + * Make destructor of this and all derived classes virtual. + */ + virtual ~PatternBase (); + + /** + * Return true if the given string matches the pattern. + */ + virtual bool match (const std::string &test_string) const = 0; + + /** + * List of possible description output formats. + * + * Capitalization chosen for similarity to ParameterHandler::OutputStyle. + */ + enum OutputStyle + { + /** + * Simple text suitable for machine parsing in the static public member + * functions for all of the built in inheriting classes. + * + * Preferably human readable, but machine parsing is more critical. + */ + Machine, + /** + * Easily human readable plain text format suitable for plain text + * documentation. + */ + Text, + /** + * Easily human readable LaTeX format suitable for printing in manuals. + */ + LaTeX + }; + + /** + * Return a string describing the pattern. + */ + virtual std::string description (const OutputStyle style=Machine) const = 0; + + /** + * Return a pointer to an exact copy of the object. This is necessary + * since we want to store objects of this type in containers, were we need + * to copy objects without knowledge of their actual data type (we only + * have pointers to the base class). + * + * Ownership of the objects returned by this function is passed to the + * caller of this function. + */ + virtual std::unique_ptr clone () const = 0; + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. To avoid unnecessary overhead, we do not force derived classes + * to provide this function as a virtual overloaded one, but rather try to + * cast the present object to one of the known derived classes and if that + * fails then take the size of this base class instead and add 32 byte + * (this value is arbitrary, it should account for virtual function + * tables, and some possible data elements). Since there are usually not + * many thousands of objects of this type around, and since the + * memory_consumption mechanism is used to find out where memory in the + * range of many megabytes is, this seems like a reasonable approximation. + * + * On the other hand, if you know that your class deviates from this + * assumption significantly, you can still overload this function. + */ + virtual std::size_t memory_consumption () const; + }; + + /** + * Return pointer to the correct derived class based on description. + */ + std::unique_ptr pattern_factory (const std::string &description); + + /** + * Test for the string being an integer. If bounds are given to the + * constructor, then the integer given also needs to be within the interval + * specified by these bounds. Note that unlike common convention in the C++ + * standard library, both bounds of this interval are inclusive; the reason + * is that in practice in most cases, one needs closed intervals, but these + * can only be realized with inclusive bounds for non-integer values. We + * thus stay consistent by always using closed intervals. + * + * If the upper bound given to the constructor is smaller than the + * lower bound, then every integer is allowed. + * + * Giving bounds may be useful if for example a value can only be positive + * and less than a reasonable upper bound (for example the number of + * refinement steps to be performed), or in many other cases. + */ + class Integer : public PatternBase + { + public: + /** + * Minimal integer value. If the numeric_limits class is available use + * this information to obtain the extremal values, otherwise set it so + * that this class understands that all values are allowed. + */ + static const int min_int_value; + + /** + * Maximal integer value. If the numeric_limits class is available use + * this information to obtain the extremal values, otherwise set it so + * that this class understands that all values are allowed. + */ + static const int max_int_value; + + /** + * Constructor. Bounds can be specified within which a valid + * parameter has to be. If the upper bound is smaller than the + * lower bound, then the entire set of integers is implied. The + * default values are chosen such that no bounds are enforced on + * parameters. + */ + Integer (const int lower_bound = min_int_value, + const int upper_bound = max_int_value); + + /** + * Return true if the string is an integer and its value is + * within the specified range. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. If bounds were specified to the constructor, then include them + * into this description. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create (const std::string &description); + + private: + /** + * Value of the lower bound. A number that satisfies the + * @ref match + * operation of this class must be equal to this value or larger, if the + * bounds of the interval for a valid range. + */ + const int lower_bound; + + /** + * Value of the upper bound. A number that satisfies the + * @ref match + * operation of this class must be equal to this value or less, if the + * bounds of the interval for a valid range. + */ + const int upper_bound; + + /** + * Initial part of description + */ + static const char *description_init; + }; + + /** + * Test for the string being a double. If bounds are given to the + * constructor, then the integer given also needs to be within the interval + * specified by these bounds. Note that unlike common convention in the C++ + * standard library, both bounds of this interval are inclusive; the reason + * is that in practice in most cases, one needs closed intervals, but these + * can only be realized with inclusive bounds for non-integer values. We + * thus stay consistent by always using closed intervals. + * + * If the upper bound given to the constructor is smaller than the + * lower bound, then every double precision number is allowed. + * + * Giving bounds may be useful if for example a value can only be positive + * and less than a reasonable upper bound (for example damping parameters + * are frequently only reasonable if between zero and one), or in many other + * cases. + */ + class Double : public PatternBase + { + public: + /** + * Minimal double value used as default value, taken from + * std::numeric_limits. + */ + static const double min_double_value; + + /** + * Maximal double value used as default value, taken from + * std::numeric_limits. + */ + static const double max_double_value; + + /** + * Constructor. Bounds can be specified within which a valid + * parameter has to be. If the upper bound is smaller than the + * lower bound, then the entire set of double precision numbers is + * implied. The default values are chosen such that no bounds are + * enforced on parameters. + */ + Double (const double lower_bound = min_double_value, + const double upper_bound = max_double_value); + + /** + * Return true if the string is a number and its value is within + * the specified range. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. If bounds were specified to the constructor, then include them + * into this description. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates a new object on the heap using @p new if the given + * @p description is a valid format (for example created by calling + * description() on an existing object), or @p nullptr otherwise. Ownership + * of the returned object is transferred to the caller of this function, + * which should be freed using @p delete. + */ + static std::unique_ptr create(const std::string &description); + + private: + /** + * Value of the lower bound. A number that satisfies the + * @ref match + * operation of this class must be equal to this value or larger, if the + * bounds of the interval form a valid range. + */ + const double lower_bound; + + /** + * Value of the upper bound. A number that satisfies the + * @ref match + * operation of this class must be equal to this value or less, if the + * bounds of the interval form a valid range. + */ + const double upper_bound; + + /** + * Initial part of description + */ + static const char *description_init; + }; + + /** + * Test for the string being one of a sequence of values given like a + * regular expression. For example, if the string given to the constructor + * is "red|blue|black", then the + * @ref match + * function returns true exactly if the string is either "red" or + * "blue" or "black". Spaces around the pipe signs do not matter and are + * eliminated. + */ + class Selection : public PatternBase + { + public: + /** + * Constructor. Take the given parameter as the specification of valid + * strings. + */ + Selection (const std::string &seq); + + /** + * Return true if the string is an element of the description + * list passed to the constructor. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. Here, this is the list of valid strings passed to the + * constructor. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + std::size_t memory_consumption () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create (const std::string &description); + + private: + /** + * List of valid strings as passed to the constructor. We don't make this + * string constant, as we process it somewhat in the constructor. + */ + std::string sequence; + + /** + * Initial part of description + */ + static const char *description_init; + }; + + + /** + * This pattern matches a list of values separated by commas (or another + * string), each of which have to match a pattern given to the constructor. + * With two additional parameters, the number of elements this list has to + * have can be specified. If none is specified, the list may have zero or + * more entries. + */ + class List : public PatternBase + { + public: + /** + * Maximal integer value. If the numeric_limits class is available use + * this information to obtain the extremal values, otherwise set it so + * that this class understands that all values are allowed. + */ + static const unsigned int max_int_value; + + /** + * Constructor. Take the given parameter as the specification of valid + * elements of the list. + * + * The three other arguments can be used to denote minimal and maximal + * allowable lengths of the list, and the string that is used as a + * separator between elements of the list. + */ + List (const PatternBase &base_pattern, + const unsigned int min_elements = 0, + const unsigned int max_elements = max_int_value, + const std::string &separator = ","); + + + /** + * Return the internally stored separator. + */ + const std::string &get_separator() const; + + /** + * Return the internally stored base pattern. + */ + const PatternBase &get_base_pattern() const; + + /** + * Copy constructor. + */ + List (const List &other); + + /** + * Return true if the string is a comma-separated list of strings + * each of which match the pattern given to the constructor. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create (const std::string &description); + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + std::size_t memory_consumption () const; + + /** + * @addtogroup Exceptions + * @{ + */ + + /** + * Exception. + */ + DeclException2 (ExcInvalidRange, + int, int, + << "The values " << arg1 << " and " << arg2 + << " do not form a valid range."); + //@} + private: + /** + * Copy of the pattern that each element of the list has to satisfy. + */ + std::unique_ptr pattern; + + /** + * Minimum number of elements the list must have. + */ + const unsigned int min_elements; + + /** + * Maximum number of elements the list must have. + */ + const unsigned int max_elements; + + /** + * Separator between elements of the list. + */ + const std::string separator; + + /** + * Initial part of description + */ + static const char *description_init; + }; + + + /** + * This pattern matches a list of comma-separated values each of which + * denotes a pair of key and value. Both key and value have to match a + * pattern given to the constructor. For each entry of the map, parameters + * have to be entered in the form key: value. In other words, a + * map is described in the form key1: value1, key2: value2, key3: + * value3, .... Two constructor arguments allow to choose a delimiter + * between pairs other than the comma, and a delimeter between key and value + * other than column. + * + * With two additional parameters, the number of elements this list has to + * have can be specified. If none is specified, the map may have zero or + * more entries. + */ + class Map : public PatternBase + { + public: + /** + * Maximal integer value. If the numeric_limits class is available use + * this information to obtain the extremal values, otherwise set it so + * that this class understands that all values are allowed. + */ + static const unsigned int max_int_value; + + /** + * Constructor. Take the given parameter as the specification of valid + * elements of the list. + * + * The four other arguments can be used to denote minimal and maximal + * allowable lengths of the list as well as the separators used to delimit + * pairs of the map and the symbol used to separate keys and values. + */ + Map (const PatternBase &key_pattern, + const PatternBase &value_pattern, + const unsigned int min_elements = 0, + const unsigned int max_elements = max_int_value, + const std::string &separator = ",", + const std::string &key_value_separator = ":"); + + /** + * Copy constructor. + */ + Map (const Map &other); + + /** + * Return true if the string is a comma-separated list of strings + * each of which match the pattern given to the constructor. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create (const std::string &description); + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + std::size_t memory_consumption () const; + + /** + * Return a reference to the key pattern. + */ + const PatternBase &get_key_pattern() const; + + /** + * Return a reference to the value pattern. + */ + const PatternBase &get_value_pattern() const; + + /** + * Return the separator of the map entries. + */ + const std::string &get_separator() const; + + /** + * Return the key-value separator. + */ + const std::string &get_key_value_separator() const; + + /** + * @addtogroup Exceptions + * @{ + */ + + /** + * Exception. + */ + DeclException2 (ExcInvalidRange, + int, int, + << "The values " << arg1 << " and " << arg2 + << " do not form a valid range."); + //@} + private: + /** + * Copy of the patterns that each key and each value of the map has to + * satisfy. + */ + std::unique_ptr key_pattern; + std::unique_ptr value_pattern; + + /** + * Minimum number of elements the list must have. + */ + const unsigned int min_elements; + + /** + * Maximum number of elements the list must have. + */ + const unsigned int max_elements; + + /** + * Separator between elements of the list. + */ + const std::string separator; + + + /** + * Separator between keys and values. + */ + const std::string key_value_separator; + + /** + * Initial part of description + */ + static const char *description_init; + }; + + + /** + * This class is much like the Selection class, but it allows the input to + * be a comma-separated list of values which each have to be given in the + * constructor argument. The input is allowed to be empty or contain values + * more than once and have an arbitrary number of spaces around commas. Of + * course commas are not allowed inside the values given to the constructor. + * + * For example, if the string to the constructor was "ucd|gmv|eps", + * then the following would be legal inputs: "eps", "gmv, eps", or "". + */ + class MultipleSelection : public PatternBase + { + public: + /** + * Constructor. @p seq is a list of valid options separated by "|". + */ + MultipleSelection (const std::string &seq); + + /** + * Return true if the string is an element of the description + * list passed to the constructor. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. Here, this is the list of valid strings passed to the + * constructor. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create (const std::string &description); + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + std::size_t memory_consumption () const; + + /** + * @addtogroup Exceptions + * @{ + */ + + /** + * Exception. + */ + DeclException1 (ExcCommasNotAllowed, + int, + << "A comma was found at position " << arg1 + << " of your input string, but commas are not allowed here."); + //@} + private: + /** + * List of valid strings as passed to the constructor. We don't make this + * string constant, as we process it somewhat in the constructor. + */ + std::string sequence; + + /** + * Initial part of description + */ + static const char *description_init; + }; + + /** + * Test for the string being either "true" or "false". This is mapped to the + * Selection class. + */ + class Bool : public Selection + { + public: + /** + * Constructor. + */ + Bool (); + + /** + * Return a description of the pattern that valid strings are expected to + * match. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create(const std::string &description); + + private: + /** + * Initial part of description + */ + static const char *description_init; + }; + + /** + * Always returns true when testing a string. + */ + class Anything : public PatternBase + { + public: + /** + * Constructor. (Allow for at least one non-virtual function in this + * class, as otherwise sometimes no virtual table is emitted.) + */ + Anything (); + + /** + * Return true if the string matches its constraints, i.e. + * always. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. Here, this is the string "[Anything]". + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create(const std::string &description); + + private: + /** + * Initial part of description + */ + static const char *description_init; + }; + + + /** + * A pattern that can be used to indicate when a parameter is intended to be + * the name of a file. By itself, this class does not check whether the + * string that is given in a parameter file actually corresponds to an + * existing file (it could, for example, be the name of a file to which you + * want to write output). Functionally, the class is therefore equivalent to + * the Anything class. However, it allows to specify the intent of a + * parameter. The flag given to the constructor also allows to specify + * whether the file is supposed to be an input or output file. + * + * The reason for the existence of this class is to support graphical user + * interfaces for editing parameter files. These may open a file selection + * dialog if the filename is supposed to represent an input file. + */ + class FileName : public PatternBase + { + public: + /** + * Files can be used for input or output. This can be specified in the + * constructor by choosing the flag type. + */ + enum FileType + { + /** + * Open for input. + */ + input = 0, + /** + * Open for output. + */ + output = 1 + }; + + /** + * Constructor. The type of the file can be specified by choosing the + * flag. + */ + FileName (const FileType type = input); + + /** + * Return true if the string matches its constraints, i.e. + * always. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. Here, this is the string "[Filename]". + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * file type flag + */ + FileType file_type; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create (const std::string &description); + + private: + /** + * Initial part of description + */ + static const char *description_init; + }; + + + /** + * A pattern that can be used to indicate when a parameter is intended to be + * the name of a directory. By itself, this class does not check whether the + * string that is given in a parameter file actually corresponds to an + * existing directory. Functionally, the class is therefore equivalent to + * the Anything class. However, it allows to specify the intent of a + * parameter. + * + * The reason for the existence of this class is to support graphical user + * interfaces for editing parameter files. These may open a file selection + * dialog to select or create a directory. + */ + class DirectoryName : public PatternBase + { + public: + /** + * Constructor. + */ + DirectoryName (); + + /** + * Return true if the string matches its constraints, i.e. + * always. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. Here, this is the string "[Filename]". + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create(const std::string &description); + + private: + /** + * Initial part of description + */ + static const char *description_init; + }; +} + +DEAL_II_NAMESPACE_CLOSE + +#endif diff --git a/source/base/CMakeLists.txt b/source/base/CMakeLists.txt index 4625cb7418..87cd9809bd 100644 --- a/source/base/CMakeLists.txt +++ b/source/base/CMakeLists.txt @@ -44,6 +44,7 @@ SET(_src parameter_handler.cc parsed_function.cc partitioner.cc + patterns.cc path_search.cc polynomial.cc polynomials_abf.cc diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index c8626df734..55c45e49ab 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -42,1321 +42,6 @@ DEAL_II_ENABLE_EXTRA_DIAGNOSTICS DEAL_II_NAMESPACE_OPEN - -//TODO[WB]: various functions here could be simplified by using namespace Utilities - -namespace Patterns -{ - - namespace - { - /** - * Read to the end of the stream and - * return whether all there is is - * whitespace or whether there are other - * characters as well. - */ - bool has_only_whitespace (std::istream &in) - { - while (in) - { - char c; - - // skip if we've reached the end of - // the line - if (!(in >> c)) - break; - - if ((c != ' ') && (c != '\t')) - return false; - } - return true; - } - } - - - - std::unique_ptr pattern_factory(const std::string &description) - { - std::unique_ptr p; - - p = Integer::create(description); - if (p != nullptr) - return p; - - p = Double::create(description); - if (p != nullptr ) - return p; - - p = Selection::create(description); - if (p != nullptr ) - return p; - - p = List::create(description); - if (p != nullptr ) - return p; - - p = Map::create(description); - if (p != nullptr ) - return p; - - p = MultipleSelection::create(description); - if (p != nullptr ) - return p; - - p = Bool::create(description); - if (p!=nullptr ) - return p; - - p = Anything::create(description); - if (p != nullptr ) - return p; - - p = FileName::create(description); - if (p != nullptr ) - return p; - - p = DirectoryName::create(description); - if (p!=nullptr ) - return p; - - Assert(false, ExcNotImplemented()); - - return p; - } - - - - PatternBase::~PatternBase () - {} - - - std::size_t - PatternBase::memory_consumption () const - { - if (dynamic_cast(this) != nullptr) - return sizeof(Integer); - else if (dynamic_cast(this) != nullptr) - return sizeof(Double); - else if (dynamic_cast(this) != nullptr) - return sizeof(Bool); - else if (dynamic_cast(this) != nullptr) - return sizeof(Anything); - else - return sizeof(*this) + 32; - } - - - - const int Integer::min_int_value = std::numeric_limits::min(); - const int Integer::max_int_value = std::numeric_limits::max(); - - const char *Integer::description_init = "[Integer"; - - Integer::Integer (const int lower_bound, - const int upper_bound) - : - lower_bound (lower_bound), - upper_bound (upper_bound) - {} - - - - bool Integer::match (const std::string &test_string) const - { - std::istringstream str(test_string); - - int i; - if (!(str >> i)) - return false; - - if (!has_only_whitespace (str)) - return false; - // check whether valid bounds - // were specified, and if so - // enforce their values - if (lower_bound <= upper_bound) - return ((lower_bound <= i) && - (upper_bound >= i)); - else - return true; - } - - - - std::string Integer::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - // check whether valid bounds - // were specified, and if so - // output their values - if (lower_bound <= upper_bound) - { - std::ostringstream description; - - description << description_init - <<" range " - << lower_bound << "..." << upper_bound - << " (inclusive)]"; - return description.str(); - } - else - // if no bounds were given, then - // return generic string - return "[Integer]"; - } - case Text: - { - if (lower_bound <= upper_bound) - { - std::ostringstream description; - - description << "An integer n such that " - << lower_bound << " <= n <= " << upper_bound; - - return description.str(); - } - else - return "An integer"; - } - case LaTeX: - { - if (lower_bound <= upper_bound) - { - std::ostringstream description; - - description << "An integer $n$ such that $" - << lower_bound << "\\leq n \\leq " << upper_bound - << "$"; - - return description.str(); - } - else - return "An integer"; - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr Integer::clone() const - { - return std::unique_ptr(new Integer(lower_bound, upper_bound)); - } - - - - std::unique_ptr Integer::create(const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - { - std::istringstream is(description); - - if (is.str().size() > strlen(description_init) + 1) - { -//TODO: verify that description matches the pattern "^\[Integer range \d+\.\.\.\d+\]$" - int lower_bound, upper_bound; - - is.ignore(strlen(description_init) + strlen(" range ")); - - if (!(is >> lower_bound)) - return std::unique_ptr(new Integer()); - - is.ignore(strlen("...")); - - if (!(is >> upper_bound)) - return std::unique_ptr(new Integer()); - - return std::unique_ptr(new Integer(lower_bound, upper_bound)); - } - else - return std::unique_ptr(new Integer()); - } - else - return std::unique_ptr(); - } - - - - const double Double::min_double_value = -std::numeric_limits::max(); - const double Double::max_double_value = std::numeric_limits::max(); - - const char *Double::description_init = "[Double"; - - Double::Double (const double lower_bound, - const double upper_bound) - : - lower_bound (lower_bound), - upper_bound (upper_bound) - {} - - - - bool Double::match (const std::string &test_string) const - { - std::istringstream str(test_string); - - double d; - str >> d; - if (str.fail()) - return false; - - if (!has_only_whitespace (str)) - return false; - // check whether valid bounds - // were specified, and if so - // enforce their values - if (lower_bound <= upper_bound) - return ((lower_bound <= d) && - (upper_bound >= d)); - else - return true; - } - - - - std::string Double::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - if (lower_bound <= upper_bound) - { - // bounds are valid - description << description_init << " "; - // We really want to compare with ==, but -Wfloat-equal would create - // a warning here, so work around it. - if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound))) - description << "-MAX_DOUBLE"; - else - description << lower_bound; - description << "..."; - if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound))) - description << "MAX_DOUBLE"; - else - description << upper_bound; - description << " (inclusive)]"; - return description.str(); - } - else - { - // invalid bounds, assume unbounded double: - description << description_init << "]"; - return description.str(); - } - } - case Text: - { - if (lower_bound <= upper_bound) - { - std::ostringstream description; - - description << "A floating point number v such that "; - if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound))) - description << "-MAX_DOUBLE"; - else - description << lower_bound; - description << " <= v <= "; - if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound))) - description << "MAX_DOUBLE"; - else - description << upper_bound; - - return description.str(); - } - else - return "A floating point number"; - } - case LaTeX: - { - if (lower_bound <= upper_bound) - { - std::ostringstream description; - - description << "A floating point number $v$ such that $"; - if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound))) - description << "-\\text{MAX\\_DOUBLE}"; - else - description << lower_bound; - description << " \\leq v \\leq "; - if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound))) - description << "\\text{MAX\\_DOUBLE}"; - else - description << upper_bound; - description << "$"; - - return description.str(); - } - else - return "A floating point number"; - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - std::unique_ptr Double::clone() const - { - return std::unique_ptr(new Double(lower_bound, upper_bound)); - } - - - - std::unique_ptr Double::create (const std::string &description) - { - const std::string description_init_str = description_init; - if (description.compare(0, description_init_str.size(), description_init_str) != 0) - return std::unique_ptr(); - if (*description.rbegin() != ']') - return std::unique_ptr(); - - std::string temp = description.substr(description_init_str.size()); - if (temp == "]") - return std::unique_ptr(new Double(1.0, -1.0)); // return an invalid range - - if (temp.find("...") != std::string::npos) - temp.replace(temp.find("..."), 3, " "); - - double lower_bound = min_double_value, - upper_bound = max_double_value; - - std::istringstream is(temp); - if (0 == temp.compare(0, std::strlen(" -MAX_DOUBLE"), " -MAX_DOUBLE")) - is.ignore(std::strlen(" -MAX_DOUBLE")); - else - { - // parse lower bound and give up if not a double - if (!(is >> lower_bound)) - return std::unique_ptr(); - } - - // ignore failure here and assume we got MAX_DOUBLE as upper bound: - is >> upper_bound; - if (is.fail()) - upper_bound = max_double_value; - - return std::unique_ptr(new Double(lower_bound, upper_bound)); - } - - - - const char *Selection::description_init = "[Selection"; - - - Selection::Selection (const std::string &seq) - : sequence(seq) - { - while (sequence.find(" |") != std::string::npos) - sequence.replace (sequence.find(" |"), 2, "|"); - while (sequence.find("| ") != std::string::npos) - sequence.replace (sequence.find("| "), 2, "|"); - } - - - - bool Selection::match (const std::string &test_string) const - { - std::string tmp(sequence); - - // remove whitespace at beginning - while ((tmp.length() != 0) && (std::isspace (tmp[0]))) - tmp.erase (0,1); - - // check the different possibilities - while (tmp.find('|') != std::string::npos) - { - if (test_string == std::string(tmp, 0, tmp.find('|'))) - return true; - - tmp.erase (0, tmp.find('|')+1); - }; - - //remove whitespace at the end - while ((tmp.length() != 0) && (std::isspace (*(tmp.end()-1)))) - tmp.erase (tmp.end()-1); - - // check last choice, not finished by | - if (test_string == tmp) - return true; - - // not found - return false; - } - - - - std::string Selection::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init - << " " - << sequence - << " ]"; - - return description.str(); - } - case Text: - case LaTeX: - { - std::ostringstream description; - - description << "Any one of " - << Utilities::replace_in_string(sequence,"|",", "); - - return description.str(); - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr Selection::clone() const - { - return std::unique_ptr(new Selection(sequence)); - } - - - std::size_t - Selection::memory_consumption () const - { - return (sizeof(PatternBase) + - MemoryConsumption::memory_consumption(sequence)); - } - - - - std::unique_ptr Selection::create(const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - { - std::string sequence(description); - - sequence.erase(0, std::strlen(description_init) + 1); - sequence.erase(sequence.length()-2, 2); - - return std::unique_ptr(new Selection(sequence)); - } - else - return std::unique_ptr(); - } - - - - const unsigned int List::max_int_value - = std::numeric_limits::max(); - - const char *List::description_init = "[List"; - - - List::List (const PatternBase &p, - const unsigned int min_elements, - const unsigned int max_elements, - const std::string &separator) - : - pattern (p.clone()), - min_elements (min_elements), - max_elements (max_elements), - separator (separator) - { - Assert (min_elements <= max_elements, - ExcInvalidRange (min_elements, max_elements)); - Assert (separator.size() > 0, - ExcMessage ("The separator must have a non-zero length.")); - } - - - - List::List (const List &other) - : - pattern (other.pattern->clone()), - min_elements (other.min_elements), - max_elements (other.max_elements), - separator (other.separator) - {} - - - const std::string &List::get_separator() const - { - return separator; - } - - - - const PatternBase &List::get_base_pattern() const - { - return *pattern; - } - - - - bool List::match (const std::string &test_string_list) const - { - const std::vector split_list = - Utilities::split_string_list(test_string_list, separator); - - if ((split_list.size() < min_elements) || - (split_list.size() > max_elements)) - return false; - - // check the different possibilities - for (const std::string &string : split_list) - if (pattern->match (string) == false) - return false; - - return true; - } - - - - std::string List::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init - << " of <" << pattern->description(style) << ">" - << " of length " << min_elements << "..." << max_elements - << " (inclusive)"; - if (separator != ",") - description << " separated by <" << separator << ">"; - description << "]"; - - return description.str(); - } - case Text: - case LaTeX: - { - std::ostringstream description; - - description << "A list of " - << min_elements << " to " << max_elements - << " elements "; - if (separator != ",") - description << "separated by <" << separator << "> "; - description << "where each element is [" - << pattern->description(style) - << "]"; - - return description.str(); - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr List::clone() const - { - return std::unique_ptr(new List(*pattern, min_elements, max_elements, separator)); - } - - - std::size_t - List::memory_consumption () const - { - return (sizeof(*this) + - MemoryConsumption::memory_consumption(*pattern) + - MemoryConsumption::memory_consumption(separator)); - } - - - - std::unique_ptr List::create (const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - { - int min_elements, max_elements; - - std::istringstream is(description); - is.ignore(strlen(description_init) + strlen(" of <")); - - std::string str; - std::getline(is, str, '>'); - - std::shared_ptr base_pattern (pattern_factory(str)); - - is.ignore(strlen(" of length ")); - if (!(is >> min_elements)) - return std::unique_ptr(new List(*base_pattern)); - - is.ignore(strlen("...")); - if (!(is >> max_elements)) - return std::unique_ptr(new List(*base_pattern, min_elements)); - - is.ignore(strlen(" (inclusive) separated by <")); - std::string separator; - if (is) - std::getline(is, separator, '>'); - else - separator = ","; - - return std::unique_ptr(new List(*base_pattern, min_elements, max_elements, separator)); - } - else - return std::unique_ptr(); - } - - - - const unsigned int Map::max_int_value - = std::numeric_limits::max(); - - const char *Map::description_init = "[Map"; - - - Map::Map (const PatternBase &p_key, - const PatternBase &p_value, - const unsigned int min_elements, - const unsigned int max_elements, - const std::string &separator, - const std::string &key_value_separator) - : - key_pattern (p_key.clone()), - value_pattern (p_value.clone()), - min_elements (min_elements), - max_elements (max_elements), - separator (separator), - key_value_separator(key_value_separator) - { - Assert (min_elements <= max_elements, - ExcInvalidRange (min_elements, max_elements)); - Assert (separator.size() > 0, - ExcMessage ("The separator must have a non-zero length.")); - Assert (key_value_separator.size() > 0, - ExcMessage ("The key_value_separator must have a non-zero length.")); - Assert (separator != key_value_separator, - ExcMessage ("The separator can not be the same of the key_value_separator " - "since that is used as the separator between the two elements " - "of pairs")); - } - - - - Map::Map (const Map &other) - : - key_pattern (other.key_pattern->clone()), - value_pattern (other.value_pattern->clone()), - min_elements (other.min_elements), - max_elements (other.max_elements), - separator (other.separator), - key_value_separator(other.key_value_separator) - {} - - - - bool Map::match (const std::string &test_string_list) const - { - std::string tmp = test_string_list; - std::vector split_list = - Utilities::split_string_list(test_string_list, separator); - if ((split_list.size() < min_elements) || - (split_list.size() > max_elements)) - return false; - - for (auto &key_value_pair : split_list) - { - std::vector pair = - Utilities::split_string_list(key_value_pair, key_value_separator); - - // Check that we have in fact two mathces - if (pair.size() != 2) - return false; - - // then verify that the patterns are satisfied - if (key_pattern->match (pair[0]) == false) - return false; - if (value_pattern->match (pair[1]) == false) - return false; - } - - return true; - } - - - - std::string Map::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init - << " of <" - << key_pattern->description(style) << ">" - << key_value_separator << "<" - << value_pattern->description(style) << ">" - << " of length " << min_elements << "..." << max_elements - << " (inclusive)"; - if (separator != ",") - description << " separated by <" << separator << ">"; - description << "]"; - - return description.str(); - } - case Text: - case LaTeX: - { - std::ostringstream description; - - description << "A key" - << key_value_separator - << "value map of " - << min_elements << " to " << max_elements - << " elements "; - if (separator != ",") - description << " separated by <" << separator << "> "; - description << " where each key is [" - << key_pattern->description(style) - << "]" - << " and each value is [" - << value_pattern->description(style) - << "]"; - - return description.str(); - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr Map::clone() const - { - return std::unique_ptr(new Map(*key_pattern, *value_pattern, - min_elements, max_elements, - separator, key_value_separator)); - } - - - std::size_t - Map::memory_consumption () const - { - return (sizeof(*this) + - MemoryConsumption::memory_consumption (*key_pattern) + - MemoryConsumption::memory_consumption (*value_pattern) + - MemoryConsumption::memory_consumption (separator)+ - MemoryConsumption::memory_consumption (key_value_separator)); - } - - - - std::unique_ptr Map::create (const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - { - int min_elements, max_elements; - - std::istringstream is(description); - is.ignore(strlen(description_init) + strlen(" of <")); - - std::string key; - std::getline(is, key, '>'); - - std::string key_value_separator; - std::getline(is, key_value_separator, '<'); - - // split 'str' into key and value - std::string value; - std::getline(is, value, '>'); - - std::shared_ptr key_pattern (pattern_factory(key)); - std::shared_ptr value_pattern (pattern_factory(value)); - - is.ignore(strlen(" of length ")); - if (!(is >> min_elements)) - return std::unique_ptr(new Map(*key_pattern, *value_pattern)); - - is.ignore(strlen("...")); - if (!(is >> max_elements)) - return std::unique_ptr(new Map(*key_pattern, *value_pattern, min_elements)); - - is.ignore(strlen(" (inclusive) separated by <")); - std::string separator; - if (is) - std::getline(is, separator, '>'); - else - separator = ","; - - return std::unique_ptr(new Map(*key_pattern, *value_pattern, - min_elements, max_elements, - separator, key_value_separator)); - } - else - return std::unique_ptr(); - } - - - - const PatternBase &Map::get_key_pattern() const - { - return *key_pattern; - } - - - - const PatternBase &Map::get_value_pattern() const - { - return *value_pattern; - } - - - - const std::string &Map::get_separator() const - { - return separator; - } - - - const std::string &Map::get_key_value_separator() const - { - return key_value_separator; - } - - - const char *MultipleSelection::description_init = "[MultipleSelection"; - - - MultipleSelection::MultipleSelection (const std::string &seq) - { - Assert (seq.find (",") == std::string::npos, ExcCommasNotAllowed(seq.find(","))); - - sequence = seq; - while (sequence.find(" |") != std::string::npos) - sequence.replace (sequence.find(" |"), 2, "|"); - while (sequence.find("| ") != std::string::npos) - sequence.replace (sequence.find("| "), 2, "|"); - } - - - - bool MultipleSelection::match (const std::string &test_string_list) const - { - std::string tmp = test_string_list; - std::vector split_names; - - // first split the input list - while (tmp.length() != 0) - { - std::string name; - name = tmp; - - if (name.find(",") != std::string::npos) - { - name.erase (name.find(","), std::string::npos); - tmp.erase (0, tmp.find(",")+1); - } - else - tmp = ""; - - while ((name.length() != 0) && - (std::isspace (name[0]))) - name.erase (0,1); - while (std::isspace (name[name.length()-1])) - name.erase (name.length()-1, 1); - - split_names.push_back (name); - }; - - - // check the different possibilities - for (std::vector::const_iterator test_string = split_names.begin(); - test_string != split_names.end(); ++test_string) - { - bool string_found = false; - - tmp = sequence; - while (tmp.find('|') != std::string::npos) - { - if (*test_string == std::string(tmp, 0, tmp.find('|'))) - { - // string found, quit - // loop. don't change - // tmp, since we don't - // need it anymore. - string_found = true; - break; - }; - - tmp.erase (0, tmp.find('|')+1); - }; - // check last choice, not finished by | - if (!string_found) - if (*test_string == tmp) - string_found = true; - - if (!string_found) - return false; - }; - - return true; - } - - - - std::string MultipleSelection::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init - << " " - << sequence - << " ]"; - - return description.str(); - } - case Text: - case LaTeX: - { - std::ostringstream description; - - description << "A comma-separated list of any of " - << Utilities::replace_in_string(sequence,"|",", "); - - return description.str(); - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr MultipleSelection::clone() const - { - return std::unique_ptr(new MultipleSelection(sequence)); - } - - - std::size_t - MultipleSelection::memory_consumption () const - { - return (sizeof(PatternBase) + - MemoryConsumption::memory_consumption(sequence)); - } - - - - std::unique_ptr MultipleSelection::create (const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - { - std::string sequence(description); - - sequence.erase(0, std::strlen(description_init) + 1); - sequence.erase(sequence.length()-2, 2); - - return std::unique_ptr(new MultipleSelection(sequence)); - } - else - return std::unique_ptr(); - } - - - - const char *Bool::description_init = "[Bool"; - - - Bool::Bool () - : - Selection ("true|false") - {} - - - - std::string Bool::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init - << "]"; - - return description.str(); - } - case Text: - case LaTeX: - { - return "A boolean value (true or false)"; - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr Bool::clone() const - { - return std::unique_ptr(new Bool()); - } - - - - std::unique_ptr Bool::create (const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - return std::unique_ptr(new Bool()); - else - return std::unique_ptr(); - } - - - - const char *Anything::description_init = "[Anything"; - - - Anything::Anything () - {} - - - - bool Anything::match (const std::string &) const - { - return true; - } - - - - std::string Anything::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init - << "]"; - - return description.str(); - } - case Text: - case LaTeX: - { - return "Any string"; - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr Anything::clone() const - { - return std::unique_ptr(new Anything()); - } - - - - std::unique_ptr Anything::create (const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - return std::unique_ptr(new Anything()); - else - return std::unique_ptr(); - } - - - - const char *FileName::description_init = "[FileName"; - - - FileName::FileName (const FileType type) - : file_type (type) - {} - - - - bool FileName::match (const std::string &) const - { - return true; - } - - - - std::string FileName::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init; - - if (file_type == input) - description << " (Type: input)]"; - else - description << " (Type: output)]"; - - return description.str(); - } - case Text: - case LaTeX: - { - if (file_type == input) - return "an input filename"; - else - return "an output filename"; - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr FileName::clone() const - { - return std::unique_ptr(new FileName(file_type)); - } - - - - std::unique_ptr FileName::create (const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - { - std::istringstream is(description); - std::string file_type; - FileType type; - - is.ignore(strlen(description_init) + strlen(" (Type:")); - - is >> file_type; - - if (file_type == "input)]") - type = input; - else - type = output; - - return std::unique_ptr(new FileName(type)); - } - else - return std::unique_ptr(); - } - - - - const char *DirectoryName::description_init = "[DirectoryName"; - - - DirectoryName::DirectoryName () - {} - - - - bool DirectoryName::match (const std::string &) const - { - return true; - } - - - - std::string DirectoryName::description (const OutputStyle style) const - { - switch (style) - { - case Machine: - { - std::ostringstream description; - - description << description_init << "]"; - - return description.str(); - } - case Text: - case LaTeX: - { - return "A directory name"; - } - default: - AssertThrow(false, ExcNotImplemented()); - } - // Should never occur without an exception, but prevent compiler from - // complaining - return ""; - } - - - - std::unique_ptr DirectoryName::clone() const - { - return std::unique_ptr(new DirectoryName()); - } - - - - std::unique_ptr DirectoryName::create (const std::string &description) - { - if (description.compare(0, std::strlen(description_init), description_init) == 0) - return std::unique_ptr(new DirectoryName()); - else - return std::unique_ptr(); - } - -} // end namespace Patterns - - - ParameterHandler::ParameterHandler () : entries (new boost::property_tree::ptree()) diff --git a/source/base/patterns.cc b/source/base/patterns.cc new file mode 100644 index 0000000000..ddcacf010d --- /dev/null +++ b/source/base/patterns.cc @@ -0,0 +1,1358 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 1998 - 2017 by the deal.II authors +// +// This file is part of the deal.II library. +// +// The deal.II library is free software; you can use it, redistribute +// it, and/or modify it under the terms of the GNU Lesser General +// Public License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// The full text of the license can be found in the file LICENSE at +// the top level of the deal.II distribution. +// +// --------------------------------------------------------------------- + + +#include +#include +#include +#include +#include + +DEAL_II_DISABLE_EXTRA_DIAGNOSTICS +#include +#include +#include + +#include +DEAL_II_ENABLE_EXTRA_DIAGNOSTICS + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +DEAL_II_NAMESPACE_OPEN + + + +//TODO[WB]: various functions here could be simplified by using namespace Utilities + +namespace Patterns +{ + + namespace + { + /** + * Read to the end of the stream and + * return whether all there is is + * whitespace or whether there are other + * characters as well. + */ + bool has_only_whitespace (std::istream &in) + { + while (in) + { + char c; + + // skip if we've reached the end of + // the line + if (!(in >> c)) + break; + + if ((c != ' ') && (c != '\t')) + return false; + } + return true; + } + } + + + + std::unique_ptr pattern_factory(const std::string &description) + { + std::unique_ptr p; + + p = Integer::create(description); + if (p != nullptr) + return p; + + p = Double::create(description); + if (p != nullptr ) + return p; + + p = Selection::create(description); + if (p != nullptr ) + return p; + + p = List::create(description); + if (p != nullptr ) + return p; + + p = Map::create(description); + if (p != nullptr ) + return p; + + p = MultipleSelection::create(description); + if (p != nullptr ) + return p; + + p = Bool::create(description); + if (p!=nullptr ) + return p; + + p = Anything::create(description); + if (p != nullptr ) + return p; + + p = FileName::create(description); + if (p != nullptr ) + return p; + + p = DirectoryName::create(description); + if (p!=nullptr ) + return p; + + Assert(false, ExcNotImplemented()); + + return p; + } + + + + PatternBase::~PatternBase () + {} + + + std::size_t + PatternBase::memory_consumption () const + { + if (dynamic_cast(this) != nullptr) + return sizeof(Integer); + else if (dynamic_cast(this) != nullptr) + return sizeof(Double); + else if (dynamic_cast(this) != nullptr) + return sizeof(Bool); + else if (dynamic_cast(this) != nullptr) + return sizeof(Anything); + else + return sizeof(*this) + 32; + } + + + + const int Integer::min_int_value = std::numeric_limits::min(); + const int Integer::max_int_value = std::numeric_limits::max(); + + const char *Integer::description_init = "[Integer"; + + Integer::Integer (const int lower_bound, + const int upper_bound) + : + lower_bound (lower_bound), + upper_bound (upper_bound) + {} + + + + bool Integer::match (const std::string &test_string) const + { + std::istringstream str(test_string); + + int i; + if (!(str >> i)) + return false; + + if (!has_only_whitespace (str)) + return false; + // check whether valid bounds + // were specified, and if so + // enforce their values + if (lower_bound <= upper_bound) + return ((lower_bound <= i) && + (upper_bound >= i)); + else + return true; + } + + + + std::string Integer::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + // check whether valid bounds + // were specified, and if so + // output their values + if (lower_bound <= upper_bound) + { + std::ostringstream description; + + description << description_init + <<" range " + << lower_bound << "..." << upper_bound + << " (inclusive)]"; + return description.str(); + } + else + // if no bounds were given, then + // return generic string + return "[Integer]"; + } + case Text: + { + if (lower_bound <= upper_bound) + { + std::ostringstream description; + + description << "An integer n such that " + << lower_bound << " <= n <= " << upper_bound; + + return description.str(); + } + else + return "An integer"; + } + case LaTeX: + { + if (lower_bound <= upper_bound) + { + std::ostringstream description; + + description << "An integer $n$ such that $" + << lower_bound << "\\leq n \\leq " << upper_bound + << "$"; + + return description.str(); + } + else + return "An integer"; + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr Integer::clone() const + { + return std::unique_ptr(new Integer(lower_bound, upper_bound)); + } + + + + std::unique_ptr Integer::create(const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + { + std::istringstream is(description); + + if (is.str().size() > strlen(description_init) + 1) + { +//TODO: verify that description matches the pattern "^\[Integer range \d+\.\.\.\d+\]$" + int lower_bound, upper_bound; + + is.ignore(strlen(description_init) + strlen(" range ")); + + if (!(is >> lower_bound)) + return std::unique_ptr(new Integer()); + + is.ignore(strlen("...")); + + if (!(is >> upper_bound)) + return std::unique_ptr(new Integer()); + + return std::unique_ptr(new Integer(lower_bound, upper_bound)); + } + else + return std::unique_ptr(new Integer()); + } + else + return std::unique_ptr(); + } + + + + const double Double::min_double_value = -std::numeric_limits::max(); + const double Double::max_double_value = std::numeric_limits::max(); + + const char *Double::description_init = "[Double"; + + Double::Double (const double lower_bound, + const double upper_bound) + : + lower_bound (lower_bound), + upper_bound (upper_bound) + {} + + + + bool Double::match (const std::string &test_string) const + { + std::istringstream str(test_string); + + double d; + str >> d; + if (str.fail()) + return false; + + if (!has_only_whitespace (str)) + return false; + // check whether valid bounds + // were specified, and if so + // enforce their values + if (lower_bound <= upper_bound) + return ((lower_bound <= d) && + (upper_bound >= d)); + else + return true; + } + + + + std::string Double::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + if (lower_bound <= upper_bound) + { + // bounds are valid + description << description_init << " "; + // We really want to compare with ==, but -Wfloat-equal would create + // a warning here, so work around it. + if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound))) + description << "-MAX_DOUBLE"; + else + description << lower_bound; + description << "..."; + if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound))) + description << "MAX_DOUBLE"; + else + description << upper_bound; + description << " (inclusive)]"; + return description.str(); + } + else + { + // invalid bounds, assume unbounded double: + description << description_init << "]"; + return description.str(); + } + } + case Text: + { + if (lower_bound <= upper_bound) + { + std::ostringstream description; + + description << "A floating point number v such that "; + if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound))) + description << "-MAX_DOUBLE"; + else + description << lower_bound; + description << " <= v <= "; + if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound))) + description << "MAX_DOUBLE"; + else + description << upper_bound; + + return description.str(); + } + else + return "A floating point number"; + } + case LaTeX: + { + if (lower_bound <= upper_bound) + { + std::ostringstream description; + + description << "A floating point number $v$ such that $"; + if (0==std::memcmp(&lower_bound, &min_double_value, sizeof(lower_bound))) + description << "-\\text{MAX\\_DOUBLE}"; + else + description << lower_bound; + description << " \\leq v \\leq "; + if (0==std::memcmp(&upper_bound, &max_double_value, sizeof(upper_bound))) + description << "\\text{MAX\\_DOUBLE}"; + else + description << upper_bound; + description << "$"; + + return description.str(); + } + else + return "A floating point number"; + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + std::unique_ptr Double::clone() const + { + return std::unique_ptr(new Double(lower_bound, upper_bound)); + } + + + + std::unique_ptr Double::create (const std::string &description) + { + const std::string description_init_str = description_init; + if (description.compare(0, description_init_str.size(), description_init_str) != 0) + return std::unique_ptr(); + if (*description.rbegin() != ']') + return std::unique_ptr(); + + std::string temp = description.substr(description_init_str.size()); + if (temp == "]") + return std::unique_ptr(new Double(1.0, -1.0)); // return an invalid range + + if (temp.find("...") != std::string::npos) + temp.replace(temp.find("..."), 3, " "); + + double lower_bound = min_double_value, + upper_bound = max_double_value; + + std::istringstream is(temp); + if (0 == temp.compare(0, std::strlen(" -MAX_DOUBLE"), " -MAX_DOUBLE")) + is.ignore(std::strlen(" -MAX_DOUBLE")); + else + { + // parse lower bound and give up if not a double + if (!(is >> lower_bound)) + return std::unique_ptr(); + } + + // ignore failure here and assume we got MAX_DOUBLE as upper bound: + is >> upper_bound; + if (is.fail()) + upper_bound = max_double_value; + + return std::unique_ptr(new Double(lower_bound, upper_bound)); + } + + + + const char *Selection::description_init = "[Selection"; + + + Selection::Selection (const std::string &seq) + : sequence(seq) + { + while (sequence.find(" |") != std::string::npos) + sequence.replace (sequence.find(" |"), 2, "|"); + while (sequence.find("| ") != std::string::npos) + sequence.replace (sequence.find("| "), 2, "|"); + } + + + + bool Selection::match (const std::string &test_string) const + { + std::string tmp(sequence); + + // remove whitespace at beginning + while ((tmp.length() != 0) && (std::isspace (tmp[0]))) + tmp.erase (0,1); + + // check the different possibilities + while (tmp.find('|') != std::string::npos) + { + if (test_string == std::string(tmp, 0, tmp.find('|'))) + return true; + + tmp.erase (0, tmp.find('|')+1); + }; + + //remove whitespace at the end + while ((tmp.length() != 0) && (std::isspace (*(tmp.end()-1)))) + tmp.erase (tmp.end()-1); + + // check last choice, not finished by | + if (test_string == tmp) + return true; + + // not found + return false; + } + + + + std::string Selection::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init + << " " + << sequence + << " ]"; + + return description.str(); + } + case Text: + case LaTeX: + { + std::ostringstream description; + + description << "Any one of " + << Utilities::replace_in_string(sequence,"|",", "); + + return description.str(); + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr Selection::clone() const + { + return std::unique_ptr(new Selection(sequence)); + } + + + std::size_t + Selection::memory_consumption () const + { + return (sizeof(PatternBase) + + MemoryConsumption::memory_consumption(sequence)); + } + + + + std::unique_ptr Selection::create(const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + { + std::string sequence(description); + + sequence.erase(0, std::strlen(description_init) + 1); + sequence.erase(sequence.length()-2, 2); + + return std::unique_ptr(new Selection(sequence)); + } + else + return std::unique_ptr(); + } + + + + const unsigned int List::max_int_value + = std::numeric_limits::max(); + + const char *List::description_init = "[List"; + + + List::List (const PatternBase &p, + const unsigned int min_elements, + const unsigned int max_elements, + const std::string &separator) + : + pattern (p.clone()), + min_elements (min_elements), + max_elements (max_elements), + separator (separator) + { + Assert (min_elements <= max_elements, + ExcInvalidRange (min_elements, max_elements)); + Assert (separator.size() > 0, + ExcMessage ("The separator must have a non-zero length.")); + } + + + + List::List (const List &other) + : + pattern (other.pattern->clone()), + min_elements (other.min_elements), + max_elements (other.max_elements), + separator (other.separator) + {} + + + const std::string &List::get_separator() const + { + return separator; + } + + + + const PatternBase &List::get_base_pattern() const + { + return *pattern; + } + + + + bool List::match (const std::string &test_string_list) const + { + const std::vector split_list = + Utilities::split_string_list(test_string_list, separator); + + if ((split_list.size() < min_elements) || + (split_list.size() > max_elements)) + return false; + + // check the different possibilities + for (const std::string &string : split_list) + if (pattern->match (string) == false) + return false; + + return true; + } + + + + std::string List::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init + << " of <" << pattern->description(style) << ">" + << " of length " << min_elements << "..." << max_elements + << " (inclusive)"; + if (separator != ",") + description << " separated by <" << separator << ">"; + description << "]"; + + return description.str(); + } + case Text: + case LaTeX: + { + std::ostringstream description; + + description << "A list of " + << min_elements << " to " << max_elements + << " elements "; + if (separator != ",") + description << "separated by <" << separator << "> "; + description << "where each element is [" + << pattern->description(style) + << "]"; + + return description.str(); + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr List::clone() const + { + return std::unique_ptr(new List(*pattern, min_elements, max_elements, separator)); + } + + + std::size_t + List::memory_consumption () const + { + return (sizeof(*this) + + MemoryConsumption::memory_consumption(*pattern) + + MemoryConsumption::memory_consumption(separator)); + } + + + + std::unique_ptr List::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + { + int min_elements, max_elements; + + std::istringstream is(description); + is.ignore(strlen(description_init) + strlen(" of <")); + + std::string str; + std::getline(is, str, '>'); + + std::shared_ptr base_pattern (pattern_factory(str)); + + is.ignore(strlen(" of length ")); + if (!(is >> min_elements)) + return std::unique_ptr(new List(*base_pattern)); + + is.ignore(strlen("...")); + if (!(is >> max_elements)) + return std::unique_ptr(new List(*base_pattern, min_elements)); + + is.ignore(strlen(" (inclusive) separated by <")); + std::string separator; + if (is) + std::getline(is, separator, '>'); + else + separator = ","; + + return std::unique_ptr(new List(*base_pattern, min_elements, max_elements, separator)); + } + else + return std::unique_ptr(); + } + + + + const unsigned int Map::max_int_value + = std::numeric_limits::max(); + + const char *Map::description_init = "[Map"; + + + Map::Map (const PatternBase &p_key, + const PatternBase &p_value, + const unsigned int min_elements, + const unsigned int max_elements, + const std::string &separator, + const std::string &key_value_separator) + : + key_pattern (p_key.clone()), + value_pattern (p_value.clone()), + min_elements (min_elements), + max_elements (max_elements), + separator (separator), + key_value_separator(key_value_separator) + { + Assert (min_elements <= max_elements, + ExcInvalidRange (min_elements, max_elements)); + Assert (separator.size() > 0, + ExcMessage ("The separator must have a non-zero length.")); + Assert (key_value_separator.size() > 0, + ExcMessage ("The key_value_separator must have a non-zero length.")); + Assert (separator != key_value_separator, + ExcMessage ("The separator can not be the same of the key_value_separator " + "since that is used as the separator between the two elements " + "of pairs")); + } + + + + Map::Map (const Map &other) + : + key_pattern (other.key_pattern->clone()), + value_pattern (other.value_pattern->clone()), + min_elements (other.min_elements), + max_elements (other.max_elements), + separator (other.separator), + key_value_separator(other.key_value_separator) + {} + + + + bool Map::match (const std::string &test_string_list) const + { + std::string tmp = test_string_list; + std::vector split_list = + Utilities::split_string_list(test_string_list, separator); + if ((split_list.size() < min_elements) || + (split_list.size() > max_elements)) + return false; + + for (auto &key_value_pair : split_list) + { + std::vector pair = + Utilities::split_string_list(key_value_pair, key_value_separator); + + // Check that we have in fact two mathces + if (pair.size() != 2) + return false; + + // then verify that the patterns are satisfied + if (key_pattern->match (pair[0]) == false) + return false; + if (value_pattern->match (pair[1]) == false) + return false; + } + + return true; + } + + + + std::string Map::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init + << " of <" + << key_pattern->description(style) << ">" + << key_value_separator << "<" + << value_pattern->description(style) << ">" + << " of length " << min_elements << "..." << max_elements + << " (inclusive)"; + if (separator != ",") + description << " separated by <" << separator << ">"; + description << "]"; + + return description.str(); + } + case Text: + case LaTeX: + { + std::ostringstream description; + + description << "A key" + << key_value_separator + << "value map of " + << min_elements << " to " << max_elements + << " elements "; + if (separator != ",") + description << " separated by <" << separator << "> "; + description << " where each key is [" + << key_pattern->description(style) + << "]" + << " and each value is [" + << value_pattern->description(style) + << "]"; + + return description.str(); + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr Map::clone() const + { + return std::unique_ptr(new Map(*key_pattern, *value_pattern, + min_elements, max_elements, + separator, key_value_separator)); + } + + + std::size_t + Map::memory_consumption () const + { + return (sizeof(*this) + + MemoryConsumption::memory_consumption (*key_pattern) + + MemoryConsumption::memory_consumption (*value_pattern) + + MemoryConsumption::memory_consumption (separator)+ + MemoryConsumption::memory_consumption (key_value_separator)); + } + + + + std::unique_ptr Map::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + { + int min_elements, max_elements; + + std::istringstream is(description); + is.ignore(strlen(description_init) + strlen(" of <")); + + std::string key; + std::getline(is, key, '>'); + + std::string key_value_separator; + std::getline(is, key_value_separator, '<'); + + // split 'str' into key and value + std::string value; + std::getline(is, value, '>'); + + std::shared_ptr key_pattern (pattern_factory(key)); + std::shared_ptr value_pattern (pattern_factory(value)); + + is.ignore(strlen(" of length ")); + if (!(is >> min_elements)) + return std::unique_ptr(new Map(*key_pattern, *value_pattern)); + + is.ignore(strlen("...")); + if (!(is >> max_elements)) + return std::unique_ptr(new Map(*key_pattern, *value_pattern, min_elements)); + + is.ignore(strlen(" (inclusive) separated by <")); + std::string separator; + if (is) + std::getline(is, separator, '>'); + else + separator = ","; + + return std::unique_ptr(new Map(*key_pattern, *value_pattern, + min_elements, max_elements, + separator, key_value_separator)); + } + else + return std::unique_ptr(); + } + + + + const PatternBase &Map::get_key_pattern() const + { + return *key_pattern; + } + + + + const PatternBase &Map::get_value_pattern() const + { + return *value_pattern; + } + + + + const std::string &Map::get_separator() const + { + return separator; + } + + + const std::string &Map::get_key_value_separator() const + { + return key_value_separator; + } + + + const char *MultipleSelection::description_init = "[MultipleSelection"; + + + MultipleSelection::MultipleSelection (const std::string &seq) + { + Assert (seq.find (",") == std::string::npos, ExcCommasNotAllowed(seq.find(","))); + + sequence = seq; + while (sequence.find(" |") != std::string::npos) + sequence.replace (sequence.find(" |"), 2, "|"); + while (sequence.find("| ") != std::string::npos) + sequence.replace (sequence.find("| "), 2, "|"); + } + + + + bool MultipleSelection::match (const std::string &test_string_list) const + { + std::string tmp = test_string_list; + std::vector split_names; + + // first split the input list + while (tmp.length() != 0) + { + std::string name; + name = tmp; + + if (name.find(",") != std::string::npos) + { + name.erase (name.find(","), std::string::npos); + tmp.erase (0, tmp.find(",")+1); + } + else + tmp = ""; + + while ((name.length() != 0) && + (std::isspace (name[0]))) + name.erase (0,1); + while (std::isspace (name[name.length()-1])) + name.erase (name.length()-1, 1); + + split_names.push_back (name); + }; + + + // check the different possibilities + for (std::vector::const_iterator test_string = split_names.begin(); + test_string != split_names.end(); ++test_string) + { + bool string_found = false; + + tmp = sequence; + while (tmp.find('|') != std::string::npos) + { + if (*test_string == std::string(tmp, 0, tmp.find('|'))) + { + // string found, quit + // loop. don't change + // tmp, since we don't + // need it anymore. + string_found = true; + break; + }; + + tmp.erase (0, tmp.find('|')+1); + }; + // check last choice, not finished by | + if (!string_found) + if (*test_string == tmp) + string_found = true; + + if (!string_found) + return false; + }; + + return true; + } + + + + std::string MultipleSelection::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init + << " " + << sequence + << " ]"; + + return description.str(); + } + case Text: + case LaTeX: + { + std::ostringstream description; + + description << "A comma-separated list of any of " + << Utilities::replace_in_string(sequence,"|",", "); + + return description.str(); + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr MultipleSelection::clone() const + { + return std::unique_ptr(new MultipleSelection(sequence)); + } + + + std::size_t + MultipleSelection::memory_consumption () const + { + return (sizeof(PatternBase) + + MemoryConsumption::memory_consumption(sequence)); + } + + + + std::unique_ptr MultipleSelection::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + { + std::string sequence(description); + + sequence.erase(0, std::strlen(description_init) + 1); + sequence.erase(sequence.length()-2, 2); + + return std::unique_ptr(new MultipleSelection(sequence)); + } + else + return std::unique_ptr(); + } + + + + const char *Bool::description_init = "[Bool"; + + + Bool::Bool () + : + Selection ("true|false") + {} + + + + std::string Bool::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init + << "]"; + + return description.str(); + } + case Text: + case LaTeX: + { + return "A boolean value (true or false)"; + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr Bool::clone() const + { + return std::unique_ptr(new Bool()); + } + + + + std::unique_ptr Bool::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + return std::unique_ptr(new Bool()); + else + return std::unique_ptr(); + } + + + + const char *Anything::description_init = "[Anything"; + + + Anything::Anything () + {} + + + + bool Anything::match (const std::string &) const + { + return true; + } + + + + std::string Anything::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init + << "]"; + + return description.str(); + } + case Text: + case LaTeX: + { + return "Any string"; + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr Anything::clone() const + { + return std::unique_ptr(new Anything()); + } + + + + std::unique_ptr Anything::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + return std::unique_ptr(new Anything()); + else + return std::unique_ptr(); + } + + + + const char *FileName::description_init = "[FileName"; + + + FileName::FileName (const FileType type) + : file_type (type) + {} + + + + bool FileName::match (const std::string &) const + { + return true; + } + + + + std::string FileName::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init; + + if (file_type == input) + description << " (Type: input)]"; + else + description << " (Type: output)]"; + + return description.str(); + } + case Text: + case LaTeX: + { + if (file_type == input) + return "an input filename"; + else + return "an output filename"; + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr FileName::clone() const + { + return std::unique_ptr(new FileName(file_type)); + } + + + + std::unique_ptr FileName::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + { + std::istringstream is(description); + std::string file_type; + FileType type; + + is.ignore(strlen(description_init) + strlen(" (Type:")); + + is >> file_type; + + if (file_type == "input)]") + type = input; + else + type = output; + + return std::unique_ptr(new FileName(type)); + } + else + return std::unique_ptr(); + } + + + + const char *DirectoryName::description_init = "[DirectoryName"; + + + DirectoryName::DirectoryName () + {} + + + + bool DirectoryName::match (const std::string &) const + { + return true; + } + + + + std::string DirectoryName::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init << "]"; + + return description.str(); + } + case Text: + case LaTeX: + { + return "A directory name"; + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr DirectoryName::clone() const + { + return std::unique_ptr(new DirectoryName()); + } + + + + std::unique_ptr DirectoryName::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + return std::unique_ptr(new DirectoryName()); + else + return std::unique_ptr(); + } + +} // end namespace Patterns + +DEAL_II_NAMESPACE_CLOSE -- 2.39.5