diff options
-rw-r--r-- | host/include/uhd/exception.hpp | 33 | ||||
-rw-r--r-- | host/lib/exception.cpp | 4 | ||||
-rw-r--r-- | host/tests/error_test.cpp | 35 |
3 files changed, 69 insertions, 3 deletions
diff --git a/host/include/uhd/exception.hpp b/host/include/uhd/exception.hpp index e2a50bf1e..10cd8f501 100644 --- a/host/include/uhd/exception.hpp +++ b/host/include/uhd/exception.hpp @@ -32,72 +32,105 @@ * * The code() provides an error code which allows the application * the option of printing a cryptic error message from the 1990s. + * + * The dynamic_clone() and dynamic_throw() methods allow us to: + * catch an exception by dynamic type (i.e. derived class), save it, + * and later rethrow it, knowing only the static type (i.e. base class), + * and then finally to catch it again using the derived type. + * + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2106.html */ namespace uhd{ struct UHD_API exception : std::runtime_error{ exception(const std::string &what); virtual unsigned code(void) const = 0; + virtual exception *dynamic_clone(void) const = 0; + virtual void dynamic_throw(void) const = 0; }; struct UHD_API assertion_error : exception{ assertion_error(const std::string &what); virtual unsigned code(void) const; + virtual assertion_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API lookup_error : exception{ lookup_error(const std::string &what); virtual unsigned code(void) const; + virtual lookup_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API index_error : lookup_error{ index_error(const std::string &what); virtual unsigned code(void) const; + virtual index_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API key_error : lookup_error{ key_error(const std::string &what); virtual unsigned code(void) const; + virtual key_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API type_error : exception{ type_error(const std::string &what); virtual unsigned code(void) const; + virtual type_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API value_error : exception{ value_error(const std::string &what); virtual unsigned code(void) const; + virtual value_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API runtime_error : exception{ runtime_error(const std::string &what); virtual unsigned code(void) const; + virtual runtime_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API not_implemented_error : runtime_error{ not_implemented_error(const std::string &what); virtual unsigned code(void) const; + virtual not_implemented_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API environment_error : exception{ environment_error(const std::string &what); virtual unsigned code(void) const; + virtual environment_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API io_error : environment_error{ io_error(const std::string &what); virtual unsigned code(void) const; + virtual io_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API os_error : environment_error{ os_error(const std::string &what); virtual unsigned code(void) const; + virtual os_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; struct UHD_API system_error : exception{ system_error(const std::string &what); virtual unsigned code(void) const; + virtual system_error *dynamic_clone(void) const; + virtual void dynamic_throw(void) const; }; /*! diff --git a/host/lib/exception.cpp b/host/lib/exception.cpp index ecb1fe768..ea056bd3b 100644 --- a/host/lib/exception.cpp +++ b/host/lib/exception.cpp @@ -27,7 +27,9 @@ exception::exception(const std::string &what): #define make_exception_impl(name, class, base) \ class::class(const std::string &what): \ base(str(boost::format("%s: %s") % name % what)){} \ - unsigned class::code(void) const{return boost::hash<std::string>()(#class) & 0xfff;} + unsigned class::code(void) const{return boost::hash<std::string>()(#class) & 0xfff;} \ + class *class::dynamic_clone(void) const{return new class(*this);} \ + void class::dynamic_throw(void) const{throw *this;} make_exception_impl("AssertionError", assertion_error, exception) make_exception_impl("LookupError", lookup_error, exception) diff --git a/host/tests/error_test.cpp b/host/tests/error_test.cpp index 983f0150c..69437e732 100644 --- a/host/tests/error_test.cpp +++ b/host/tests/error_test.cpp @@ -44,7 +44,8 @@ BOOST_AUTO_TEST_CASE(test_assert_has){ std::cout << "The output of the assert_has error:" << std::endl; try{ uhd::assert_has(vec, 1, "prime"); - }catch(const std::exception &e){ + } + catch(const std::exception &e){ std::cout << e.what() << std::endl; } } @@ -53,7 +54,37 @@ BOOST_AUTO_TEST_CASE(test_assert_throw){ std::cout << "The output of the assert throw error:" << std::endl; try{ UHD_ASSERT_THROW(2 + 2 == 5); - }catch(const std::exception &e){ + } + catch(const std::exception &e){ + std::cout << e.what() << std::endl; + } +} + +BOOST_AUTO_TEST_CASE(test_exception_dynamic){ + uhd::exception *exception_clone; + + //throw an exception and dynamically clone it + try{ + throw uhd::runtime_error("noooooo"); + } + catch(const uhd::exception &e){ std::cout << e.what() << std::endl; + exception_clone = e.dynamic_clone(); + } + + //now we dynamically re-throw the exception + try{ + exception_clone->dynamic_throw(); + } + catch(const uhd::assertion_error &e){ + BOOST_CHECK(false); } + catch(const uhd::runtime_error &e){ + BOOST_CHECK(true); + } + catch(const uhd::exception &e){ + BOOST_CHECK(false); + } + + delete exception_clone; //manual cleanup } |