--- /dev/null
+Fixed: deal.II, compiled with the bundled copy of muParser, can now be
+safely linked alongside other projects which use a separate copy of muParser.
+<br>
+(David Wells, 2022/03/25)
#include <memory>
#include <vector>
-namespace mu
-{
- class Parser;
-}
-
DEAL_II_NAMESPACE_OPEN
// Forward declaration
class Vector;
#endif
+namespace internal
+{
+ /**
+ * deal.II uses muParser as a purely internal dependency. To this end, we do
+ * not include any muParser headers in this file (and the bundled version of
+ * the dependency does not install its headers or compile a separate muparser
+ * library). Hence, to interface with muParser, we use the PIMPL idiom here to
+ * wrap a pointer to mu::Parser objects.
+ */
+ class muParserBase
+ {
+ public:
+ virtual ~muParserBase() = default;
+ };
+} // namespace internal
+
/**
* This class implements a function object that gets its value by parsing a
* string describing this function. It is a wrapper class for the muparser
*/
FunctionParser(FunctionParser &&) = delete;
- /**
- * Destructor.
- */
- virtual ~FunctionParser() override;
-
/**
* Copy operator. Objects of this type can not be copied, and
* consequently this operator is deleted.
mutable Threads::ThreadLocalStorage<std::vector<double>> vars;
/**
- * The muParser objects for each thread (and one for each component). We are
- * storing a unique_ptr so that we don't need to include the definition of
- * mu::Parser in this header.
+ * The muParser objects (hidden with the PIMPL idiom) for each thread (and one
+ * for each component).
*/
- mutable Threads::ThreadLocalStorage<std::vector<std::unique_ptr<mu::Parser>>>
+ mutable Threads::ThreadLocalStorage<
+ std::vector<std::unique_ptr<internal::muParserBase>>>
fp;
/**
#include <deal.II/base/config.h>
#include <deal.II/base/exceptions.h>
+#include <deal.II/base/function_parser.h>
#include <deal.II/base/point.h>
#include <deal.II/base/tensor.h>
#include <deal.II/base/tensor_function.h>
#include <memory>
#include <vector>
-namespace mu
-{
- class Parser;
-}
-
DEAL_II_NAMESPACE_OPEN
// Forward declaration
*/
TensorFunctionParser(TensorFunctionParser &&) = delete;
- /**
- * Destructor.
- */
- virtual ~TensorFunctionParser() override;
-
/**
* Copy operator. Objects of this type can not be copied, and
* consequently this operator is deleted.
mutable Threads::ThreadLocalStorage<std::vector<double>> vars;
/**
- * The muParser objects for each thread (and one for each component). We are
- * storing a unique_ptr so that we don't need to include the definition of
- * mu::Parser in this header.
+ * The muParser objects (hidden with the PIMPL idiom) for each thread (and one
+ * for each component).
*/
- mutable Threads::ThreadLocalStorage<std::vector<std::unique_ptr<mu::Parser>>>
+ mutable Threads::ThreadLocalStorage<
+ std::vector<std::unique_ptr<internal::muParserBase>>>
tfp;
/**
}
-
-// Note: we explicitly define the destructor here (instead of silently using
-// the default destructor by declaring nothing in the header) since we do not
-// expect muParser.h to be available in user projects: i.e., the destructor
-// must be defined in the source file.
-template <int dim>
-FunctionParser<dim>::~FunctionParser() = default;
-
-
#ifdef DEAL_II_WITH_MUPARSER
template <int dim>
initialized = true;
}
+namespace internal
+{
+ namespace FunctionParserImplementation
+ {
+ namespace
+ {
+ /**
+ * PIMPL for mu::Parser.
+ */
+ class Parser : public internal::muParserBase
+ {
+ public:
+ operator mu::Parser &()
+ {
+ return parser;
+ }
+
+ operator const mu::Parser &() const
+ {
+ return parser;
+ }
+
+ protected:
+ mu::Parser parser;
+ };
+ } // namespace
+ } // namespace FunctionParserImplementation
+} // namespace internal
template <int dim>
vars.get().resize(var_names.size());
for (unsigned int component = 0; component < this->n_components; ++component)
{
- fp.get().emplace_back(new mu::Parser());
+ fp.get().emplace_back(
+ std::make_unique<internal::FunctionParserImplementation::Parser>());
+ mu::Parser &parser =
+ dynamic_cast<internal::FunctionParserImplementation::Parser &>(
+ *fp.get().back());
for (const auto &constant : constants)
{
- fp.get()[component]->DefineConst(constant.first, constant.second);
+ parser.DefineConst(constant.first, constant.second);
}
for (unsigned int iv = 0; iv < var_names.size(); ++iv)
- fp.get()[component]->DefineVar(var_names[iv], &vars.get()[iv]);
+ parser.DefineVar(var_names[iv], &vars.get()[iv]);
// define some compatibility functions:
- fp.get()[component]->DefineFun("if",
- internal::FunctionParser::mu_if,
- true);
- fp.get()[component]->DefineOprt("|", internal::FunctionParser::mu_or, 1);
- fp.get()[component]->DefineOprt("&", internal::FunctionParser::mu_and, 2);
- fp.get()[component]->DefineFun("int",
- internal::FunctionParser::mu_int,
- true);
- fp.get()[component]->DefineFun("ceil",
- internal::FunctionParser::mu_ceil,
- true);
- fp.get()[component]->DefineFun("cot",
- internal::FunctionParser::mu_cot,
- true);
- fp.get()[component]->DefineFun("csc",
- internal::FunctionParser::mu_csc,
- true);
- fp.get()[component]->DefineFun("floor",
- internal::FunctionParser::mu_floor,
- true);
- fp.get()[component]->DefineFun("sec",
- internal::FunctionParser::mu_sec,
- true);
- fp.get()[component]->DefineFun("log",
- internal::FunctionParser::mu_log,
- true);
- fp.get()[component]->DefineFun("pow",
- internal::FunctionParser::mu_pow,
- true);
- fp.get()[component]->DefineFun("erf",
- internal::FunctionParser::mu_erf,
- true);
- fp.get()[component]->DefineFun("erfc",
- internal::FunctionParser::mu_erfc,
- true);
- fp.get()[component]->DefineFun("rand_seed",
- internal::FunctionParser::mu_rand_seed,
- true);
- fp.get()[component]->DefineFun("rand",
- internal::FunctionParser::mu_rand,
- true);
+ parser.DefineFun("if", internal::FunctionParser::mu_if, true);
+ parser.DefineOprt("|", internal::FunctionParser::mu_or, 1);
+ parser.DefineOprt("&", internal::FunctionParser::mu_and, 2);
+ parser.DefineFun("int", internal::FunctionParser::mu_int, true);
+ parser.DefineFun("ceil", internal::FunctionParser::mu_ceil, true);
+ parser.DefineFun("cot", internal::FunctionParser::mu_cot, true);
+ parser.DefineFun("csc", internal::FunctionParser::mu_csc, true);
+ parser.DefineFun("floor", internal::FunctionParser::mu_floor, true);
+ parser.DefineFun("sec", internal::FunctionParser::mu_sec, true);
+ parser.DefineFun("log", internal::FunctionParser::mu_log, true);
+ parser.DefineFun("pow", internal::FunctionParser::mu_pow, true);
+ parser.DefineFun("erf", internal::FunctionParser::mu_erf, true);
+ parser.DefineFun("erfc", internal::FunctionParser::mu_erfc, true);
+ parser.DefineFun("rand_seed",
+ internal::FunctionParser::mu_rand_seed,
+ true);
+ parser.DefineFun("rand", internal::FunctionParser::mu_rand, true);
try
{
}
// now use the transformed expression
- fp.get()[component]->SetExpr(transformed_expression);
+ parser.SetExpr(transformed_expression);
}
catch (mu::ParserError &e)
{
try
{
- return fp.get()[component]->Eval();
+ Assert(dynamic_cast<internal::FunctionParserImplementation::Parser *>(
+ fp.get()[component].get()),
+ ExcInternalError());
+ // using dynamic_cast in the next line is about 6% slower than
+ // static_cast, so use the assertion above for debugging and disable
+ // clang-tidy:
+ mu::Parser &parser =
+ static_cast<internal::FunctionParserImplementation::Parser &>( // NOLINT
+ *fp.get()[component]);
+ return parser.Eval();
}
catch (mu::ParserError &e)
{
vars.get()[dim] = this->get_time();
for (unsigned int component = 0; component < this->n_components; ++component)
- values(component) = fp.get()[component]->Eval();
+ {
+ // Same comment in value() applies here too:
+ Assert(dynamic_cast<internal::FunctionParserImplementation::Parser *>(
+ fp.get()[component].get()),
+ ExcInternalError());
+ mu::Parser &parser =
+ static_cast<internal::FunctionParserImplementation::Parser &>( // NOLINT
+ *fp.get()[component]);
+
+ values(component) = parser.Eval();
+ }
}
#else
}
-// We deliberately delay the definition of the default destructor
-// so that we don't need to include the definition of mu::Parser
-// in the header file.
-template <int rank, int dim, typename Number>
-TensorFunctionParser<rank, dim, Number>::~TensorFunctionParser() = default;
-
-
#ifdef DEAL_II_WITH_MUPARSER
template <int rank, int dim, typename Number>
+namespace internal
+{
+ namespace TensorFunctionParserImplementation
+ {
+ namespace
+ {
+ /**
+ * PIMPL for mu::Parser.
+ */
+ class Parser : public internal::muParserBase
+ {
+ public:
+ operator mu::Parser &()
+ {
+ return parser;
+ }
+
+ operator const mu::Parser &() const
+ {
+ return parser;
+ }
+
+ protected:
+ mu::Parser parser;
+ };
+ } // namespace
+ } // namespace TensorFunctionParserImplementation
+} // namespace internal
+
+
+
template <int rank, int dim, typename Number>
void
TensorFunctionParser<rank, dim, Number>::init_muparser() const
vars.get().resize(var_names.size());
for (unsigned int component = 0; component < this->n_components; ++component)
{
- tfp.get().emplace_back(new mu::Parser());
+ tfp.get().emplace_back(
+ std::make_unique<
+ internal::TensorFunctionParserImplementation::Parser>());
+ mu::Parser &parser =
+ dynamic_cast<internal::TensorFunctionParserImplementation::Parser &>(
+ *tfp.get().back());
for (const auto &constant : constants)
{
- tfp.get()[component]->DefineConst(constant.first, constant.second);
+ parser.DefineConst(constant.first, constant.second);
}
for (unsigned int iv = 0; iv < var_names.size(); ++iv)
- tfp.get()[component]->DefineVar(var_names[iv], &vars.get()[iv]);
+ parser.DefineVar(var_names[iv], &vars.get()[iv]);
// define some compatibility functions:
- tfp.get()[component]->DefineFun("if",
- internal::FunctionParser::mu_if,
- true);
- tfp.get()[component]->DefineOprt("|", internal::FunctionParser::mu_or, 1);
- tfp.get()[component]->DefineOprt("&",
- internal::FunctionParser::mu_and,
- 2);
- tfp.get()[component]->DefineFun("int",
- internal::FunctionParser::mu_int,
- true);
- tfp.get()[component]->DefineFun("ceil",
- internal::FunctionParser::mu_ceil,
- true);
- tfp.get()[component]->DefineFun("cot",
- internal::FunctionParser::mu_cot,
- true);
- tfp.get()[component]->DefineFun("csc",
- internal::FunctionParser::mu_csc,
- true);
- tfp.get()[component]->DefineFun("floor",
- internal::FunctionParser::mu_floor,
- true);
- tfp.get()[component]->DefineFun("sec",
- internal::FunctionParser::mu_sec,
- true);
- tfp.get()[component]->DefineFun("log",
- internal::FunctionParser::mu_log,
- true);
- tfp.get()[component]->DefineFun("pow",
- internal::FunctionParser::mu_pow,
- true);
- tfp.get()[component]->DefineFun("erfc",
- internal::FunctionParser::mu_erfc,
- true);
- tfp.get()[component]->DefineFun("rand_seed",
- internal::FunctionParser::mu_rand_seed,
- true);
- tfp.get()[component]->DefineFun("rand",
- internal::FunctionParser::mu_rand,
- true);
+ parser.DefineFun("if", internal::FunctionParser::mu_if, true);
+ parser.DefineOprt("|", internal::FunctionParser::mu_or, 1);
+ parser.DefineOprt("&", internal::FunctionParser::mu_and, 2);
+ parser.DefineFun("int", internal::FunctionParser::mu_int, true);
+ parser.DefineFun("ceil", internal::FunctionParser::mu_ceil, true);
+ parser.DefineFun("cot", internal::FunctionParser::mu_cot, true);
+ parser.DefineFun("csc", internal::FunctionParser::mu_csc, true);
+ parser.DefineFun("floor", internal::FunctionParser::mu_floor, true);
+ parser.DefineFun("sec", internal::FunctionParser::mu_sec, true);
+ parser.DefineFun("log", internal::FunctionParser::mu_log, true);
+ parser.DefineFun("pow", internal::FunctionParser::mu_pow, true);
+ parser.DefineFun("erfc", internal::FunctionParser::mu_erfc, true);
+ parser.DefineFun("rand_seed",
+ internal::FunctionParser::mu_rand_seed,
+ true);
+ parser.DefineFun("rand", internal::FunctionParser::mu_rand, true);
try
{
}
// now use the transformed expression
- tfp.get()[component]->SetExpr(transformed_expression);
+ parser.SetExpr(transformed_expression);
}
catch (mu::ParserError &e)
{
for (Number *value_ptr = value.begin_raw(); value_ptr != value.end_raw();
++value_ptr)
{
- *value_ptr = tfp.get()[component]->Eval();
+ Assert(dynamic_cast<
+ internal::TensorFunctionParserImplementation::Parser *>(
+ tfp.get()[component].get()),
+ ExcInternalError());
+ mu::Parser &parser = static_cast< // NOLINT
+ internal::TensorFunctionParserImplementation::Parser &>(
+ *tfp.get()[component]);
+ *value_ptr = parser.Eval();
++component;
} // for
} // try