@@ -66,27 +66,13 @@ class ParsedFunction : public FunctionBase<Output>
66
66
const std::vector<Output> * initial_vals=nullptr );
67
67
68
68
/* *
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
+ * Constructors
70
+ * - This class contains unique_ptrs so it can't be default copy
71
+ * constructed or assigned, only default moved and deleted .
72
72
*/
73
- ParsedFunction & operator = (const ParsedFunction &) = delete ;
73
+ ParsedFunction (const ParsedFunction &);
74
+ ParsedFunction & operator = (const ParsedFunction &);
74
75
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 ;
90
76
ParsedFunction (ParsedFunction &&) = default ;
91
77
ParsedFunction & operator = (ParsedFunction &&) = default ;
92
78
virtual ~ParsedFunction () = default ;
@@ -183,18 +169,18 @@ class ParsedFunction : public FunctionBase<Output>
183
169
184
170
std::string _expression;
185
171
std::vector<std::string> _subexpressions;
186
- std::vector<FunctionParserADBase<Output>> parsers;
172
+ std::vector<std::unique_ptr< FunctionParserADBase<Output> >> parsers;
187
173
std::vector<Output> _spacetime;
188
174
189
175
// derivative functions
190
- std::vector<FunctionParserADBase<Output>> dx_parsers;
176
+ std::vector<std::unique_ptr< FunctionParserADBase<Output> >> dx_parsers;
191
177
#if LIBMESH_DIM > 1
192
- std::vector<FunctionParserADBase<Output>> dy_parsers;
178
+ std::vector<std::unique_ptr< FunctionParserADBase<Output> >> dy_parsers;
193
179
#endif
194
180
#if LIBMESH_DIM > 2
195
- std::vector<FunctionParserADBase<Output>> dz_parsers;
181
+ std::vector<std::unique_ptr< FunctionParserADBase<Output> >> dz_parsers;
196
182
#endif
197
- std::vector<FunctionParserADBase<Output>> dt_parsers;
183
+ std::vector<std::unique_ptr< FunctionParserADBase<Output> >> dt_parsers;
198
184
bool _valid_derivatives;
199
185
200
186
// Variables/values that can be parsed and handled by the function parser
@@ -225,6 +211,37 @@ ParsedFunction<Output,OutputGradient>::ParsedFunction (const std::string & expre
225
211
}
226
212
227
213
214
+ template <typename Output, typename OutputGradient>
215
+ inline
216
+ ParsedFunction<Output,OutputGradient>::ParsedFunction (const ParsedFunction<Output,OutputGradient> & other) :
217
+ FunctionBase<Output>(other),
218
+ _expression(other._expression),
219
+ _subexpressions(other._subexpressions),
220
+ _spacetime(other._spacetime),
221
+ _valid_derivatives(other._valid_derivatives),
222
+ variables(other.variables),
223
+ _additional_vars(other._additional_vars),
224
+ _initial_vals(other._initial_vals)
225
+ {
226
+ // parsers can be generated from scratch by reparsing expression
227
+ this ->reparse (this ->_expression );
228
+ this ->_initialized = true ;
229
+ }
230
+
231
+
232
+
233
+ template <typename Output, typename OutputGradient>
234
+ inline
235
+ ParsedFunction<Output,OutputGradient> &
236
+ ParsedFunction<Output,OutputGradient>::operator = (const ParsedFunction<Output,OutputGradient> & other)
237
+ {
238
+ // Use copy-and-swap idiom
239
+ ParsedFunction<Output,OutputGradient> tmp (other);
240
+ std::swap (tmp, *this );
241
+ return *this ;
242
+ }
243
+
244
+
228
245
template <typename Output, typename OutputGradient>
229
246
inline
230
247
void
@@ -262,7 +279,7 @@ Output
262
279
ParsedFunction<Output,OutputGradient>::operator () (const Point & p, const Real time)
263
280
{
264
281
set_spacetime (p, time );
265
- return eval (parsers[0 ], " f" , 0 );
282
+ return eval (* parsers[0 ], " f" , 0 );
266
283
}
267
284
268
285
template <typename Output, typename OutputGradient>
@@ -271,7 +288,7 @@ Output
271
288
ParsedFunction<Output,OutputGradient>::dot (const Point & p, const Real time)
272
289
{
273
290
set_spacetime (p, time );
274
- return eval (dt_parsers[0 ], " df/dt" , 0 );
291
+ return eval (* dt_parsers[0 ], " df/dt" , 0 );
275
292
}
276
293
277
294
template <typename Output, typename OutputGradient>
@@ -282,12 +299,12 @@ ParsedFunction<Output,OutputGradient>::gradient (const Point & p, const Real tim
282
299
OutputGradient grad;
283
300
set_spacetime (p, time );
284
301
285
- grad (0 ) = eval (dx_parsers[0 ], " df/dx" , 0 );
302
+ grad (0 ) = eval (* dx_parsers[0 ], " df/dx" , 0 );
286
303
#if LIBMESH_DIM > 1
287
- grad (1 ) = eval (dy_parsers[0 ], " df/dy" , 0 );
304
+ grad (1 ) = eval (* dy_parsers[0 ], " df/dy" , 0 );
288
305
#endif
289
306
#if LIBMESH_DIM > 2
290
- grad (2 ) = eval (dz_parsers[0 ], " df/dz" , 0 );
307
+ grad (2 ) = eval (* dz_parsers[0 ], " df/dz" , 0 );
291
308
#endif
292
309
293
310
return grad;
@@ -310,7 +327,7 @@ ParsedFunction<Output,OutputGradient>::operator()
310
327
// The remaining locations in _spacetime are currently fixed at construction
311
328
// but could potentially be made dynamic
312
329
for (unsigned int i=0 ; i != size; ++i)
313
- output (i) = eval (parsers[i], " f" , i);
330
+ output (i) = eval (* parsers[i], " f" , i);
314
331
}
315
332
316
333
/* *
@@ -330,7 +347,7 @@ ParsedFunction<Output,OutputGradient>::component (unsigned int i,
330
347
// The remaining locations in _spacetime are currently fixed at construction
331
348
// but could potentially be made dynamic
332
349
libmesh_assert_less (i, parsers.size ());
333
- return eval (parsers[i], " f" , i);
350
+ return eval (* parsers[i], " f" , i);
334
351
}
335
352
336
353
/* *
@@ -541,51 +558,53 @@ ParsedFunction<Output,OutputGradient>::partial_reparse (const std::string & expr
541
558
542
559
// Parse (and optimize if possible) the subexpression.
543
560
// 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 )));
561
+ auto fp = libmesh_make_unique< FunctionParserADBase<Output>>() ;
562
+ fp-> AddConstant (" NaN" , std::numeric_limits<Real>::quiet_NaN ());
563
+ fp-> AddConstant (" pi" , std::acos (Real (-1 )));
564
+ fp-> AddConstant (" e" , std::exp (Real (1 )));
548
565
libmesh_error_msg_if
549
- (fp. Parse (_subexpressions.back (), variables) != -1 , // -1 for success
566
+ (fp-> Parse (_subexpressions.back (), variables) != -1 , // -1 for success
550
567
" ERROR: FunctionParser is unable to parse expression: "
551
- << _subexpressions.back () << ' \n ' << fp. ErrorMsg ());
568
+ << _subexpressions.back () << ' \n ' << fp-> ErrorMsg ());
552
569
553
570
// use of derivatives is optional. suppress error output on the console
554
571
// use the has_derivatives() method to check if AutoDiff was successful.
555
572
// also enable immediate optimization
556
- fp. SetADFlags (FunctionParserADBase<Output>::ADSilenceErrors |
573
+ fp-> SetADFlags (FunctionParserADBase<Output>::ADSilenceErrors |
557
574
FunctionParserADBase<Output>::ADAutoOptimize);
558
575
559
576
// optimize original function
560
- fp.Optimize ();
561
- parsers.push_back (fp);
577
+ fp->Optimize ();
562
578
563
579
// generate derivatives through automatic differentiation
564
- FunctionParserADBase<Output> dx_fp ( fp);
565
- if (dx_fp. AutoDiff (" x" ) != -1 ) // -1 for success
580
+ auto dx_fp = libmesh_make_unique< FunctionParserADBase<Output>>(* fp);
581
+ if (dx_fp-> AutoDiff (" x" ) != -1 ) // -1 for success
566
582
_valid_derivatives = false ;
567
- dx_parsers.push_back (dx_fp);
583
+ dx_parsers.push_back (std::move ( dx_fp) );
568
584
#if LIBMESH_DIM > 1
569
- FunctionParserADBase<Output> dy_fp ( fp);
570
- if (dy_fp. AutoDiff (" y" ) != -1 ) // -1 for success
585
+ auto dy_fp = libmesh_make_unique< FunctionParserADBase<Output>>(* fp);
586
+ if (dy_fp-> AutoDiff (" y" ) != -1 ) // -1 for success
571
587
_valid_derivatives = false ;
572
- dy_parsers.push_back (dy_fp);
588
+ dy_parsers.push_back (std::move ( dy_fp) );
573
589
#endif
574
590
#if LIBMESH_DIM > 2
575
- FunctionParserADBase<Output> dz_fp ( fp);
576
- if (dz_fp. AutoDiff (" z" ) != -1 ) // -1 for success
591
+ auto dz_fp = libmesh_make_unique< FunctionParserADBase<Output>>(* fp);
592
+ if (dz_fp-> AutoDiff (" z" ) != -1 ) // -1 for success
577
593
_valid_derivatives = false ;
578
- dz_parsers.push_back (dz_fp);
594
+ dz_parsers.push_back (std::move ( dz_fp) );
579
595
#endif
580
- FunctionParserADBase<Output> dt_fp ( fp);
581
- if (dt_fp. AutoDiff (" t" ) != -1 ) // -1 for success
596
+ auto dt_fp = libmesh_make_unique< FunctionParserADBase<Output>>(* fp);
597
+ if (dt_fp-> AutoDiff (" t" ) != -1 ) // -1 for success
582
598
_valid_derivatives = false ;
583
- dt_parsers.push_back (dt_fp);
599
+ dt_parsers.push_back (std::move ( dt_fp) );
584
600
585
601
// If at end, use nextstart=maxSize. Else start at next
586
602
// character.
587
603
nextstart = (end == std::string::npos) ?
588
604
std::string::npos : end + 1 ;
605
+
606
+ // Store fp for later use
607
+ parsers.push_back (std::move (fp));
589
608
}
590
609
}
591
610
0 commit comments