From 5a1664fda7df69e24739fb01c77649550a83c0e6 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Thu, 26 Oct 2017 12:10:35 +0200 Subject: [PATCH] New tuple pattern. --- doc/news/changes/minor/20171026LucaHeltai | 4 + include/deal.II/base/patterns.h | 92 +++++++++++ source/base/patterns.cc | 179 ++++++++++++++++++++++ tests/base/patterns_08.cc | 47 ++++++ tests/base/patterns_08.output | 2 + tests/base/patterns_09.cc | 43 ++++++ tests/base/patterns_09.output | 3 + 7 files changed, 370 insertions(+) create mode 100644 doc/news/changes/minor/20171026LucaHeltai create mode 100644 tests/base/patterns_08.cc create mode 100644 tests/base/patterns_08.output create mode 100644 tests/base/patterns_09.cc create mode 100644 tests/base/patterns_09.output diff --git a/doc/news/changes/minor/20171026LucaHeltai b/doc/news/changes/minor/20171026LucaHeltai new file mode 100644 index 0000000000..b74c649a51 --- /dev/null +++ b/doc/news/changes/minor/20171026LucaHeltai @@ -0,0 +1,4 @@ +New:Created a new Patterns::Tuple class, that allows parsing arbitrary tuples +of objects in parameter files. +
+(Luca Heltai, 2017/10/26) diff --git a/include/deal.II/base/patterns.h b/include/deal.II/base/patterns.h index b6d168d2e7..60e1fd1da9 100644 --- a/include/deal.II/base/patterns.h +++ b/include/deal.II/base/patterns.h @@ -661,6 +661,98 @@ namespace Patterns }; + + /** + * This pattern matches comma-separated values of arbitrary types. Each type + * has to match a pattern given to the constructor. + * + * The constructor expects a vector of Patterns, and optionally an + * std::string, specifying the separator to use when parsing the Tuple from a + * string. + */ + class Tuple : public PatternBase + { + public: + /** + * Constructor. Specify each pattern that the Tuple should contain. + * + * Optionally specify a separator string. + */ + + /** + * Constructor. + * @param patterns The pattern each object of the Tuple should match + * @param separator An optional string used to delimit each element + */ + Tuple (const std::vector > &patterns, + const std::string &separator = ","); + + /** + * Copy constructor. + */ + Tuple (const Tuple &other); + + /** + * Return true if the string is a list of strings + * each of which matches the patterns given to the constructor. + */ + virtual bool match (const std::string &test_string) const; + + /** + * Return a description of the pattern that valid strings are expected to + * match. + */ + virtual std::string description (const OutputStyle style=Machine) const; + + /** + * Return a copy of the present object, which is newly allocated on the + * heap. Ownership of that object is transferred to the caller of this + * function. + */ + virtual std::unique_ptr clone () const; + + /** + * Creates new object if the start of description matches + * description_init. Ownership of that object is transferred to the + * caller of this function. + */ + static std::unique_ptr create (const std::string &description); + + /** + * Determine an estimate for the memory consumption (in bytes) of this + * object. + */ + std::size_t memory_consumption () const; + + /** + * Return a reference to the i-th pattern in the tuple. + */ + const PatternBase &get_pattern(const unsigned int &i) const; + + /** + * Return the separator of the tuple entries. + */ + const std::string &get_separator() const; + + private: + /** + * Copy of the patterns stored in the Tuple. + */ + std::vector > patterns; + + /** + * Separator between elements of the list. + */ + const std::string 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 diff --git a/source/base/patterns.cc b/source/base/patterns.cc index 7057a733bc..4d56e88b62 100644 --- a/source/base/patterns.cc +++ b/source/base/patterns.cc @@ -946,6 +946,185 @@ namespace Patterns } + + const char *Tuple::description_init = "[Tuple"; + + + Tuple::Tuple (const std::vector > &ps, + const std::string &separator) + : + separator (separator) + { + Assert (ps.size() > 0, + ExcMessage ("The Patterns list must have a non-zero length.")); + Assert (separator.size() > 0, + ExcMessage ("The separator must have a non-zero length.")); + patterns.resize(ps.size()); + for (unsigned int i=0; iclone(); + } + + + + Tuple::Tuple (const Tuple &other) + : + separator (other.separator) + { + patterns.resize(other.patterns.size()); + for (unsigned int i=0; iclone(); + } + + + + bool Tuple::match (const std::string &test_string_list) const + { + std::vector split_list = + Utilities::split_string_list(test_string_list, separator); + if (split_list.size() != patterns.size()) + return false; + + for (unsigned int i=0; imatch (split_list[i]) == false) + return false; + } + + return true; + } + + + + std::string Tuple::description (const OutputStyle style) const + { + switch (style) + { + case Machine: + { + std::ostringstream description; + + description << description_init + << " of <" + << patterns.size() << "> elements <" + << patterns[0]->description(style) + << ">"; + for (unsigned int i=1; idescription(style) + << ">"; + + if (separator != ",") + description << " separated by <" << separator << ">"; + description << "]"; + + return description.str(); + } + case Text: + case LaTeX: + { + std::ostringstream description; + + description << "A Tuple of " + << patterns.size() + << " elements "; + if (separator != ",") + description << " separated by <" << separator << "> "; + description << " where each element is [" + << patterns[0]->description(style) + << "]"; + for (unsigned int i=1; idescription(style) << "]"; + + return description.str(); + } + } + default: + AssertThrow(false, ExcNotImplemented()); + } + // Should never occur without an exception, but prevent compiler from + // complaining + return ""; + } + + + + std::unique_ptr Tuple::clone() const + { + return std::unique_ptr(new Tuple(patterns, separator)); + } + + + std::size_t + Tuple::memory_consumption () const + { + return (sizeof(*this) + + MemoryConsumption::memory_consumption (patterns) + + MemoryConsumption::memory_consumption (separator)); + } + + + + std::unique_ptr Tuple::create (const std::string &description) + { + if (description.compare(0, std::strlen(description_init), description_init) == 0) + { + std::vector > patterns; + + std::istringstream is(description); + is.ignore(strlen(description_init) + strlen(" of <")); + + std::string len; + std::getline(is, len, '>'); + const unsigned int n_elements = Utilities::string_to_int(len); + Assert(n_elements>0, + ExcMessage("Provide at least 1 element in the tuple.")); + patterns.resize(n_elements); + + is.ignore(strlen(" elements <")); + + std::string element; + std::getline(is, element, '>'); + patterns[0] = pattern_factory(element); + + for (unsigned int i=1; i'); + patterns[i] = pattern_factory(element); + } + + is.ignore(strlen(" separated by <")); + + std::string separator; + if (is) + std::getline(is, separator, '>'); + else + separator = ","; + + return std::unique_ptr(new Tuple(patterns,separator)); + } + else + return std::unique_ptr(); + } + + + + const PatternBase &Tuple::get_pattern(const unsigned int &i) const + { + return *patterns[i]; + } + + + + const std::string &Tuple::get_separator() const + { + return separator; + } + + + const char *MultipleSelection::description_init = "[MultipleSelection"; diff --git a/tests/base/patterns_08.cc b/tests/base/patterns_08.cc new file mode 100644 index 0000000000..b736dd350a --- /dev/null +++ b/tests/base/patterns_08.cc @@ -0,0 +1,47 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2005 - 2015 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 "../tests.h" +#include +#include +#include + +int main() +{ + initlog(); + + // create a pattern and let it + // output its description + std::vector > ps; + ps.push_back(std_cxx14::make_unique()); + ps.push_back(std_cxx14::make_unique()); + ps.push_back(std_cxx14::make_unique()); + + Patterns::Tuple pattern(ps, ";"); + const std::string desc = pattern.description(); + + // now let the same class re-create + // a pattern object from the + // description and verify that the + // result is the same as what we + // started out with + std::unique_ptr pattern2 = Patterns::Tuple::create (desc); + + AssertThrow (pattern2 != nullptr, ExcInternalError()); + AssertThrow (desc == pattern2->description(), ExcInternalError()); + + deallog << desc << std::endl; +} diff --git a/tests/base/patterns_08.output b/tests/base/patterns_08.output new file mode 100644 index 0000000000..774b01de06 --- /dev/null +++ b/tests/base/patterns_08.output @@ -0,0 +1,2 @@ + +DEAL::[Tuple of <3> elements <[Integer range -2147483648...2147483647 (inclusive)]>, <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]>, <[Anything]> separated by <;>] diff --git a/tests/base/patterns_09.cc b/tests/base/patterns_09.cc new file mode 100644 index 0000000000..6b469a6319 --- /dev/null +++ b/tests/base/patterns_09.cc @@ -0,0 +1,43 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2005 - 2015 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 "../tests.h" +#include +#include +#include + +int main() +{ + initlog(); + + // create a pattern and match a string + std::vector > ps; + ps.push_back(std_cxx14::make_unique()); + ps.push_back(std_cxx14::make_unique()); + ps.push_back(std_cxx14::make_unique()); + + Patterns::Tuple pattern(ps, ";"); + const std::string desc = pattern.description(); + + deallog << desc << std::endl; + + std::string test = "5; 3.14; Ciao"; + + if (pattern.match(test)) + deallog << "OK" << std::endl; + else + deallog << "Not OK" << std::endl; +} diff --git a/tests/base/patterns_09.output b/tests/base/patterns_09.output new file mode 100644 index 0000000000..d24657a065 --- /dev/null +++ b/tests/base/patterns_09.output @@ -0,0 +1,3 @@ + +DEAL::[Tuple of <3> elements <[Integer range -2147483648...2147483647 (inclusive)]>, <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]>, <[Anything]> separated by <;>] +DEAL::OK -- 2.39.5