From 8baec601550db1151817607be0b00a8a8c8e0fde Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Thu, 23 Jan 2025 00:03:30 -0500 Subject: [PATCH] implement an utils::print() function similar to fmt::print() this doesn't have the constexpr requirement for the format string. also it will help porting to std::format in C++20, which doesn't have a similar functionality either. --- doc/src/Developer_code_design.rst | 35 ++++++++++--------- doc/src/Developer_utils.rst | 6 ++++ doc/src/Developer_write_fix.rst | 4 +-- doc/utils/sphinx-config/false_positives.txt | 1 + src/utils.cpp | 16 +++++++++ src/utils.h | 38 +++++++++++++++++++-- 6 files changed, 80 insertions(+), 20 deletions(-) diff --git a/doc/src/Developer_code_design.rst b/doc/src/Developer_code_design.rst index 974266ec7f..02c0e7731b 100644 --- a/doc/src/Developer_code_design.rst +++ b/doc/src/Developer_code_design.rst @@ -300,18 +300,19 @@ Formatting with the {fmt} library The LAMMPS source code includes a copy of the `{fmt} library `_, which is preferred over formatting with the -"printf()" family of functions. The primary reason is that it allows -a typesafe default format for any type of supported data. This is +"printf()" family of functions. The primary reason is that it allows a +typesafe default format for any type of supported data. This is particularly useful for formatting integers of a given size (32-bit or -64-bit) which may require different format strings depending on -compile time settings or compilers/operating systems. Furthermore, -{fmt} gives better performance, has more functionality, a familiar -formatting syntax that has similarities to ``format()`` in Python, and -provides a facility that can be used to integrate format strings and a -variable number of arguments into custom functions in a much simpler -way than the varargs mechanism of the C library. Finally, {fmt} has -been included into the C++20 language standard, so changes to adopt it -are future-proof. +64-bit) which may require different format strings depending on compile +time settings or compilers/operating systems. Furthermore, {fmt} gives +better performance, has more functionality, a familiar formatting syntax +that has similarities to ``format()`` in Python, and provides a facility +that can be used to integrate format strings and a variable number of +arguments into custom functions in a much simpler way than the varargs +mechanism of the C library. Finally, {fmt} has been included into the +C++20 language standard as ``std::format()``, so changes to adopt it are +future-proof, for as long as they are not using any extensions that are +not (yet) included into C++. Formatted strings are frequently created by calling the ``fmt::format()`` function, which will return a string as a @@ -319,11 +320,13 @@ Formatted strings are frequently created by calling the ``printf()``, the {fmt} library uses ``{}`` to embed format descriptors. In the simplest case, no additional characters are needed, as {fmt} will choose the default format based on the data type of the argument. -Otherwise, the ``fmt::print()`` function may be used instead of -``printf()`` or ``fprintf()``. In addition, several LAMMPS output -functions, that originally accepted a single string as argument have -been overloaded to accept a format string with optional arguments as -well (e.g., ``Error::all()``, ``Error::one()``, ``utils::logmesg()``). +Otherwise, the :cpp:func:`utils::print() ` +function may be used instead of ``printf()`` or ``fprintf()``. In +addition, several LAMMPS output functions, that originally accepted a +single string as argument have been overloaded to accept a format string +with optional arguments as well (e.g., ``Error::all()``, +``Error::one()``, :cpp:func:`utils::logmesg() +`). Summary of the {fmt} format syntax ================================== diff --git a/doc/src/Developer_utils.rst b/doc/src/Developer_utils.rst index 86a536f0cd..866945fc88 100644 --- a/doc/src/Developer_utils.rst +++ b/doc/src/Developer_utils.rst @@ -238,6 +238,12 @@ Convenience functions .. doxygenfunction:: logmesg(LAMMPS *lmp, const std::string &mesg) :project: progguide +.. doxygenfunction:: print(FILE *fp, const std::string &format, Args&&... args) + :project: progguide + +.. doxygenfunction:: print(FILE *fp, const std::string &mesg) + :project: progguide + .. doxygenfunction:: errorurl :project: progguide diff --git a/doc/src/Developer_write_fix.rst b/doc/src/Developer_write_fix.rst index afa569b05d..1b578823bd 100644 --- a/doc/src/Developer_write_fix.rst +++ b/doc/src/Developer_write_fix.rst @@ -96,8 +96,8 @@ Here the we specify which methods of the fix should be called during MPI_Allreduce(localAvgVel, globalAvgVel, 4, MPI_DOUBLE, MPI_SUM, world); scale3(1.0 / globalAvgVel[3], globalAvgVel); if ((comm->me == 0) && screen) { - fmt::print(screen,"{}, {}, {}\n", - globalAvgVel[0], globalAvgVel[1], globalAvgVel[2]); + utils::print(screen, "{}, {}, {}\n", + globalAvgVel[0], globalAvgVel[1], globalAvgVel[2]); } } diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index f272af6dec..1a1d4d1af3 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -1236,6 +1236,7 @@ fp fphi fPIC fplo +fprintf Fqq Fraige framerate diff --git a/src/utils.cpp b/src/utils.cpp index 52d7e5113a..3f571991e1 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -262,6 +262,22 @@ void utils::fmtargs_logmesg(LAMMPS *lmp, fmt::string_view format, fmt::format_ar } } +/* specialization for the case of just a single string argument */ + +void utils::print(FILE *fp, const std::string &mesg) +{ + fputs(mesg.c_str(), fp); +} + +void utils::fmtargs_print(FILE *fp, fmt::string_view format, fmt::format_args args) +{ + try { + print(fp, fmt::vformat(format, args)); + } catch (fmt::format_error &) { + ; // do nothing + } +} + std::string utils::errorurl(int errorcode) { return fmt::format("\nFor more information see https://docs.lammps.org/err{:04d}", errorcode); diff --git a/src/utils.h b/src/utils.h index 38f91cfc66..5de7dda82e 100644 --- a/src/utils.h +++ b/src/utils.h @@ -92,8 +92,8 @@ namespace utils { * * This function simplifies the repetitive task of outputting some * message to both the screen and/or the log file. The template - * wrapper with fmtlib format and argument processing allows - * this function to work similar to ``fmt::print()``. + * wrapper with {fmt} formatting and argument processing allows + * this function to work similar to :cpp:func:`utils::print() `. * * \param lmp pointer to LAMMPS class instance * \param format format string of message to be printed @@ -111,6 +111,40 @@ namespace utils { void logmesg(LAMMPS *lmp, const std::string &mesg); + /*! Return text redirecting the user to a specific paragraph in the manual + * + * The LAMMPS manual contains detailed explanations for errors and + * warnings where a simple error message may not be sufficient. These can + * be reached through URLs with a numeric code. This function creates the + * corresponding text to be included into the error message that redirects + * the user to that URL. + * + * \param errorcode number pointing to a paragraph in the manual */ + + /*! Internal function handling the argument list for print(). */ + + void fmtargs_print(FILE *fp, fmt::string_view format, fmt::format_args args); + + /*! Write formatted message to file + * + * This function implements a version of fprintf() that uses {fmt} formatting + * + * \param fp stdio FILE pointer + * \param format format string of message to be printed + * \param args arguments to format string */ + + template void print(FILE *fp, const std::string &format, Args &&...args) + { + fmtargs_print(fp, format, fmt::make_format_args(args...)); + } + + /*! \overload + * + * \param fp stdio FILE pointer + * \param mesg string with message to be printed */ + + void print(FILE *fp, const std::string &mesg); + /*! Return text redirecting the user to a specific paragraph in the manual * * The LAMMPS manual contains detailed explanations for errors and