]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Moved Patterns namespace in its own file.
authorLuca Heltai <luca.heltai@sissa.it>
Thu, 20 Jul 2017 16:37:57 +0000 (18:37 +0200)
committerLuca Heltai <luca.heltai@sissa.it>
Sun, 23 Jul 2017 14:57:30 +0000 (16:57 +0200)
include/deal.II/base/parameter_handler.h
include/deal.II/base/patterns.h [new file with mode: 0644]
source/base/CMakeLists.txt
source/base/parameter_handler.cc
source/base/patterns.cc [new file with mode: 0644]

index d0806054dc20c77ce63f8d60e3f8807d9eed025c..14c5f833c9720af1a86cc4290990793546e0550b 100644 (file)
@@ -20,6 +20,7 @@
 #include <deal.II/base/config.h>
 #include <deal.II/base/exceptions.h>
 #include <deal.II/base/subscriptor.h>
+#include <deal.II/base/patterns.h>
 
 #include <boost/property_tree/ptree_fwd.hpp>
 #include <boost/serialization/split_member.hpp>
@@ -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 <tt>clone</tt> 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 <tt>true</tt> 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<PatternBase> 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<PatternBase> 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 <tt>true</tt> 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<PatternBase> 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<Integer> 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 <tt>double</tt>. 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
-     * <tt>std::numeric_limits</tt>.
-     */
-    static const double min_double_value;
-
-    /**
-     * Maximal double value used as default value, taken from
-     * <tt>std::numeric_limits</tt>.
-     */
-    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 <tt>true</tt> 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<PatternBase> 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<Double> 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 <tt>"red|blue|black"</tt>, then the
-   * @ref match
-   * function returns <tt>true</tt> 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 <tt>true</tt> 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<PatternBase> 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<Selection> 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 <tt>true</tt> 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<PatternBase> 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<List> 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<PatternBase> 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 <code>key: value</code>. In other words, a
-   * map is described in the form <code>key1: value1, key2: value2, key3:
-   * value3, ...</code>. 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 <tt>true</tt> 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<PatternBase> 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<Map> 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<PatternBase> key_pattern;
-    std::unique_ptr<PatternBase> 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 <tt>"ucd|gmv|eps"</tt>,
-   * 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 <tt>true</tt> 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<PatternBase> 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<MultipleSelection> 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<PatternBase> 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<Bool> create(const std::string &description);
-
-  private:
-    /**
-     * Initial part of description
-     */
-    static const char *description_init;
-  };
-
-  /**
-   * Always returns <tt>true</tt> 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 <tt>true</tt> 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 <tt>"[Anything]"</tt>.
-     */
-    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<PatternBase> 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<Anything> 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 <i>intent</i> 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 <tt>type</tt>.
-     */
-    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 <tt>true</tt> 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 <tt>"[Filename]"</tt>.
-     */
-    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<PatternBase> 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<FileName> 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 <i>intent</i> 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 <tt>true</tt> 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 <tt>"[Filename]"</tt>.
-     */
-    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<PatternBase> 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<DirectoryName> 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 (file)
index 0000000..905d8e7
--- /dev/null
@@ -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 <deal.II/base/config.h>
+#include <deal.II/base/exceptions.h>
+#include <deal.II/base/subscriptor.h>
+
+#include <boost/property_tree/ptree_fwd.hpp>
+#include <boost/serialization/split_member.hpp>
+#include <boost/archive/basic_archive.hpp>
+#include <boost/property_tree/ptree_serialization.hpp>
+
+#include <map>
+#include <vector>
+#include <string>
+#include <memory>
+
+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 <tt>clone</tt> 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 <tt>true</tt> 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<PatternBase> 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<PatternBase> 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 <tt>true</tt> 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<PatternBase> 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<Integer> 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 <tt>double</tt>. 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
+     * <tt>std::numeric_limits</tt>.
+     */
+    static const double min_double_value;
+
+    /**
+     * Maximal double value used as default value, taken from
+     * <tt>std::numeric_limits</tt>.
+     */
+    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 <tt>true</tt> 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<PatternBase> 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<Double> 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 <tt>"red|blue|black"</tt>, then the
+   * @ref match
+   * function returns <tt>true</tt> 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 <tt>true</tt> 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<PatternBase> 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<Selection> 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 <tt>true</tt> 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<PatternBase> 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<List> 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<PatternBase> 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 <code>key: value</code>. In other words, a
+   * map is described in the form <code>key1: value1, key2: value2, key3:
+   * value3, ...</code>. 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 <tt>true</tt> 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<PatternBase> 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<Map> 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<PatternBase> key_pattern;
+    std::unique_ptr<PatternBase> 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 <tt>"ucd|gmv|eps"</tt>,
+   * 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 <tt>true</tt> 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<PatternBase> 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<MultipleSelection> 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<PatternBase> 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<Bool> create(const std::string &description);
+
+  private:
+    /**
+     * Initial part of description
+     */
+    static const char *description_init;
+  };
+
+  /**
+   * Always returns <tt>true</tt> 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 <tt>true</tt> 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 <tt>"[Anything]"</tt>.
+     */
+    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<PatternBase> 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<Anything> 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 <i>intent</i> 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 <tt>type</tt>.
+     */
+    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 <tt>true</tt> 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 <tt>"[Filename]"</tt>.
+     */
+    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<PatternBase> 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<FileName> 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 <i>intent</i> 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 <tt>true</tt> 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 <tt>"[Filename]"</tt>.
+     */
+    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<PatternBase> 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<DirectoryName> create(const std::string &description);
+
+  private:
+    /**
+     * Initial part of description
+     */
+    static const char *description_init;
+  };
+}
+
+DEAL_II_NAMESPACE_CLOSE
+
+#endif
index 4625cb74183eead0cac8544f0d0b6f1129010475..87cd9809bd557c08f1fe050f4855d115536aa995 100644 (file)
@@ -44,6 +44,7 @@ SET(_src
   parameter_handler.cc
   parsed_function.cc
   partitioner.cc
+  patterns.cc
   path_search.cc
   polynomial.cc
   polynomials_abf.cc
index c8626df734bd8adec802f6401cad587c6cb8154f..55c45e49abfd4aec0e9df8585349a0e1d0627da6 100644 (file)
@@ -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<PatternBase> pattern_factory(const std::string &description)
-  {
-    std::unique_ptr<PatternBase> 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<const Integer *>(this) != nullptr)
-      return sizeof(Integer);
-    else if (dynamic_cast<const Double *>(this) != nullptr)
-      return sizeof(Double);
-    else if (dynamic_cast<const Bool *>(this) != nullptr)
-      return sizeof(Bool);
-    else if (dynamic_cast<const Anything *>(this) != nullptr)
-      return sizeof(Anything);
-    else
-      return sizeof(*this) + 32;
-  }
-
-
-
-  const int Integer::min_int_value = std::numeric_limits<int>::min();
-  const int Integer::max_int_value = std::numeric_limits<int>::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<PatternBase> Integer::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new Integer(lower_bound, upper_bound));
-  }
-
-
-
-  std::unique_ptr<Integer> 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<Integer>(new Integer());
-
-            is.ignore(strlen("..."));
-
-            if (!(is >> upper_bound))
-              return std::unique_ptr<Integer>(new Integer());
-
-            return std::unique_ptr<Integer>(new Integer(lower_bound, upper_bound));
-          }
-        else
-          return std::unique_ptr<Integer>(new Integer());
-      }
-    else
-      return std::unique_ptr<Integer>();
-  }
-
-
-
-  const double Double::min_double_value = -std::numeric_limits<double>::max();
-  const double Double::max_double_value = std::numeric_limits<double>::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<PatternBase> Double::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new Double(lower_bound, upper_bound));
-  }
-
-
-
-  std::unique_ptr<Double> 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<Double>();
-    if (*description.rbegin() != ']')
-      return std::unique_ptr<Double>();
-
-    std::string temp = description.substr(description_init_str.size());
-    if (temp == "]")
-      return std::unique_ptr<Double>(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<Double>();
-      }
-
-    // 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<Double>(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<PatternBase> Selection::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new Selection(sequence));
-  }
-
-
-  std::size_t
-  Selection::memory_consumption () const
-  {
-    return (sizeof(PatternBase) +
-            MemoryConsumption::memory_consumption(sequence));
-  }
-
-
-
-  std::unique_ptr<Selection> 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<Selection>(new Selection(sequence));
-      }
-    else
-      return std::unique_ptr<Selection>();
-  }
-
-
-
-  const unsigned int List::max_int_value
-    = std::numeric_limits<unsigned int>::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<std::string> 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<PatternBase> List::clone() const
-  {
-    return std::unique_ptr<PatternBase>(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> 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<PatternBase> base_pattern (pattern_factory(str));
-
-        is.ignore(strlen(" of length "));
-        if (!(is >> min_elements))
-          return std::unique_ptr<List>(new List(*base_pattern));
-
-        is.ignore(strlen("..."));
-        if (!(is >> max_elements))
-          return std::unique_ptr<List>(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<List>(new List(*base_pattern, min_elements, max_elements, separator));
-      }
-    else
-      return std::unique_ptr<List>();
-  }
-
-
-
-  const unsigned int Map::max_int_value
-    = std::numeric_limits<unsigned int>::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 <key:value> 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<std::string> 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<std::string> 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<PatternBase> Map::clone() const
-  {
-    return std::unique_ptr<PatternBase>(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> 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<PatternBase> key_pattern (pattern_factory(key));
-        std::shared_ptr<PatternBase> value_pattern (pattern_factory(value));
-
-        is.ignore(strlen(" of length "));
-        if (!(is >> min_elements))
-          return std::unique_ptr<Map>(new Map(*key_pattern, *value_pattern));
-
-        is.ignore(strlen("..."));
-        if (!(is >> max_elements))
-          return std::unique_ptr<Map>(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<Map>(new Map(*key_pattern, *value_pattern,
-                                            min_elements, max_elements,
-                                            separator, key_value_separator));
-      }
-    else
-      return std::unique_ptr<Map>();
-  }
-
-
-
-  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<std::string> 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<std::string>::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<PatternBase> MultipleSelection::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new MultipleSelection(sequence));
-  }
-
-
-  std::size_t
-  MultipleSelection::memory_consumption () const
-  {
-    return (sizeof(PatternBase) +
-            MemoryConsumption::memory_consumption(sequence));
-  }
-
-
-
-  std::unique_ptr<MultipleSelection> 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<MultipleSelection>(new MultipleSelection(sequence));
-      }
-    else
-      return std::unique_ptr<MultipleSelection>();
-  }
-
-
-
-  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<PatternBase> Bool::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new Bool());
-  }
-
-
-
-  std::unique_ptr<Bool> Bool::create (const std::string &description)
-  {
-    if (description.compare(0, std::strlen(description_init), description_init) == 0)
-      return std::unique_ptr<Bool>(new Bool());
-    else
-      return std::unique_ptr<Bool>();
-  }
-
-
-
-  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<PatternBase> Anything::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new Anything());
-  }
-
-
-
-  std::unique_ptr<Anything> Anything::create (const std::string &description)
-  {
-    if (description.compare(0, std::strlen(description_init), description_init) == 0)
-      return std::unique_ptr<Anything>(new Anything());
-    else
-      return std::unique_ptr<Anything>();
-  }
-
-
-
-  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<PatternBase> FileName::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new FileName(file_type));
-  }
-
-
-
-  std::unique_ptr<FileName> 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<FileName>(new FileName(type));
-      }
-    else
-      return std::unique_ptr<FileName>();
-  }
-
-
-
-  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<PatternBase> DirectoryName::clone() const
-  {
-    return std::unique_ptr<PatternBase>(new DirectoryName());
-  }
-
-
-
-  std::unique_ptr<DirectoryName> DirectoryName::create (const std::string &description)
-  {
-    if (description.compare(0, std::strlen(description_init), description_init) == 0)
-      return std::unique_ptr<DirectoryName>(new DirectoryName());
-    else
-      return std::unique_ptr<DirectoryName>();
-  }
-
-}   // 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 (file)
index 0000000..ddcacf0
--- /dev/null
@@ -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 <deal.II/base/patterns.h>
+#include <deal.II/base/logstream.h>
+#include <deal.II/base/path_search.h>
+#include <deal.II/base/memory_consumption.h>
+#include <deal.II/base/utilities.h>
+
+DEAL_II_DISABLE_EXTRA_DIAGNOSTICS
+#include <boost/property_tree/ptree.hpp>
+#include <boost/property_tree/xml_parser.hpp>
+#include <boost/property_tree/json_parser.hpp>
+
+#include <boost/io/ios_state.hpp>
+DEAL_II_ENABLE_EXTRA_DIAGNOSTICS
+
+#include <fstream>
+#include <iostream>
+#include <iomanip>
+#include <cstdlib>
+#include <algorithm>
+#include <sstream>
+#include <cctype>
+#include <limits>
+#include <cstring>
+
+
+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<PatternBase> pattern_factory(const std::string &description)
+  {
+    std::unique_ptr<PatternBase> 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<const Integer *>(this) != nullptr)
+      return sizeof(Integer);
+    else if (dynamic_cast<const Double *>(this) != nullptr)
+      return sizeof(Double);
+    else if (dynamic_cast<const Bool *>(this) != nullptr)
+      return sizeof(Bool);
+    else if (dynamic_cast<const Anything *>(this) != nullptr)
+      return sizeof(Anything);
+    else
+      return sizeof(*this) + 32;
+  }
+
+
+
+  const int Integer::min_int_value = std::numeric_limits<int>::min();
+  const int Integer::max_int_value = std::numeric_limits<int>::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<PatternBase> Integer::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new Integer(lower_bound, upper_bound));
+  }
+
+
+
+  std::unique_ptr<Integer> 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<Integer>(new Integer());
+
+            is.ignore(strlen("..."));
+
+            if (!(is >> upper_bound))
+              return std::unique_ptr<Integer>(new Integer());
+
+            return std::unique_ptr<Integer>(new Integer(lower_bound, upper_bound));
+          }
+        else
+          return std::unique_ptr<Integer>(new Integer());
+      }
+    else
+      return std::unique_ptr<Integer>();
+  }
+
+
+
+  const double Double::min_double_value = -std::numeric_limits<double>::max();
+  const double Double::max_double_value = std::numeric_limits<double>::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<PatternBase> Double::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new Double(lower_bound, upper_bound));
+  }
+
+
+
+  std::unique_ptr<Double> 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<Double>();
+    if (*description.rbegin() != ']')
+      return std::unique_ptr<Double>();
+
+    std::string temp = description.substr(description_init_str.size());
+    if (temp == "]")
+      return std::unique_ptr<Double>(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<Double>();
+      }
+
+    // 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<Double>(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<PatternBase> Selection::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new Selection(sequence));
+  }
+
+
+  std::size_t
+  Selection::memory_consumption () const
+  {
+    return (sizeof(PatternBase) +
+            MemoryConsumption::memory_consumption(sequence));
+  }
+
+
+
+  std::unique_ptr<Selection> 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<Selection>(new Selection(sequence));
+      }
+    else
+      return std::unique_ptr<Selection>();
+  }
+
+
+
+  const unsigned int List::max_int_value
+    = std::numeric_limits<unsigned int>::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<std::string> 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<PatternBase> List::clone() const
+  {
+    return std::unique_ptr<PatternBase>(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> 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<PatternBase> base_pattern (pattern_factory(str));
+
+        is.ignore(strlen(" of length "));
+        if (!(is >> min_elements))
+          return std::unique_ptr<List>(new List(*base_pattern));
+
+        is.ignore(strlen("..."));
+        if (!(is >> max_elements))
+          return std::unique_ptr<List>(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<List>(new List(*base_pattern, min_elements, max_elements, separator));
+      }
+    else
+      return std::unique_ptr<List>();
+  }
+
+
+
+  const unsigned int Map::max_int_value
+    = std::numeric_limits<unsigned int>::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 <key:value> 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<std::string> 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<std::string> 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<PatternBase> Map::clone() const
+  {
+    return std::unique_ptr<PatternBase>(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> 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<PatternBase> key_pattern (pattern_factory(key));
+        std::shared_ptr<PatternBase> value_pattern (pattern_factory(value));
+
+        is.ignore(strlen(" of length "));
+        if (!(is >> min_elements))
+          return std::unique_ptr<Map>(new Map(*key_pattern, *value_pattern));
+
+        is.ignore(strlen("..."));
+        if (!(is >> max_elements))
+          return std::unique_ptr<Map>(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<Map>(new Map(*key_pattern, *value_pattern,
+                                            min_elements, max_elements,
+                                            separator, key_value_separator));
+      }
+    else
+      return std::unique_ptr<Map>();
+  }
+
+
+
+  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<std::string> 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<std::string>::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<PatternBase> MultipleSelection::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new MultipleSelection(sequence));
+  }
+
+
+  std::size_t
+  MultipleSelection::memory_consumption () const
+  {
+    return (sizeof(PatternBase) +
+            MemoryConsumption::memory_consumption(sequence));
+  }
+
+
+
+  std::unique_ptr<MultipleSelection> 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<MultipleSelection>(new MultipleSelection(sequence));
+      }
+    else
+      return std::unique_ptr<MultipleSelection>();
+  }
+
+
+
+  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<PatternBase> Bool::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new Bool());
+  }
+
+
+
+  std::unique_ptr<Bool> Bool::create (const std::string &description)
+  {
+    if (description.compare(0, std::strlen(description_init), description_init) == 0)
+      return std::unique_ptr<Bool>(new Bool());
+    else
+      return std::unique_ptr<Bool>();
+  }
+
+
+
+  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<PatternBase> Anything::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new Anything());
+  }
+
+
+
+  std::unique_ptr<Anything> Anything::create (const std::string &description)
+  {
+    if (description.compare(0, std::strlen(description_init), description_init) == 0)
+      return std::unique_ptr<Anything>(new Anything());
+    else
+      return std::unique_ptr<Anything>();
+  }
+
+
+
+  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<PatternBase> FileName::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new FileName(file_type));
+  }
+
+
+
+  std::unique_ptr<FileName> 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<FileName>(new FileName(type));
+      }
+    else
+      return std::unique_ptr<FileName>();
+  }
+
+
+
+  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<PatternBase> DirectoryName::clone() const
+  {
+    return std::unique_ptr<PatternBase>(new DirectoryName());
+  }
+
+
+
+  std::unique_ptr<DirectoryName> DirectoryName::create (const std::string &description)
+  {
+    if (description.compare(0, std::strlen(description_init), description_init) == 0)
+      return std::unique_ptr<DirectoryName>(new DirectoryName());
+    else
+      return std::unique_ptr<DirectoryName>();
+  }
+
+}   // end namespace Patterns
+
+DEAL_II_NAMESPACE_CLOSE

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

Douglas Adams


Typeset in Trocchi and Trocchi Bold Sans Serif.