From 83ef572d7750e746ed9319b40cb8dc9126e13d8e Mon Sep 17 00:00:00 2001 From: Cyrus Harrison Date: Fri, 12 Mar 2021 11:40:48 -0800 Subject: [PATCH] added methods to get active info,warning, and error handlers (#726) * added methods to get active info,warning, and error handlers * fix extra changelog stuff * you learn something new every day * learning continues, but this time related to spelling * add docs about accessing default handlers --- CHANGELOG.md | 4 +- src/docs/sphinx/tutorial_cpp_errors.rst | 17 +++ src/libs/conduit/conduit_utils.cpp | 21 +++ src/libs/conduit/conduit_utils.hpp | 61 ++++++--- src/tests/conduit/t_conduit_utils.cpp | 122 ++++++++++++++++++ .../docs/t_conduit_docs_tutorial_errors.cpp | 19 +++ 6 files changed, 225 insertions(+), 19 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 32178294f..49d24a047 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s ### Added #### General +- Added `conduit::utils::info_handler()`, `conduit::utils::warning_handler()`, and `conduit::utils::error_handler()` methods, which provide access to the currently registered info, warning, and error handlers. - Added DataType::index_t method. Creates a DataType instance that describes an `index_t`, which is an alias to either `int32`, or `int 64` controlled by the `CONDUIT_INDEX_32` compile time option. - Added several more methods to Python DataType interface @@ -472,7 +473,8 @@ and this project aspires to adhere to [Semantic Versioning](https://semver.org/s ### Added - Initial Open Source Release on GitHub -[Unreleased]: https://github.com/llnl/conduit/compare/v0.7.0...HEAD +[Unreleased]: https://github.com/llnl/conduit/compare/v0.7.1...HEAD +[0.7.1]: https://github.com/llnl/conduit/compare/v0.7.0...v0.7.1 [0.7.0]: https://github.com/llnl/conduit/compare/v0.6.0...v0.7.0 [0.6.0]: https://github.com/llnl/conduit/compare/v0.5.1...v0.6.0 [0.5.1]: https://github.com/llnl/conduit/compare/v0.5.0...v0.5.1 diff --git a/src/docs/sphinx/tutorial_cpp_errors.rst b/src/docs/sphinx/tutorial_cpp_errors.rst index 945936935..129bf6a00 100644 --- a/src/docs/sphinx/tutorial_cpp_errors.rst +++ b/src/docs/sphinx/tutorial_cpp_errors.rst @@ -80,3 +80,20 @@ The default handlers are part of the conduit::utils interface, so you can restor :language: cpp :dedent: 4 +Accessing Current Handlers +-------------------------------- + +You can access the currently active handlers using the `conduit::utils::info_handler()`, +`conduit::utils::warning_handler()`, and `conduit::utils::error_handler()` methods. +Here is an example that shows how to save the current handlers, temporarily restore +the default handlers, execute an operation, and finally restore the saved handlers: + +.. literalinclude:: ../../tests/docs/t_conduit_docs_tutorial_errors.cpp + :start-after: BEGIN_EXAMPLE("error_handlers_current_push_pop") + :end-before: END_EXAMPLE("error_handlers_current_push_pop") + :language: cpp + :dedent: 4 + + + + diff --git a/src/libs/conduit/conduit_utils.cpp b/src/libs/conduit/conduit_utils.cpp index 68d1ee08f..aa330fdcd 100644 --- a/src/libs/conduit/conduit_utils.cpp +++ b/src/libs/conduit/conduit_utils.cpp @@ -104,6 +104,13 @@ set_info_handler(void(*on_info) conduit_on_info = on_info; } +//----------------------------------------------------------------------------- +conduit_info_handler +info_handler() +{ + return conduit_on_info; +} + //----------------------------------------------------------------------------- void handle_info(const std::string &msg, @@ -140,6 +147,13 @@ set_warning_handler(void(*on_warning) conduit_on_warning = on_warning; } +//----------------------------------------------------------------------------- +conduit_warning_handler +warning_handler() +{ + return conduit_on_warning; +} + //----------------------------------------------------------------------------- void handle_warning(const std::string &msg, @@ -177,6 +191,13 @@ set_error_handler(void(*on_error) conduit_on_error = on_error; } +//----------------------------------------------------------------------------- +conduit_error_handler +error_handler() +{ + return conduit_on_error; +} + //----------------------------------------------------------------------------- void handle_error(const std::string &msg, diff --git a/src/libs/conduit/conduit_utils.hpp b/src/libs/conduit/conduit_utils.hpp index c3ed26015..a31d00d4d 100644 --- a/src/libs/conduit/conduit_utils.hpp +++ b/src/libs/conduit/conduit_utils.hpp @@ -164,7 +164,6 @@ class Node; //----------------------------------------------------------------------------- namespace utils { - //----------------------------------------------------------------------------- /// Primary interface used by the conduit API when an info message is issued /// This simply dispatches the message to the currently configured info handler. @@ -175,12 +174,11 @@ namespace utils int line); //----------------------------------------------------------------------------- -/// Allows other libraries to provide an alternate info message handler. +/// Info handler callback function type //----------------------------------------------------------------------------- - void CONDUIT_API set_info_handler( void(*on_info) - (const std::string &, + typedef void(*conduit_info_handler)(const std::string &, const std::string &, - int)); + int); //----------------------------------------------------------------------------- /// Default info message handler, which prints the message to std::cout; @@ -189,6 +187,16 @@ namespace utils const std::string &file, int line); +//----------------------------------------------------------------------------- +/// Allows other libraries to provide an alternate info message handler. +//----------------------------------------------------------------------------- + void CONDUIT_API set_info_handler(conduit_info_handler on_info); + +//----------------------------------------------------------------------------- +/// Returns the active info message handler. +//----------------------------------------------------------------------------- + conduit_info_handler CONDUIT_API info_handler(); + //----------------------------------------------------------------------------- /// Primary interface used by the conduit API when a warning is issued. /// This simply dispatches the warning to the currently configured warning handler. @@ -199,12 +207,11 @@ namespace utils int line); //----------------------------------------------------------------------------- -/// Allows other libraries to provide an alternate warning handler. +/// Warning handler callback function type //----------------------------------------------------------------------------- - void CONDUIT_API set_warning_handler( void(*on_error) - (const std::string &, - const std::string &, - int)); + typedef void(*conduit_warning_handler)(const std::string &, + const std::string &, + int); //----------------------------------------------------------------------------- /// Default warning handler, which throws a conduit::Error exception. @@ -213,6 +220,15 @@ namespace utils const std::string &file, int line); +//----------------------------------------------------------------------------- +/// Allows other libraries to provide an alternate warning handler. +//----------------------------------------------------------------------------- + void CONDUIT_API set_warning_handler(conduit_warning_handler on_warning); + +//----------------------------------------------------------------------------- +/// Returns the active warning message handler. +//----------------------------------------------------------------------------- + conduit_warning_handler CONDUIT_API warning_handler(); //----------------------------------------------------------------------------- /// Primary interface used by the conduit API when an error occurs. @@ -223,20 +239,29 @@ namespace utils const std::string &file, int line); -//----------------------------------------------------------------------------- -/// Allows other libraries to provide an alternate error handler. -//----------------------------------------------------------------------------- - void CONDUIT_API set_error_handler( void(*on_error) - (const std::string &, - const std::string &, - int)); - //----------------------------------------------------------------------------- /// Default error handler, which throws a conduit::Error exception. //----------------------------------------------------------------------------- void CONDUIT_API default_error_handler(const std::string &msg, const std::string &file, int line); +//----------------------------------------------------------------------------- +/// Warning handler callback function type +//----------------------------------------------------------------------------- + typedef void(*conduit_error_handler)(const std::string &, + const std::string &, + int); + +//----------------------------------------------------------------------------- +/// Allows other libraries to provide an alternate error handler. +//----------------------------------------------------------------------------- + void CONDUIT_API set_error_handler(conduit_error_handler on_error); + +//----------------------------------------------------------------------------- +/// Returns the active warning message handler. +//----------------------------------------------------------------------------- + conduit_error_handler CONDUIT_API error_handler(); + //----------------------------------------------------------------------------- /// Helpers for common string splitting operations. diff --git a/src/tests/conduit/t_conduit_utils.cpp b/src/tests/conduit/t_conduit_utils.cpp index 976c3baae..0d6d846ef 100644 --- a/src/tests/conduit/t_conduit_utils.cpp +++ b/src/tests/conduit/t_conduit_utils.cpp @@ -24,6 +24,10 @@ bool info_occured = false; bool warning_occured = false; bool error_occured = false; +bool other_info_occured = false; +bool other_warning_occured = false; +bool other_error_occured = false; + //----------------------------------------------------------------------------- void print_msg(const std::string &msg, @@ -66,6 +70,38 @@ my_error_handler(const std::string &msg, error_occured = true; } +//----------------------------------------------------------------------------- +void +my_other_info_handler(const std::string &msg, + const std::string &file, + int line) +{ + print_msg(msg,file,line); + other_info_occured = true; +} + + +//----------------------------------------------------------------------------- +void +my_other_warning_handler(const std::string &msg, + const std::string &file, + int line) +{ + print_msg(msg,file,line); + other_warning_occured = true; +} + +//----------------------------------------------------------------------------- +void +my_other_error_handler(const std::string &msg, + const std::string &file, + int line) +{ + print_msg(msg,file,line); + other_error_occured = true; +} + + //----------------------------------------------------------------------------- TEST(conduit_utils, error_constructors) { @@ -148,6 +184,92 @@ TEST(conduit_utils, override_error) } +//----------------------------------------------------------------------------- +TEST(conduit_utils, handler_defaults_are_the_defaults) +{ + conduit::utils::conduit_info_handler on_info = conduit::utils::info_handler(); + conduit::utils::conduit_info_handler on_info_default = conduit::utils::default_info_handler; + EXPECT_EQ(on_info,on_info_default); + + conduit::utils::conduit_warning_handler on_warning = conduit::utils::warning_handler(); + conduit::utils::conduit_warning_handler on_warning_default = conduit::utils::default_warning_handler; + EXPECT_EQ(on_warning,on_warning_default); + + conduit::utils::conduit_error_handler on_error = conduit::utils::error_handler(); + conduit::utils::conduit_error_handler on_error_default = conduit::utils::default_error_handler; + EXPECT_EQ(on_error,on_error_default); + + + EXPECT_NE(on_info,on_error); + EXPECT_NE(on_info,on_warning); + + // + // NOTE: (Excerpt from "Adventures in fun with compilers") + // The default implementations of: + // conduit::utils::default_warning_handler + // and + // conduit::utils::default_error_handler + // are identical at the source level. + // On windows, we hit a case where the compiler understands this + // and low and behold there is only one copy! + // + // B/c of this we can't expect the following to hold: + // EXPECT_NE(on_error,on_warning); + // + +} + +//----------------------------------------------------------------------------- +TEST(conduit_utils, handler_defaults_push_pop) +{ + // change to other handler + conduit::utils::set_info_handler(my_other_info_handler); + conduit::utils::set_warning_handler(my_other_warning_handler); + conduit::utils::set_error_handler(my_other_error_handler); + + // ---------- + // demo push / pop like swing to default + // ---------- + conduit::utils::conduit_info_handler curr_on_info = conduit::utils::info_handler(); + conduit::utils::conduit_warning_handler curr_on_warning = conduit::utils::warning_handler(); + conduit::utils::conduit_error_handler curr_on_error = conduit::utils::error_handler(); + + // set to default + conduit::utils::set_info_handler(conduit::utils::default_info_handler); + conduit::utils::set_warning_handler(conduit::utils::default_warning_handler); + conduit::utils::set_error_handler(conduit::utils::default_error_handler); + + EXPECT_THROW(utils::handle_warning("ERROR!",__FILE__,__LINE__), + conduit::Error); + + // set to curr + conduit::utils::set_info_handler(curr_on_info); + conduit::utils::set_warning_handler(curr_on_warning); + conduit::utils::set_error_handler(curr_on_error); + + EXPECT_FALSE(other_info_occured); + EXPECT_FALSE(other_warning_occured); + EXPECT_FALSE(other_error_occured); + + utils::handle_info("INFO!",__FILE__,__LINE__); + utils::handle_warning("WARNING!",__FILE__,__LINE__); + utils::handle_error("ERROR!",__FILE__,__LINE__); + + EXPECT_TRUE(other_info_occured); + EXPECT_TRUE(other_warning_occured); + EXPECT_TRUE(other_error_occured); + + + // back set to default (for other tests !!!!) + conduit::utils::set_info_handler(conduit::utils::default_info_handler); + conduit::utils::set_warning_handler(conduit::utils::default_warning_handler); + conduit::utils::set_error_handler(conduit::utils::default_error_handler); + +} + + + + //----------------------------------------------------------------------------- TEST(conduit_utils, escape_special_chars) { diff --git a/src/tests/docs/t_conduit_docs_tutorial_errors.cpp b/src/tests/docs/t_conduit_docs_tutorial_errors.cpp index 335829de0..443145a96 100644 --- a/src/tests/docs/t_conduit_docs_tutorial_errors.cpp +++ b/src/tests/docs/t_conduit_docs_tutorial_errors.cpp @@ -100,6 +100,25 @@ TEST(conduit_tutorial, error_handlers) conduit::utils::set_warning_handler(conduit::utils::default_warning_handler); conduit::utils::set_error_handler(conduit::utils::default_error_handler); END_EXAMPLE("error_handlers_reset"); + + BEGIN_EXAMPLE("error_handlers_current_push_pop"); + // store current handlers + conduit::utils::conduit_info_handler on_info = conduit::utils::info_handler(); + conduit::utils::conduit_warning_handler on_warn = conduit::utils::warning_handler(); + conduit::utils::conduit_error_handler on_error = conduit::utils::error_handler(); + + // temporarily restore default handlers + conduit::utils::set_info_handler(conduit::utils::default_info_handler); + conduit::utils::set_warning_handler(conduit::utils::default_warning_handler); + conduit::utils::set_error_handler(conduit::utils::default_error_handler); + + // do something exciting ... + + // done with excitement, reset to previously saved handlers + conduit::utils::set_info_handler(on_info); + conduit::utils::set_warning_handler(on_warn); + conduit::utils::set_error_handler(on_error); + END_EXAMPLE("error_handlers_current_push_pop"); }