]> https://gitweb.dealii.org/ - dealii.git/commitdiff
Provide some guarantees with regard to exceptions.
authorWolfgang Bangerth <bangerth@colostate.edu>
Fri, 21 Apr 2017 23:30:27 +0000 (17:30 -0600)
committerWolfgang Bangerth <bangerth@colostate.edu>
Mon, 24 Apr 2017 19:25:29 +0000 (13:25 -0600)
include/deal.II/base/parameter_handler.h
source/base/parameter_handler.cc

index f2d2241901bf3409ebfde9b9d2d9a5243072a53a..739386d8f01406f910b4c6e2e1399832e4735bc8 100644 (file)
@@ -1744,6 +1744,23 @@ public:
    * If non-empty @p last_line is provided, the ParameterHandler object
    * will stop parsing lines after encountering @p last_line .
    * This is handy when adding extra data that shall be parsed manually.
+   *
+   * The function sets the value of all parameters it encounters in the
+   * input file to the provided value. Parameters not explicitly listed
+   * in the input file are left at the value they previously held, which
+   * will be the default value provided to declare_entry() unless one
+   * has previously read a different input file.
+   *
+   * Each parameter value is matched against the pattern for this
+   * parameter that was provided to declare_entry(), and for each parameter
+   * all associated actions that may previously have been set by
+   * add_action() are executed. If a parameter does not satisfy its
+   * pattern, or if an associated action throws an exception, then the
+   * value provided for the parameter is not set and the current
+   * object reverts to the subsection it was in before the current
+   * function was called. No further processing of the input stream
+   * occurs, that is everything that comes after the parameter whose
+   * value does not satisfy its pattern is ignored.
    */
   virtual void parse_input (std::istream &input,
                             const std::string &filename = "input file",
@@ -1753,9 +1770,9 @@ public:
    * Parse the given file to provide values for known parameter fields. The
    * PathSearch class "PARAMETERS" is used to find the file.
    *
-   * If non-empty @p last_line is provided, the ParameterHandler object
-   * will stop parsing lines after encountering @p last_line .
-   * This is handy when adding extra data that shall be parsed manually.
+   * The function in essence reads the entire file into a stream and
+   * then calls the other parse_input() function with that stream. See
+   * there for more information.
    */
   virtual void parse_input (const std::string &filename,
                             const std::string &last_line = "");
@@ -1764,9 +1781,9 @@ public:
    * Parse input from a string to populate known parameter fields. The lines
    * in the string must be separated by <tt>@\n</tt> characters.
    *
-   * If non-empty @p last_line is provided, the ParameterHandler object
-   * will stop parsing lines after encountering @p last_line .
-   * This is handy when adding extra data that shall be parsed manually.
+   * The function in essence reads the entire file into a stream and
+   * then calls the other parse_input() function with that stream. See
+   * there for more information.
    */
   virtual void parse_input_from_string (const char *s,
                                         const std::string &last_line = "");
@@ -1843,6 +1860,14 @@ public:
    *  there is no guarantee about the order in which they will be read
    *  from an input file, you will not want to rely on the values these
    *  functions would return.
+   *
+   * @note Throwing an exception in an action is generally not a good
+   *  idea, but yields fundamentally the same result as if one tries to
+   *  read a parameter from a file for which the value does not satisfy
+   *  the pattern associated with the parameter. In other words, the
+   *  value just read is discarded, and ParameterHandler::parse_input()
+   *  stops to read any further content from the file. See
+   *  ParameterHandler::parse_input() for more information.
    */
   void add_action (const std::string &entry,
                    const std::function<void (const std::string &value)> &action);
index c072193074f219af9a20486fb18ce3d7005025f5..9573cbee36c9283e7c960db706cbbf3ffa7054aa 100644 (file)
@@ -1620,7 +1620,7 @@ void ParameterHandler::parse_input (std::istream &input,
   AssertThrow (input, ExcIO());
 
   // store subsections we are currently in
-  std::vector<std::string> saved_path = subsection_path;
+  const std::vector<std::string> saved_path = subsection_path;
 
   std::string input_line;
   std::string fully_concatenated_line;
@@ -1631,6 +1631,39 @@ void ParameterHandler::parse_input (std::istream &input,
   unsigned int current_line_n = 0;
   unsigned int current_logical_line_n = 0;
 
+  // define an action that tries to scan a line.
+  //
+  // if that fails, i.e., if scan_line throws
+  // an exception either because a parameter doesn't match its
+  // pattern or because an associated action throws an exception,
+  // then try to rewind the set of subsections to the same
+  // point where we were when the current function was called.
+  // this at least allows to read parameters from a predictable
+  // state, rather than leave the subsection stack in some
+  // unknown state.
+  //
+  // after unwinding the subsection stack, just re-throw the exception
+  auto scan_line_or_cleanup =
+    [this, &saved_path](const std::string &line,
+                        const std::string &filename,
+                        const unsigned int line_number)
+  {
+    try
+      {
+        scan_line (line, filename, line_number);
+      }
+    catch (...)
+      {
+        while ((saved_path != subsection_path)
+               &&
+               (subsection_path.size() > 0))
+          leave_subsection ();
+
+        throw;
+      }
+  };
+
+
   while (std::getline (input, input_line))
     {
       ++current_line_n;
@@ -1672,17 +1705,21 @@ void ParameterHandler::parse_input (std::istream &input,
 
       if (!is_concatenated)
         {
-          scan_line (fully_concatenated_line, filename, current_logical_line_n);
+          scan_line_or_cleanup (fully_concatenated_line,
+                                filename,
+                                current_logical_line_n);
+
           fully_concatenated_line.clear();
         }
     }
 
   // While it does not make much sense for anyone to actually do this, allow
-  // the last line to end in a backslash.
+  // the last line to end in a backslash. to do do, we need to parse
+  // whatever was left in the stash of concatenated lines
   if (is_concatenated)
-    {
-      scan_line (fully_concatenated_line, filename, current_line_n);
-    }
+    scan_line_or_cleanup (fully_concatenated_line,
+                          filename,
+                          current_line_n);
 
   if (saved_path != subsection_path)
     {

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.