From 2f2d500a1109d087fd3c9d898470418466941865 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Mon, 4 Jun 2018 12:46:33 +0200 Subject: [PATCH 1/3] Allow compilation without exceptions --- include/cpptoml.h | 108 +++++++++++++++++++++++++++++++++++++--------- 1 file changed, 88 insertions(+), 20 deletions(-) diff --git a/include/cpptoml.h b/include/cpptoml.h index 87c3b26..d27607e 100644 --- a/include/cpptoml.h +++ b/include/cpptoml.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -51,6 +52,31 @@ using string_to_base_map = std::unordered_map>; #endif +#if defined(CPPTOML_NO_EXCEPTIONS) +// if defined, exception handling will be crudely disabled +#define THROW_(exception, reason) die(reason, __FILE__, __LINE__) +#define THROW2_(exception, reason, input_line) \ + die(reason, input_line, __FILE__, __LINE__) + +[[noreturn]] inline void die(const std::string& reason, const std::string& file, + const int line) { + std::cerr << file << ":" << std::to_string(line) << ": error: " << reason + << std::endl; + std::exit(1); +} + +[[noreturn]] inline void die(const std::string& reason, const int input_line, + const std::string& file, const int line) +{ + std::cerr << file << ":" << std::to_string(line) << ": error: " << reason + << " at line " << input_line << std::endl; + std::exit(1); +} +#else +#define THROW_(exception, reason) throw exception{reason} +#define THROW2_(exception, reason, input_line) throw exception{reason, input_line} +#endif + template class option { @@ -339,13 +365,13 @@ struct value_traits::min)()) - throw std::underflow_error{"constructed value cannot be " - "represented by a 64-bit signed " - "integer"}; + THROW_(std::underflow_error, "constructed value cannot be " + "represented by a 64-bit signed " + "integer"); if (val > (std::numeric_limits::max)()) - throw std::overflow_error{"constructed value cannot be represented " - "by a 64-bit signed integer"}; + THROW_(std::overflow_error, "constructed value cannot be represented " + "by a 64-bit signed integer"); return static_cast(val); } @@ -365,8 +391,8 @@ struct value_traits static_cast((std::numeric_limits::max)())) - throw std::overflow_error{"constructed value cannot be represented " - "by a 64-bit signed integer"}; + THROW_(std::overflow_error, "constructed value cannot be represented " + "by a 64-bit signed integer"); return static_cast(val); } @@ -744,7 +770,7 @@ class array : public base } else { - throw array_exception{"Arrays must be homogenous."}; + THROW_(array_exception, "Arrays must be homogenous."); } } @@ -759,7 +785,7 @@ class array : public base } else { - throw array_exception{"Arrays must be homogenous."}; + THROW_(array_exception, "Arrays must be homogenous."); } } @@ -785,7 +811,7 @@ class array : public base } else { - throw array_exception{"Arrays must be homogenous."}; + THROW_(array_exception, "Arrays must be homogenous."); } } @@ -800,7 +826,7 @@ class array : public base } else { - throw array_exception{"Arrays must be homogenous."}; + THROW_(array_exception, "Arrays must be homogenous."); } } @@ -1034,12 +1060,12 @@ get_impl(const std::shared_ptr& elem) if (auto v = elem->as()) { if (v->get() < (std::numeric_limits::min)()) - throw std::underflow_error{ - "T cannot represent the value requested in get"}; + THROW_(std::underflow_error, + "T cannot represent the value requested in get"); if (v->get() > (std::numeric_limits::max)()) - throw std::overflow_error{ - "T cannot represent the value requested in get"}; + THROW_(std::overflow_error, + "T cannot represent the value requested in get"); return {static_cast(v->get())}; } @@ -1058,11 +1084,12 @@ get_impl(const std::shared_ptr& elem) if (auto v = elem->as()) { if (v->get() < 0) - throw std::underflow_error{"T cannot store negative value in get"}; + THROW_(std::underflow_error, + "T cannot store negative value in get"); if (static_cast(v->get()) > (std::numeric_limits::max)()) - throw std::overflow_error{ - "T cannot represent the value requested in get"}; + THROW_(std::overflow_error, + "T cannot represent the value requested in get"); return {static_cast(v->get())}; } @@ -1250,6 +1277,7 @@ class table : public base template option get_as(const std::string& key) const { +#ifndef CPPTOML_NO_EXCEPTIONS try { return get_impl(get(key)); @@ -1258,6 +1286,16 @@ class table : public base { return {}; } +#else + if (contains(key)) + { + return get_impl(get(key)); + } + else + { + return {}; + } +#endif } /** @@ -1268,6 +1306,7 @@ class table : public base template option get_qualified_as(const std::string& key) const { +#ifndef CPPTOML_NO_EXCEPTIONS try { return get_impl(get_qualified(key)); @@ -1276,6 +1315,16 @@ class table : public base { return {}; } +#else + if (contains_qualified(key)) + { + return get_impl(get_qualified(key)); + } + else + { + return {}; + } +#endif } /** @@ -1410,10 +1459,14 @@ class table : public base table = table->get_table(part).get(); if (!table) { +#ifndef CPPTOML_NO_EXCEPTIONS if (!p) return false; throw std::out_of_range{key + " is not a valid key"}; +#else + return false; +#endif } } @@ -1714,7 +1767,7 @@ class parser #endif void throw_parse_exception(const std::string& err) { - throw parse_exception{err, line_number_}; + THROW2_(parse_exception, err, line_number_); } void parse_table(std::string::iterator& it, @@ -2433,10 +2486,13 @@ class parser std::string v{it, end}; v.erase(std::remove(v.begin(), v.end(), '_'), v.end()); it = end; +#ifndef CPPTOML_NO_EXCEPTIONS try +#endif { return make_value(std::stoll(v)); } +#ifndef CPPTOML_NO_EXCEPTIONS catch (const std::invalid_argument& ex) { throw_parse_exception("Malformed number (invalid argument: " @@ -2447,6 +2503,7 @@ class parser throw_parse_exception("Malformed number (out of range: " + std::string{ex.what()} + ")"); } +#endif } std::shared_ptr> parse_float(std::string::iterator& it, @@ -2457,10 +2514,13 @@ class parser it = end; char decimal_point = std::localeconv()->decimal_point[0]; std::replace(v.begin(), v.end(), '.', decimal_point); +#ifndef CPPTOML_NO_EXCEPTIONS try +#endif { return make_value(std::stod(v)); } +#ifndef CPPTOML_NO_EXCEPTIONS catch (const std::invalid_argument& ex) { throw_parse_exception("Malformed number (invalid argument: " @@ -2471,6 +2531,7 @@ class parser throw_parse_exception("Malformed number (out of range: " + std::string{ex.what()} + ")"); } +#endif } std::shared_ptr> parse_bool(std::string::iterator& it, @@ -2848,7 +2909,7 @@ inline std::shared_ptr parse_file(const std::string& filename) std::ifstream file{filename}; #endif if (!file.is_open()) - throw parse_exception{filename + " could not be opened for parsing"}; + THROW_(parse_exception, filename + " could not be opened for parsing"); parser p{file}; return p.parse(); } @@ -3278,4 +3339,11 @@ inline std::ostream& operator<<(std::ostream& stream, const array& a) return stream; } } + +#if defined(CPPTOML_NO_EXCEPTIONS) +// if defined, re-enable exception handling after this file +#undef THROW_ +#undef THROW2_ +#endif + #endif From 758a9bcac90c87f8bc8fe101b22e32ac51be5a95 Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Mon, 4 Jun 2018 12:52:05 +0200 Subject: [PATCH 2/3] Update comments --- include/cpptoml.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/include/cpptoml.h b/include/cpptoml.h index d27607e..7ed05be 100644 --- a/include/cpptoml.h +++ b/include/cpptoml.h @@ -53,7 +53,10 @@ using string_to_base_map #endif #if defined(CPPTOML_NO_EXCEPTIONS) -// if defined, exception handling will be crudely disabled +// If defined, exception handling will be disabled. In some cases, originally +// thrown exceptions will now result in an abort using std::exit. In other +// cases, caught exceptions are now passed on. Where exception handling is +// used for control flow, it is replaced by other (maybe more costly) means. #define THROW_(exception, reason) die(reason, __FILE__, __LINE__) #define THROW2_(exception, reason, input_line) \ die(reason, input_line, __FILE__, __LINE__) @@ -3341,7 +3344,7 @@ inline std::ostream& operator<<(std::ostream& stream, const array& a) } #if defined(CPPTOML_NO_EXCEPTIONS) -// if defined, re-enable exception handling after this file +// undefine local macros such that they do not leak outside this file #undef THROW_ #undef THROW2_ #endif From bd6d8f7725a8119426d03b5985d01467b8161c8d Mon Sep 17 00:00:00 2001 From: Michael Schlottke-Lakemper Date: Mon, 4 Jun 2018 13:01:57 +0200 Subject: [PATCH 3/3] Simplify no-exceptions support in resolve_qualified --- include/cpptoml.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/cpptoml.h b/include/cpptoml.h index 7ed05be..c602ccb 100644 --- a/include/cpptoml.h +++ b/include/cpptoml.h @@ -1462,14 +1462,10 @@ class table : public base table = table->get_table(part).get(); if (!table) { -#ifndef CPPTOML_NO_EXCEPTIONS if (!p) return false; - throw std::out_of_range{key + " is not a valid key"}; -#else - return false; -#endif + THROW_(std::out_of_range, key + " is not a valid key"); } }