From 97fcea36cbb4c0c69ff002a34ffa6520e858b6f7 Mon Sep 17 00:00:00 2001 From: Weiqun Zhang Date: Mon, 16 Sep 2024 21:20:16 -0500 Subject: [PATCH] ParmParse::queryAsDouble: Support bool and std::optional (#4152) This is needed in WarpX. --- Src/Base/AMReX_ParmParse.H | 103 ++++++++++++++++++++++++++++--------- Tests/ParmParse/inputs | 2 + Tests/ParmParse/main.cpp | 14 +++++ 3 files changed, 94 insertions(+), 25 deletions(-) diff --git a/Src/Base/AMReX_ParmParse.H b/Src/Base/AMReX_ParmParse.H index caa4697cd5..a29ac163d6 100644 --- a/Src/Base/AMReX_ParmParse.H +++ b/Src/Base/AMReX_ParmParse.H @@ -11,10 +11,11 @@ #include #include -#include +#include #include #include #include +#include #include namespace amrex { @@ -27,6 +28,32 @@ class IntVectND; using IntVect = IntVectND; class RealVect; +namespace ppdetail { + template + struct ArithmeticOptional_TT : std::false_type {}; + + template + struct ArithmeticOptional_TT>> + : std::true_type + { + using value_type = T; + }; + + template + struct ArithmeticOptional_TT, + std::enable_if_t>> + : std::true_type + { + using value_type = T; + }; + + template + inline constexpr bool IsArithmeticOptional_v = ArithmeticOptional_TT::value; + + template + using underlying_type_t = typename ArithmeticOptional_TT::value_type; +} + // // ParmParse class implements a simple database for the storage and // retrieval of command-line and input-file arguments. The entries are @@ -1428,49 +1455,71 @@ public: } } - //! \brief Query integer with Parser, but treat the number as double - //! precision during parsing. The final result is cast to integer. It - //! may result in a runtime error if the conversion is not safe. - template ,int> = 0> + /** + * \brief Query T with Parser, but treat the number as double precision + * during parsing. + * + * The final result is cast to T. It may result in a runtime error if + * the conversion is not safe. T is either arithmetic type or + * std::optional of arithmetic type. + */ + template , int> = 0> int queryAsDouble (const char* name, T& ref) const { + using value_type = ppdetail::underlying_type_t; double dref; int exist = queryWithParser(name, dref); if (exist) { dref = std::round(dref); - ref = static_cast(dref); - if (static_cast(ref) != dref) { - amrex::Abort("ParmParse:: queryAsDouble is not safe"); + auto vref = static_cast(dref); + if constexpr (!std::is_same_v) { + if (static_cast(vref) != dref) { + amrex::Abort("ParmParse:: queryAsDouble is not safe"); + } } + ref = vref; } return exist; } - //! \brief Query integer array with Parser, but treat the numbers as - //! double precision uring parsing. The final results are cast to - //! integers. It may result in a runtime error if the conversion is not - //! safe. - template ,int> = 0> + /** + * \brief Query T array with Parser, but treat the number as double + * precision during parsing. + * + * The final result is cast to T's. It may result in a runtime error if + * the conversion is not safe. T is either arithmetic type or + * std::optional of arithmetic type. + */ + template , int> = 0> int queryarrAsDouble (const char* name, int nvals, T* ref) const { + using value_type = ppdetail::underlying_type_t; std::vector dref(nvals); int exist = queryarrWithParser(name, nvals, dref.data()); if (exist) { for (int i = 0; i < nvals; ++i) { dref[i] = std::round(dref[i]); - ref[i] = static_cast(dref[i]); - if (static_cast(ref[i]) != dref[i]) { - amrex::Abort("ParmParse:: queryarrAsDouble is not safe"); + auto vref = static_cast(dref[i]); + if constexpr (!std::is_same_v) { + if (static_cast(vref) != dref[i]) { + amrex::Abort("ParmParse:: queryarrAsDouble is not safe"); + } } + ref[i] = vref; } } return exist; } - //! \brief Get integer with Parser, but treat the number as double - //! precision during parsing. The final result is cast to integer. It - //! may result in a runtime error if the conversion is not safe. - template ,int> = 0> + /** + * \brief Get T with Parser, but treat the number as double precision + * during parsing. + * + * The final result is cast to T. It may result in a runtime error if + * the conversion is not safe. T is either arithmetic type or + * std::optional of arithmetic type. + */ + template , int> = 0> void getAsDouble (const char* name, T& ref) const { int exist = this->queryAsDouble(name, ref); @@ -1479,11 +1528,15 @@ public: } } - //! \brief Get integer array with Parser, but treat the numbers as - //! double precision uring parsing. The final results are cast to - //! integers. It may result in a runtime error if the conversion is not - //! safe. - template ,int> = 0> + /** + * \brief Get T array with Parser, but treat the number as double + * precision during parsing. + * + * The final result is cast to T's. It may result in a runtime error if + * the conversion is not safe. T is either arithmetic type or + * std::optional of arithmetic type. + */ + template , int> = 0> void getarrAsDouble (const char* name, int nvals, T* ref) const { int exist = this->queryarrAsDouble(name, nvals, ref); diff --git a/Tests/ParmParse/inputs b/Tests/ParmParse/inputs index b053026d87..ab876ad9ef 100644 --- a/Tests/ParmParse/inputs +++ b/Tests/ParmParse/inputs @@ -60,3 +60,5 @@ my_constants.dx = 6.25e-7 my_constants.nx = lx/dx n_cell = nx nx nx ny = nx + +do_this = 1 diff --git a/Tests/ParmParse/main.cpp b/Tests/ParmParse/main.cpp index cc8aa2261e..68612e82ea 100644 --- a/Tests/ParmParse/main.cpp +++ b/Tests/ParmParse/main.cpp @@ -122,6 +122,20 @@ int main(int argc, char* argv[]) pp.queryarrAsDouble("n_cell", 3, n_cell.data()); AMREX_ALWAYS_ASSERT(n_cell[0] == 64 && n_cell[1] == 64 && n_cell[2] == 64); } + { + ParmParse pp; + bool b_do_this = false; + pp.queryAsDouble("do_this", b_do_this); + AMREX_ALWAYS_ASSERT(b_do_this); + + std::optional o_do_this; + pp.queryAsDouble("do_this", o_do_this); + AMREX_ALWAYS_ASSERT(o_do_this.has_value() && o_do_this.value()); + + std::optional o_do_that; + pp.queryAsDouble("do_that", o_do_that); + AMREX_ALWAYS_ASSERT(!o_do_that.has_value()); + } { amrex::Print() << "SUCCESS\n"; }