From 852db02945e4eedf251d528d701b0c2b10a368c2 Mon Sep 17 00:00:00 2001 From: Luca Heltai Date: Wed, 14 Jun 2017 17:54:36 +0200 Subject: [PATCH] Added new parameter to Patterns::Map --- doc/news/changes/minor/20170614LucaHeltai-b | 5 + include/deal.II/base/parameter_handler.h | 20 +++- source/base/parameter_handler.cc | 122 ++++++++------------ tests/base/patterns_04.cc | 74 ++++++++++++ tests/base/patterns_04.output | 41 +++++++ 5 files changed, 184 insertions(+), 78 deletions(-) create mode 100644 doc/news/changes/minor/20170614LucaHeltai-b create mode 100644 tests/base/patterns_04.cc create mode 100644 tests/base/patterns_04.output diff --git a/doc/news/changes/minor/20170614LucaHeltai-b b/doc/news/changes/minor/20170614LucaHeltai-b new file mode 100644 index 0000000000..6518c6a759 --- /dev/null +++ b/doc/news/changes/minor/20170614LucaHeltai-b @@ -0,0 +1,5 @@ +New: Patterns::Map now accepts a new optional parameter, +that allows to specify also the separator between +key-value pairs. +
+(Luca Heltai, 2017/06/14) diff --git a/include/deal.II/base/parameter_handler.h b/include/deal.II/base/parameter_handler.h index 9e35f26f48..f80fa5bbf6 100644 --- a/include/deal.II/base/parameter_handler.h +++ b/include/deal.II/base/parameter_handler.h @@ -498,8 +498,9 @@ namespace Patterns * pattern given to the constructor. For each entry of the map, parameters * have to be entered in the form key: value. In other words, a * map is described in the form key1: value1, key2: value2, key3: - * value3, .... A constructor argument allows to choose a delimiter - * between pairs other than the comma. + * value3, .... Two constructor arguments allow to choose a delimiter + * between pairs other than the comma, and a delimeter between key and value + * other than column. * * With two additional parameters, the number of elements this list has to * have can be specified. If none is specified, the map may have zero or @@ -519,15 +520,16 @@ namespace Patterns * 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 as well as the separator used to delimit - * pairs of the map. + * 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 &separator = ",", + const std::string &key_value_separator = ":"); /** * Copy constructor. @@ -602,6 +604,12 @@ namespace Patterns */ const std::string separator; + + /** + * Separator between keys and values. + */ + const std::string key_value_separator; + /** * Initial part of description */ diff --git a/source/base/parameter_handler.cc b/source/base/parameter_handler.cc index e50971f748..5e9b463f47 100644 --- a/source/base/parameter_handler.cc +++ b/source/base/parameter_handler.cc @@ -96,6 +96,10 @@ namespace Patterns if (p != nullptr ) return p; + p = Map::create(description); + if (p != nullptr ) + return p; + p = MultipleSelection::create(description); if (p != nullptr ) return p; @@ -650,7 +654,7 @@ namespace Patterns std::ostringstream description; description << description_init - << " list of <" << pattern->description(style) << ">" + << " of <" << pattern->description(style) << ">" << " of length " << min_elements << "..." << max_elements << " (inclusive)"; if (separator != ",") @@ -708,7 +712,7 @@ namespace Patterns int min_elements, max_elements; std::istringstream is(description); - is.ignore(strlen(description_init) + strlen(" list of <")); + is.ignore(strlen(description_init) + strlen(" of <")); std::string str; std::getline(is, str, '>'); @@ -723,9 +727,9 @@ namespace Patterns if (!(is >> max_elements)) return std::unique_ptr(new List(*base_pattern, min_elements)); - is.ignore(strlen(" separated by <")); + is.ignore(strlen(" (inclusive) separated by <")); std::string separator; - if (!is) + if (is) std::getline(is, separator, '>'); else separator = ","; @@ -748,21 +752,26 @@ namespace Patterns const PatternBase &p_value, const unsigned int min_elements, const unsigned int max_elements, - const std::string &separator) + 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) + 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 (separator != ":", - ExcMessage ("The separator can not be a colon ':' since that " - "is the separator between the two elements of pairs")); + Assert (key_value_separator.size() > 0, + ExcMessage ("The key_value_separator must have a non-zero length.")); + Assert (separator != key_value_separator, + ExcMessage ("The separator can not be the same of the key_value_separator " + "since that is used as the separator between the two elements " + "of pairs")); } @@ -773,7 +782,8 @@ namespace Patterns value_pattern (other.value_pattern->clone()), min_elements (other.min_elements), max_elements (other.max_elements), - separator (other.separator) + separator (other.separator), + key_value_separator(other.key_value_separator) {} @@ -781,61 +791,25 @@ namespace Patterns bool Map::match (const std::string &test_string_list) const { std::string tmp = test_string_list; - std::vector split_list; - - // first split the input list at comma sites - while (tmp.length() != 0) - { - std::string map_entry; - map_entry = tmp; - - if (map_entry.find(separator) != std::string::npos) - { - map_entry.erase (map_entry.find(separator), std::string::npos); - tmp.erase (0, tmp.find(separator)+separator.size()); - } - else - tmp = ""; - - while ((map_entry.length() != 0) && - (std::isspace (map_entry[0]))) - map_entry.erase (0,1); - - while (std::isspace (map_entry[map_entry.length()-1])) - map_entry.erase (map_entry.length()-1, 1); - - split_list.push_back (map_entry); - } - + std::vector split_list = + Utilities::split_string_list(test_string_list, separator); if ((split_list.size() < min_elements) || (split_list.size() > max_elements)) return false; - // check the different possibilities - for (std::vector::const_iterator - test_string = split_list.begin(); - test_string != split_list.end(); ++test_string) + for (auto &key_value_pair : split_list) { - // separate key and value from the test_string - if (test_string->find(":") == std::string::npos) - return false; - - // we know now that there is a ':', so split the string there - // and trim spaces - std::string key = *test_string; - key.erase (key.find(":"), std::string::npos); - while ((key.length() > 0) && (std::isspace (key[key.length()-1]))) - key.erase (key.length()-1, 1); + std::vector pair = + Utilities::split_string_list(key_value_pair, key_value_separator); - std::string value = *test_string; - value.erase (0, value.find(":")+1); - while ((value.length() > 0) && (std::isspace (value[0]))) - value.erase (0, 1); + // 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 (key) == false) + if (key_pattern->match (pair[0]) == false) return false; - if (value_pattern->match (value) == false) + if (value_pattern->match (pair[1]) == false) return false; } @@ -853,8 +827,9 @@ namespace Patterns std::ostringstream description; description << description_init - << " map of <" - << key_pattern->description(style) << ":" + << " of <" + << key_pattern->description(style) << ">" + << key_value_separator << "<" << value_pattern->description(style) << ">" << " of length " << min_elements << "..." << max_elements << " (inclusive)"; @@ -869,7 +844,9 @@ namespace Patterns { std::ostringstream description; - description << "A key-value map of " + description << "A key" + << key_value_separator + << "value map of " << min_elements << " to " << max_elements << " elements "; if (separator != ",") @@ -897,7 +874,7 @@ namespace Patterns { return std::unique_ptr(new Map(*key_pattern, *value_pattern, min_elements, max_elements, - separator)); + separator, key_value_separator)); } @@ -907,7 +884,8 @@ namespace Patterns return (sizeof(*this) + MemoryConsumption::memory_consumption (*key_pattern) + MemoryConsumption::memory_consumption (*value_pattern) + - MemoryConsumption::memory_consumption (separator)); + MemoryConsumption::memory_consumption (separator)+ + MemoryConsumption::memory_consumption (key_value_separator)); } @@ -919,17 +897,17 @@ namespace Patterns int min_elements, max_elements; std::istringstream is(description); - is.ignore(strlen(description_init) + strlen(" map of <")); + is.ignore(strlen(description_init) + strlen(" of <")); - std::string str; - std::getline(is, str, '>'); + std::string key; + std::getline(is, key, '>'); - // split 'str' into key and value - std::string key = str; - key.erase (key.find(":"), std::string::npos); + std::string key_value_separator; + std::getline(is, key_value_separator, '<'); - std::string value = str; - value.erase (0, value.find(":")+1); + // split 'str' into key and value + std::string value; + std::getline(is, value, '>'); std::shared_ptr key_pattern (pattern_factory(key)); std::shared_ptr value_pattern (pattern_factory(value)); @@ -942,16 +920,16 @@ namespace Patterns if (!(is >> max_elements)) return std::unique_ptr(new Map(*key_pattern, *value_pattern, min_elements)); - is.ignore(strlen(" separated by <")); + is.ignore(strlen(" (inclusive) separated by <")); std::string separator; - if (!is) + if (is) std::getline(is, separator, '>'); else separator = ","; return std::unique_ptr(new Map(*key_pattern, *value_pattern, min_elements, max_elements, - separator)); + separator, key_value_separator)); } else return std::unique_ptr(); diff --git a/tests/base/patterns_04.cc b/tests/base/patterns_04.cc new file mode 100644 index 0000000000..8201cb28da --- /dev/null +++ b/tests/base/patterns_04.cc @@ -0,0 +1,74 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 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. +// +// --------------------------------------------------------------------- + +// pattern_factory tests + +#include "../tests.h" +#include +#include +#include + + +void +test(const Patterns::PatternBase &p) +{ + // Print description + auto desc = p.description(); + deallog << p.description() << std::endl; + + // Check that we can clone + auto p2 = p.clone(); + deallog << p2->description() << std::endl; + + auto p3 = Patterns::pattern_factory(desc); + deallog << p3->description() << std::endl; + + AssertThrow(desc == p2->description(), + ExcInternalError("Cloned pattern does not have the same " + "description of the original pattern!")); + + AssertThrow(desc == p3->description(), + ExcInternalError("Pattern created using factory " + "does not have the same " + "description of the original pattern!")); +} + + +using namespace Patterns; + +int main() +{ + initlog(); + test(Integer()); + test(Integer(-1)); + test(Integer(-1,50)); + + test(Double()); + test(Double(0.0, 50.0)); + + test(Bool()); + + test(List(Integer())); + test(List(Double())); + test(List(Bool())); + + test(Selection("alpha|beta")); + test(List(Double(),0,3,";")); + + test(Map(Integer(), Double())); + test(Map(Integer(0,10), Double(), 0, 10, ";", "=")); + + deallog << "OK" << std::endl; +} diff --git a/tests/base/patterns_04.output b/tests/base/patterns_04.output new file mode 100644 index 0000000000..9cf54f1877 --- /dev/null +++ b/tests/base/patterns_04.output @@ -0,0 +1,41 @@ + +DEAL::[Integer range -2147483648...2147483647 (inclusive)] +DEAL::[Integer range -2147483648...2147483647 (inclusive)] +DEAL::[Integer range -2147483648...2147483647 (inclusive)] +DEAL::[Integer range -1...2147483647 (inclusive)] +DEAL::[Integer range -1...2147483647 (inclusive)] +DEAL::[Integer range -1...2147483647 (inclusive)] +DEAL::[Integer range -1...50 (inclusive)] +DEAL::[Integer range -1...50 (inclusive)] +DEAL::[Integer range -1...50 (inclusive)] +DEAL::[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)] +DEAL::[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)] +DEAL::[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)] +DEAL::[Double 0...50 (inclusive)] +DEAL::[Double 0...50 (inclusive)] +DEAL::[Double 0...50 (inclusive)] +DEAL::[Bool] +DEAL::[Bool] +DEAL::[Bool] +DEAL::[List of <[Integer range -2147483648...2147483647 (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Integer range -2147483648...2147483647 (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Integer range -2147483648...2147483647 (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Bool]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Bool]> of length 0...4294967295 (inclusive)] +DEAL::[List of <[Bool]> of length 0...4294967295 (inclusive)] +DEAL::[Selection alpha|beta ] +DEAL::[Selection alpha|beta ] +DEAL::[Selection alpha|beta ] +DEAL::[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...3 (inclusive) separated by <;>] +DEAL::[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...3 (inclusive) separated by <;>] +DEAL::[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...3 (inclusive) separated by <;>] +DEAL::[Map of <[Integer range -2147483648...2147483647 (inclusive)]>:<[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[Map of <[Integer range -2147483648...2147483647 (inclusive)]>:<[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[Map of <[Integer range -2147483648...2147483647 (inclusive)]>:<[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...4294967295 (inclusive)] +DEAL::[Map of <[Integer range 0...10 (inclusive)]>=<[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...10 (inclusive) separated by <;>] +DEAL::[Map of <[Integer range 0...10 (inclusive)]>=<[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...10 (inclusive) separated by <;>] +DEAL::[Map of <[Integer range 0...10 (inclusive)]>=<[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 0...10 (inclusive) separated by <;>] +DEAL::OK -- 2.39.5