Skip to content

Commit b67b3e4

Browse files
committed
ParsedFunction: change to vectors of unique_ptrs
This is similar to the change made in 783091b for ParsedFEMFunction. For a class to be pushed-back onto a vector, it must be MoveInsertable, which FunctionParserADBase is not. Refs #2710
1 parent 558f2ab commit b67b3e4

File tree

2 files changed

+39
-61
lines changed

2 files changed

+39
-61
lines changed

include/numerics/parsed_function.h

+39-53
Original file line numberDiff line numberDiff line change
@@ -66,28 +66,12 @@ class ParsedFunction : public FunctionBase<Output>
6666
const std::vector<Output> * initial_vals=nullptr);
6767

6868
/**
69-
* This class cannot be (default) copy assigned because the
70-
* underlying FunctionParserADBase class does not define a custom
71-
* copy assignment operator, and manually manages memory.
69+
* Special functions
70+
* - This class contains unique_ptrs so it can't be default copy constructed or assigned.
7271
*/
73-
ParsedFunction & operator= (const ParsedFunction &) = delete;
74-
75-
/**
76-
* The remaining special functions can be defaulted for this class.
77-
*
78-
* \note Despite the fact that the underlying FunctionParserADBase
79-
* class is not move-assignable or move-constructible, it is still
80-
* possible for _this_ class to be move-assigned and
81-
* move-constructed, because FunctionParserADBase objects only
82-
* appear within std::vectors in this class, and std::vectors can
83-
* generally still be move-assigned and move-constructed even when
84-
* their contents cannot. There are some allocator-specific
85-
* exceptions to this, but it should be guaranteed to work for
86-
* std::allocator in C++14 and beyond. See also:
87-
* https://stackoverflow.com/q/42051917/659433
88-
*/
89-
ParsedFunction (const ParsedFunction &) = default;
72+
ParsedFunction (const ParsedFunction &) = delete;
9073
ParsedFunction (ParsedFunction &&) = default;
74+
ParsedFunction & operator= (const ParsedFunction &) = delete;
9175
ParsedFunction & operator= (ParsedFunction &&) = default;
9276
virtual ~ParsedFunction () = default;
9377

@@ -183,18 +167,18 @@ class ParsedFunction : public FunctionBase<Output>
183167

184168
std::string _expression;
185169
std::vector<std::string> _subexpressions;
186-
std::vector<FunctionParserADBase<Output>> parsers;
170+
std::vector<std::unique_ptr<FunctionParserADBase<Output>>> parsers;
187171
std::vector<Output> _spacetime;
188172

189173
// derivative functions
190-
std::vector<FunctionParserADBase<Output>> dx_parsers;
174+
std::vector<std::unique_ptr<FunctionParserADBase<Output>>> dx_parsers;
191175
#if LIBMESH_DIM > 1
192-
std::vector<FunctionParserADBase<Output>> dy_parsers;
176+
std::vector<std::unique_ptr<FunctionParserADBase<Output>>> dy_parsers;
193177
#endif
194178
#if LIBMESH_DIM > 2
195-
std::vector<FunctionParserADBase<Output>> dz_parsers;
179+
std::vector<std::unique_ptr<FunctionParserADBase<Output>>> dz_parsers;
196180
#endif
197-
std::vector<FunctionParserADBase<Output>> dt_parsers;
181+
std::vector<std::unique_ptr<FunctionParserADBase<Output>>> dt_parsers;
198182
bool _valid_derivatives;
199183

200184
// Variables/values that can be parsed and handled by the function parser
@@ -262,7 +246,7 @@ Output
262246
ParsedFunction<Output,OutputGradient>::operator() (const Point & p, const Real time)
263247
{
264248
set_spacetime(p, time);
265-
return eval(parsers[0], "f", 0);
249+
return eval(*parsers[0], "f", 0);
266250
}
267251

268252
template <typename Output, typename OutputGradient>
@@ -271,7 +255,7 @@ Output
271255
ParsedFunction<Output,OutputGradient>::dot (const Point & p, const Real time)
272256
{
273257
set_spacetime(p, time);
274-
return eval(dt_parsers[0], "df/dt", 0);
258+
return eval(*dt_parsers[0], "df/dt", 0);
275259
}
276260

277261
template <typename Output, typename OutputGradient>
@@ -282,12 +266,12 @@ ParsedFunction<Output,OutputGradient>::gradient (const Point & p, const Real tim
282266
OutputGradient grad;
283267
set_spacetime(p, time);
284268

285-
grad(0) = eval(dx_parsers[0], "df/dx", 0);
269+
grad(0) = eval(*dx_parsers[0], "df/dx", 0);
286270
#if LIBMESH_DIM > 1
287-
grad(1) = eval(dy_parsers[0], "df/dy", 0);
271+
grad(1) = eval(*dy_parsers[0], "df/dy", 0);
288272
#endif
289273
#if LIBMESH_DIM > 2
290-
grad(2) = eval(dz_parsers[0], "df/dz", 0);
274+
grad(2) = eval(*dz_parsers[0], "df/dz", 0);
291275
#endif
292276

293277
return grad;
@@ -310,7 +294,7 @@ ParsedFunction<Output,OutputGradient>::operator()
310294
// The remaining locations in _spacetime are currently fixed at construction
311295
// but could potentially be made dynamic
312296
for (unsigned int i=0; i != size; ++i)
313-
output(i) = eval(parsers[i], "f", i);
297+
output(i) = eval(*parsers[i], "f", i);
314298
}
315299

