From 3f1c3901fb9f7b865c60c3e77f2e2c8e3ba07a56 Mon Sep 17 00:00:00 2001 From: Daniel Arndt Date: Tue, 16 May 2023 13:57:16 -0400 Subject: [PATCH] Patterns: Fix parsing lists of lists --- doc/news/changes/minor/20230516DanielArndt | 3 ++ source/base/patterns.cc | 27 +++++++--- tests/parameter_handler/patterns_18.cc | 61 ++++++++++++++++++++++ tests/parameter_handler/patterns_18.output | 9 ++++ 4 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 doc/news/changes/minor/20230516DanielArndt create mode 100644 tests/parameter_handler/patterns_18.cc create mode 100644 tests/parameter_handler/patterns_18.output diff --git a/doc/news/changes/minor/20230516DanielArndt b/doc/news/changes/minor/20230516DanielArndt new file mode 100644 index 0000000000..6ab8ac7a55 --- /dev/null +++ b/doc/news/changes/minor/20230516DanielArndt @@ -0,0 +1,3 @@ +Fixed: Patterns::pattern_factory now parses lists of lists correctly. +
+(Daniel Arndt, 2023/05/16) diff --git a/source/base/patterns.cc b/source/base/patterns.cc index 69322932e4..e76155a937 100644 --- a/source/base/patterns.cc +++ b/source/base/patterns.cc @@ -780,15 +780,30 @@ namespace Patterns { unsigned int min_elements = 0, max_elements = 0; - std::istringstream is(description); - is.ignore(strlen(description_init) + strlen(" of <")); + std::string::const_iterator it = + description.begin() + strlen(description_init) + strlen(" of <"); - std::string str; - std::getline(is, str, '>'); + int n_open_angular = 1; + auto tmp_it = it - 1; + while (n_open_angular > 0) + { + tmp_it = std::find_if(tmp_it + 1, description.end(), [](char c) { + return (c == '>' || c == '<'); + }); + Assert(tmp_it != description.end(), + ExcMessage("Couldn't find a closing '>' in description!")); + if (*tmp_it == '<') + ++n_open_angular; + else + --n_open_angular; + } - std::unique_ptr base_pattern(pattern_factory(str)); + std::string base_pattern_string(it, tmp_it); + std::unique_ptr base_pattern( + pattern_factory(base_pattern_string)); - is.ignore(strlen(" of length ")); + std::istringstream is( + std::string(tmp_it + strlen(" of length "), description.end())); if (!(is >> min_elements)) return std::make_unique(*base_pattern); diff --git a/tests/parameter_handler/patterns_18.cc b/tests/parameter_handler/patterns_18.cc new file mode 100644 index 0000000000..74327473c3 --- /dev/null +++ b/tests/parameter_handler/patterns_18.cc @@ -0,0 +1,61 @@ +// --------------------------------------------------------------------- +// +// Copyright (C) 2005 - 2021 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.md at +// the top level directory of deal.II. +// +// --------------------------------------------------------------------- + +// test that lists of lists are parsed correctly +#include + +#include "../tests.h" + +int +main() +{ + initlog(); + + // Example parameter pattern for a list of lists + const std::string description = + "[List of <[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 3...3 (inclusive) separated by < >]> of length 0...4294967295 (inclusive)]"; + // The above pattern describes a list of lists of 3 doubles, e.g.: + // "1 2 3,1.2 3.2 1.2" is valid + // "1.2,1.3,1.4,1.6 1.2,1.3,1.0,1.5,6.5,5.1 7.6,13.5,1.5" is not valid + + // Parse the description in deal.ii + std::unique_ptr pattern = + dealii::Patterns::pattern_factory(description); + + // Write the original and parsed description + deallog << "Original description: " << std::endl + << description << std::endl + << std::endl + << "Parsed description: " << std::endl + << pattern->description(dealii::Patterns::PatternBase::Machine) + << std::endl; + + // First check, should be a match + deallog << "First check: \"\" is " + << (pattern->match("") ? "a match" : "not a match") << std::endl; + + // Second check, should be a match + deallog << "Second check: \"1 2 3,1.2 3.2 1.2\" is " + << (pattern->match("1 2 3,1.2 3.2 1.2") ? "a match" : "not a match") + << std::endl; + + // Third check, should not be a match + deallog + << "Third check: \"1.2,1.3,1.4,1.6 1.2,1.3,1.0,1.5,6.5,5.1 7.6,13.5,1.5\" is " + << (pattern->match("1.2,1.3,1.4,1.6 1.2,1.3,1.0,1.5,6.5,5.1 7.6,13.5,1.5") ? + "a match" : + "not a match") + << std::endl; +} diff --git a/tests/parameter_handler/patterns_18.output b/tests/parameter_handler/patterns_18.output new file mode 100644 index 0000000000..55c7ba1ddd --- /dev/null +++ b/tests/parameter_handler/patterns_18.output @@ -0,0 +1,9 @@ + +DEAL::Original description: +DEAL::[List of <[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 3...3 (inclusive) separated by < >]> of length 0...4294967295 (inclusive)] +DEAL:: +DEAL::Parsed description: +DEAL::[List of <[List of <[Double -MAX_DOUBLE...MAX_DOUBLE (inclusive)]> of length 3...3 (inclusive) separated by < >]> of length 0...4294967295 (inclusive)] +DEAL::First check: "" is a match +DEAL::Second check: "1 2 3,1.2 3.2 1.2" is a match +DEAL::Third check: "1.2,1.3,1.4,1.6 1.2,1.3,1.0,1.5,6.5,5.1 7.6,13.5,1.5" is not a match -- 2.39.5