Skip to content

Commit 783091b

Browse files
committed
ParsedFEMFunction: change "parsers" to a vector of unique_ptrs
This is an attempt to fix the issue raised in libMesh#2710. Since FunctionParserBase has a deleted move constructor, it is not considered to be MoveInsertable, which means it cannot be passed to std::vector::push_back() by value. Adding a vector<unique_ptr> to the class means that it can no longer be default copy constructed. We had a unit test of this but, no actual uses within the library so hopefully it's OK to drop it.
1 parent 7d38136 commit 783091b

File tree

2 files changed

+25
-39
lines changed

2 files changed

+25
-39
lines changed

include/numerics/parsed_fem_function.h

+25-32
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
#include <sstream>
4141
#include <string>
4242
#include <vector>
43+
#include <memory>
4344

4445
namespace libMesh
4546
{
@@ -68,21 +69,13 @@ class ParsedFEMFunction : public FEMFunctionBase<Output>
6869
const std::vector<Output> * initial_vals=nullptr);
6970

7071
/**
71-
* This class contains a const reference so it can't be copy or move-assigned.
72+
* Special functions
73+
* - This class contains a const reference so it can't be copy or move-assigned.
74+
* - This class contains unique_ptrs so it can't be default copy constructed.
7275
*/
7376
ParsedFEMFunction & operator= (const ParsedFEMFunction &) = delete;
7477
ParsedFEMFunction & operator= (ParsedFEMFunction &&) = delete;
75-
76-
/**
77-
* The remaining 5 special functions can be safely defaulted.
78-
*
79-
* \note The underlying FunctionParserBase class has a copy
80-
* constructor, so this class should be default-constructible. And,
81-
* although FunctionParserBase's move constructor is deleted, _this_
82-
* class should still be move-constructible because
83-
* FunctionParserBase only appears in a vector.
84-
*/
85-
ParsedFEMFunction (const ParsedFEMFunction &) = default;
78+
ParsedFEMFunction (const ParsedFEMFunction &) = delete;
8679
ParsedFEMFunction (ParsedFEMFunction &&) = default;
8780
virtual ~ParsedFEMFunction () = default;
8881

@@ -168,9 +161,9 @@ class ParsedFEMFunction : public FEMFunctionBase<Output>
168161
_n_requested_hess_components;
169162
bool _requested_normals;
170163
#ifdef LIBMESH_HAVE_FPARSER
171-
std::vector<FunctionParserBase<Output>> parsers;
164+
std::vector<std::unique_ptr<FunctionParserBase<Output>>> parsers;
172165
#else
173-
std::vector<char> parsers;
166+
std::vector<char*> parsers;
174167
#endif
175168
std::vector<Output> _spacetime;
176169

@@ -401,7 +394,7 @@ ParsedFEMFunction<Output>::operator() (const FEMContext & c,
401394
{
402395
eval_args(c, p, time);
403396

404-
return eval(parsers[0], "f", 0);
397+
return eval(*parsers[0], "f", 0);
405398
}
406399

407400

@@ -421,7 +414,7 @@ ParsedFEMFunction<Output>::operator() (const FEMContext & c,
421414
libmesh_assert_equal_to (size, parsers.size());
422415

423416
for (unsigned int i=0; i != size; ++i)
424-
output(i) = eval(parsers[i], "f", i);
417+
output(i) = eval(*parsers[i], "f", i);
425418
}
426419

427420

@@ -436,7 +429,7 @@ ParsedFEMFunction<Output>::component (const FEMContext & c,
436429
eval_args(c, p, time);
437430

438431
libmesh_assert_less (i, parsers.size());
439-
return eval(parsers[i], "f", i);
432+
return eval(*parsers[i], "f", i);
440433
}
441434

442435
template <typename Output>
@@ -479,16 +472,16 @@ ParsedFEMFunction<Output>::get_inline_value(const std::string & inline_var_name)
479472
#ifdef LIBMESH_HAVE_FPARSER
480473
// Parse and evaluate the new subexpression.
481474
// Add the same constants as we used originally.
482-
FunctionParserBase<Output> fp;
483-
fp.AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
484-
fp.AddConstant("pi", std::acos(Real(-1)));
485-
fp.AddConstant("e", std::exp(Real(1)));
475+
auto fp = libmesh_make_unique<FunctionParserBase<Output>>();
476+
fp->AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
477+
fp->AddConstant("pi", std::acos(Real(-1)));
478+
fp->AddConstant("e", std::exp(Real(1)));
486479
libmesh_error_msg_if
487-
(fp.Parse(new_subexpression, variables) != -1, // -1 for success
480+
(fp->Parse(new_subexpression, variables) != -1, // -1 for success
488481
"ERROR: FunctionParser is unable to parse modified expression: "
489-
<< new_subexpression << '\n' << fp.ErrorMsg());
482+
<< new_subexpression << '\n' << fp->ErrorMsg());
490483

491-
Output new_var_value = this->eval(fp, new_subexpression, 0);
484+
Output new_var_value = this->eval(*fp, new_subexpression, 0);
492485
#ifdef NDEBUG
493486
return new_var_value;
494487
#else
@@ -621,16 +614,16 @@ ParsedFEMFunction<Output>::partial_reparse (const std::string & expression)
621614
#ifdef LIBMESH_HAVE_FPARSER
622615
// Parse (and optimize if possible) the subexpression.
623616
// Add some basic constants, to Real precision.
624-
FunctionParserBase<Output> fp;
625-
fp.AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
626-
fp.AddConstant("pi", std::acos(Real(-1)));
627-
fp.AddConstant("e", std::exp(Real(1)));
617+
auto fp = libmesh_make_unique<FunctionParserBase<Output>>();
618+
fp->AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
619+
fp->AddConstant("pi", std::acos(Real(-1)));
620+
fp->AddConstant("e", std::exp(Real(1)));
628621
libmesh_error_msg_if
629-
(fp.Parse(_subexpressions.back(), variables) != -1, // -1 for success
622+
(fp->Parse(_subexpressions.back(), variables) != -1, // -1 for success
630623
"ERROR: FunctionParser is unable to parse expression: "
631-
<< _subexpressions.back() << '\n' << fp.ErrorMsg());
632-
fp.Optimize();
633-
parsers.push_back(fp);
624+
<< _subexpressions.back() << '\n' << fp->ErrorMsg());
625+
fp->Optimize();
626+
parsers.push_back(std::move(fp));
634627
#else
635628
libmesh_error_msg("ERROR: This functionality requires fparser!");
636629
#endif

tests/numerics/parsed_fem_function_test.C

-7
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,6 @@ private:
142142
c->get_elem().processor_id() == TestCommWorld->rank())
143143
{
144144
ParsedFEMFunction<Number> x2(*sys, "x2");
145-
146-
// Test that copy constructor works
147-
ParsedFEMFunction<Number> x2_copy(x2);
148-
149-
LIBMESH_ASSERT_FP_EQUAL
150-
(1.0, libmesh_real(x2_copy(*c,Point(0.5,0.5,0.5))), TOLERANCE*TOLERANCE);
151-
152145
ParsedFEMFunction<Number> xy8(*sys, "x2*y4");
153146

154147
// Test that move constructor works

0 commit comments

Comments
 (0)