316300
/**
@@ -330,7 +314,7 @@ ParsedFunction<Output,OutputGradient>::component (unsigned int i,
330314
// The remaining locations in _spacetime are currently fixed at construction
331315
// but could potentially be made dynamic
332316
libmesh_assert_less(i, parsers.size());
333-
return eval(parsers[i], "f", i);
317+
return eval(*parsers[i], "f", i);
334318
}
335319

336320
/**
@@ -541,51 +525,53 @@ ParsedFunction<Output,OutputGradient>::partial_reparse (const std::string & expr
541525

542526
// Parse (and optimize if possible) the subexpression.
543527
// Add some basic constants, to Real precision.
544-
FunctionParserADBase<Output> fp;
545-
fp.AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
546-
fp.AddConstant("pi", std::acos(Real(-1)));
547-
fp.AddConstant("e", std::exp(Real(1)));
528+
auto fp = libmesh_make_unique<FunctionParserADBase<Output>>();
529+
fp->AddConstant("NaN", std::numeric_limits<Real>::quiet_NaN());
530+
fp->AddConstant("pi", std::acos(Real(-1)));
531+
fp->AddConstant("e", std::exp(Real(1)));
548532
libmesh_error_msg_if
549-
(fp.Parse(_subexpressions.back(), variables) != -1, // -1 for success
533+
(fp->Parse(_subexpressions.back(), variables) != -1, // -1 for success
550534
"ERROR: FunctionParser is unable to parse expression: "
551-
<< _subexpressions.back() << '\n' << fp.ErrorMsg());
535+
<< _subexpressions.back() << '\n' << fp->ErrorMsg());
552536

553537
// use of derivatives is optional. suppress error output on the console
554538
// use the has_derivatives() method to check if AutoDiff was successful.
555539
// also enable immediate optimization
556-
fp.SetADFlags(FunctionParserADBase<Output>::ADSilenceErrors |
540+
fp->SetADFlags(FunctionParserADBase<Output>::ADSilenceErrors |
557541
FunctionParserADBase<Output>::ADAutoOptimize);
558542

559543
// optimize original function
560-
fp.Optimize();
561-
parsers.push_back(fp);
544+
fp->Optimize();
562545

563546
// generate derivatives through automatic differentiation
564-
FunctionParserADBase<Output> dx_fp(fp);
565-
if (dx_fp.AutoDiff("x") != -1) // -1 for success
547+
auto dx_fp = libmesh_make_unique<FunctionParserADBase<Output>>(*fp);
548+
if (dx_fp->AutoDiff("x") != -1) // -1 for success
566549
_valid_derivatives = false;
567-
dx_parsers.push_back(dx_fp);
550+
dx_parsers.push_back(std::move(dx_fp));
568551
#if LIBMESH_DIM > 1
569-
FunctionParserADBase<Output> dy_fp(fp);
570-
if (dy_fp.AutoDiff("y") != -1) // -1 for success
552+
auto dy_fp = libmesh_make_unique<FunctionParserADBase<Output>>(*fp);
553+
if (dy_fp->AutoDiff("y") != -1) // -1 for success
571554
_valid_derivatives = false;
572-
dy_parsers.push_back(dy_fp);
555+
dy_parsers.push_back(std::move(dy_fp));
573556
#endif
574557
#if LIBMESH_DIM > 2
575-
FunctionParserADBase<Output> dz_fp(fp);
576-
if (dz_fp.AutoDiff("z") != -1) // -1 for success
558+
auto dz_fp = libmesh_make_unique<FunctionParserADBase<Output>>(*fp);
559+
if (dz_fp->AutoDiff("z") != -1) // -1 for success
577560
_valid_derivatives = false;
578-
dz_parsers.push_back(dz_fp);
561+
dz_parsers.push_back(std::move(dz_fp));
579562
#endif
580-
FunctionParserADBase<Output> dt_fp(fp);
581-
if (dt_fp.AutoDiff("t") != -1) // -1 for success
563+
auto dt_fp = libmesh_make_unique<FunctionParserADBase<Output>>(*fp);
564+
if (dt_fp->AutoDiff("t") != -1) // -1 for success
582565
_valid_derivatives = false;
583-
dt_parsers.push_back(dt_fp);
566+
dt_parsers.push_back(std::move(dt_fp));
584567

585568
// If at end, use nextstart=maxSize. Else start at next
586569
// character.
587570
nextstart = (end == std::string::npos) ?
588571
std::string::npos : end + 1;
572+
573+
// Store fp for later use
574+
parsers.push_back(std::move(fp));
589575
}
590576
}
591577

tests/numerics/parsed_function_test.C

-8
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,6 @@ private:
3939

4040
void testValues()
4141
{
42-
ParsedFunction<Number> x2("x*2");
43-
44-
// Test that the copy constructor works
45-
ParsedFunction<Number> x2_copy(x2);
46-
47-
LIBMESH_ASSERT_FP_EQUAL
48-
(1.0, libmesh_real(x2_copy(Point(0.5,1.5,2.5))), TOLERANCE*TOLERANCE);
49-
5042
ParsedFunction<Number> xy8("x*y*8");
5143

5244
// Test that the move ctor works

0 commit comments

Comments
 (0)