diff --git a/include/yaml-cpp/node/api_switch.h b/include/yaml-cpp/node/api_switch.h new file mode 100644 index 0000000..716ab98 --- /dev/null +++ b/include/yaml-cpp/node/api_switch.h @@ -0,0 +1,53 @@ +// +// Created by marcel on 3/3/22. +// + +#ifndef YAML_CPP_API_SWITCH_H +#define YAML_CPP_API_SWITCH_H + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/exceptions.h" +#include + +namespace YAML{ +namespace detail { + + //detect the method of the new api + template + std::false_type has_decode_new_api(long); + + template + auto has_decode_new_api(int) + -> decltype( T::decode(std::declval()), std::true_type{}); + + template + struct static_api_switch; + + template<> //new api call-path + struct static_api_switch { + template + static T decode(const Node& node) { + return convert::decode(node); + } + }; + + template<> //old api call-path + struct static_api_switch { + template + static T decode(const Node& node) { + T t; + if (convert::decode(node, t)) + return t; + throw conversion::DecodeException(); + } + }; +} +} + +#endif // YAML_CPP_API_SWITCH_H diff --git a/include/yaml-cpp/node/convert.h b/include/yaml-cpp/node/convert.h index 22a2226..ed77cf5 100644 --- a/include/yaml-cpp/node/convert.h +++ b/include/yaml-cpp/node/convert.h @@ -34,9 +34,6 @@ template struct convert; } // namespace YAML -#define BAD_DECODE_EXCEPTION throw YAML::conversion::DecodeException(); - - namespace YAML { namespace conversion { inline bool IsInfinity(const std::string& input) { @@ -58,12 +55,17 @@ template <> struct convert { static Node encode(const Node& rhs) { return rhs; } - static Node decode(const Node& node) { //FIXME, this is dangerous - throw std::runtime_error("this should not have been encountered"); - Node rhs; + static bool decode(const Node& node, Node& rhs) { rhs.reset(node); - return rhs; + return true; } + +// static Node decode(const Node& node) { +// throw std::runtime_error("this should not have been encountered"); +// Node rhs; +// rhs.reset(node); +// return rhs; +// } }; // std::string @@ -73,10 +75,9 @@ struct convert { static std::string decode(const Node& node) { if (!node.IsScalar()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); return node.Scalar(); } - }; // C-strings can only be encoded @@ -101,7 +102,7 @@ struct convert<_Null> { static _Null decode(const Node& node) { if (!node.IsNull()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); return _Null(); } }; @@ -166,19 +167,19 @@ ConvertStreamTo(std::stringstream& stream, T& rhs) { return Node(stream.str()); \ } \ \ - static type decode(const Node& node) { \ + static type decode(const Node& node) { \ if (node.Type() != NodeType::Scalar) { \ - BAD_DECODE_EXCEPTION; \ + throw YAML::conversion::DecodeException();; \ } \ const std::string& input = node.Scalar(); \ std::stringstream stream(input); \ stream.unsetf(std::ios::dec); \ if ((stream.peek() == '-') && std::is_unsigned::value) { \ - BAD_DECODE_EXCEPTION \ + throw YAML::conversion::DecodeException(); \ } \ type rhs; \ if (conversion::ConvertStreamTo(stream, rhs)) { \ - return rhs; \ + return rhs; \ } \ if (std::numeric_limits::has_infinity) { \ if (conversion::IsInfinity(input)) { \ @@ -194,7 +195,7 @@ ConvertStreamTo(std::stringstream& stream, T& rhs) { } \ } \ \ - BAD_DECODE_EXCEPTION \ + throw YAML::conversion::DecodeException(); \ } \ } @@ -245,7 +246,7 @@ struct convert> { static std::map decode(const Node& node) { if (!node.IsMap()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); std::map rhs; for (const auto& element : node) @@ -271,7 +272,7 @@ struct convert> { static std::unordered_map decode(const Node& node) { if (!node.IsMap()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); std::unordered_map rhs; for (const auto& element : node) @@ -297,7 +298,7 @@ struct convert> { static std::vector decode(const Node& node) { if (!node.IsSequence()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); std::vector rhs; for (const auto& element : node) @@ -323,7 +324,7 @@ struct convert> { static std::list decode(const Node& node) { if (!node.IsSequence()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); std::list rhs; for (const auto& element : node) @@ -350,7 +351,7 @@ struct convert> { static std::array decode(const Node& node) { if (!isNodeValid(node)) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); std::array rhs; for (auto i = 0u; i < node.size(); ++i) { @@ -382,7 +383,7 @@ struct convert> { static std::pair decode(const Node& node) { if (!node.IsSequence() || node.size() != 2) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); std::pair rhs; #if defined(__GNUC__) && __GNUC__ < 4 @@ -410,11 +411,11 @@ struct convert { static Binary decode(const Node& node) { if (!node.IsScalar()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); std::vector data = DecodeBase64(node.Scalar()); if (data.empty() && !node.Scalar().empty()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); Binary rhs; rhs.swap(data); diff --git a/include/yaml-cpp/node/detail/impl.h b/include/yaml-cpp/node/detail/impl.h index ab5d8c3..f574383 100644 --- a/include/yaml-cpp/node/detail/impl.h +++ b/include/yaml-cpp/node/detail/impl.h @@ -9,6 +9,7 @@ #include "yaml-cpp/node/detail/node.h" #include "yaml-cpp/node/detail/node_data.h" +#include "yaml-cpp/node/api_switch.h" #include #include @@ -96,63 +97,11 @@ struct remove_idx -struct static_switch; - -template<> //new api -struct static_switch { - template - static T call(const Node& node) { - return convert::decode(node); - } -}; - -template<> //old api -struct static_switch { - template - static T call(const Node& node) { - T t; - if (convert::decode(node, t)) - return t; - throw conversion::DecodeException(); - } -}; -#endif - -//detect the method of the new api -template -std::false_type has_decode_new_api(long); - -template -auto has_decode_new_api(int) - -> decltype( T::decode(std::declval()), std::true_type{}); - - - template inline bool node::equals(const T& rhs, shared_memory_holder pMemory) { - try { -#ifdef PRE_CPP17_SHIM - return static_switch>( - 0))::value>::template call(Node(*this, pMemory)) == rhs; -#else - if constexpr (decltype(has_decode_new_api>(0))::value >) - return convert::decode(Node(*this, pMemory)) == rhs; - else { - T lhs; - if (convert::decode(Node(*this, pMemory), lhs)) - return lhs == rhs; - throw conversion::DecodeException(); - } -#endif + return static_api_switch>( + 0))::value>::template decode(Node(*this, pMemory)) == rhs; } catch(const conversion::DecodeException& e) { //throw; //prefer to throw over returning just the inability to deserialize return false; //not doing this breaks upstream functionality @@ -160,20 +109,19 @@ inline bool node::equals(const T& rhs, shared_memory_holder pMemory) { throw; } } -#undef PRE_CPP17_SHIM - inline bool node::equals(const char* rhs, shared_memory_holder pMemory) { - std::string lhs; - if (convert::decode(Node(*this, std::move(pMemory)), lhs)) { - return lhs == rhs; + try { + return static_api_switch>( + 0))::value>::template decode(Node(*this, std::move(pMemory))) == rhs; + } catch(const conversion::DecodeException& e) { + //throw; //prefer to throw over returning just the inability to deserialize + return false; //not doing this breaks upstream functionality + } catch (...) { + throw; } - return false; } - - - // indexing template inline node* node_data::get(const Key& key, diff --git a/include/yaml-cpp/node/impl.h b/include/yaml-cpp/node/impl.h index 46917da..c565d6d 100644 --- a/include/yaml-cpp/node/impl.h +++ b/include/yaml-cpp/node/impl.h @@ -12,6 +12,7 @@ #include "yaml-cpp/node/detail/node.h" #include "yaml-cpp/node/iterator.h" #include "yaml-cpp/node/node.h" +#include "yaml-cpp/node/api_switch.h" #include #include #include @@ -88,44 +89,6 @@ inline NodeType::value Node::Type() const { // access -//detect the method of the new api -template -std::false_type has_decode_new_api(long); - -template -auto has_decode_new_api(int) - -> decltype( T::decode(std::declval()), std::true_type{}); - -//shim to emulate constexpr-if, which is a feature of c++17 -#if __cplusplus < 201703L || (defined(_MSVC_LANG) && _MSVC_LANG < 201703L) -#define PRE_CPP17_SHIM -#endif - -#ifdef PRE_CPP17_SHIM -template -struct static_switch; - -template<> //new api -struct static_switch { - template - static T call(const Node& node) { - return convert::decode(node); - } -}; - -template<> //old api -struct static_switch { - template - static T call(const Node& node) { - T t; - if (convert::decode(node, t)) - return t; - throw conversion::DecodeException(); - } -}; -#endif - - // template helpers template struct as_if { @@ -137,19 +100,8 @@ struct as_if { return fallback; try { -#ifdef PRE_CPP17_SHIM - return static_switch>( - 0))::value>::template call(node); -#else - if constexpr (decltype(has_decodex>(0))::value >) - return convert::decodex(node); - else { - T t; - if (convert::decode(node, t)) - return t; - throw conversion::DecodeException(); - } -#endif + return detail::static_api_switch>( + 0))::value>::template decode(node); } catch (const conversion::DecodeException& e) { return fallback; } catch (...) { @@ -204,19 +156,8 @@ struct as_if { throw TypedBadConversion(node.Mark()); try { -#ifdef PRE_CPP17_SHIM - return static_switch>( - 0))::value>::template call(node); -#else - if constexpr (decltype(has_decodex>(0))::value >) - return convert::decodex(node); - else { - T t; - if (convert::decode(node, t)) - return t; - throw conversion::DecodeException(); - } -#endif + return detail::static_api_switch>( + 0))::value>::template decode(node); } catch(const conversion::DecodeException& e) { throw TypedBadConversion(node.Mark()); } catch (...) { @@ -224,7 +165,6 @@ struct as_if { } }; }; -#undef PRE_CPP17_SHIM template <> struct as_if { diff --git a/src/convert.cpp b/src/convert.cpp index 7dda819..957aeda 100644 --- a/src/convert.cpp +++ b/src/convert.cpp @@ -40,7 +40,7 @@ bool IsFlexibleCase(const std::string& str) { namespace YAML { bool convert::decode(const Node& node) { if (!node.IsScalar()) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); // we can't use iostream bool extraction operators as they don't // recognize all possible values in the table below (taken from @@ -55,7 +55,7 @@ bool convert::decode(const Node& node) { }; if (!IsFlexibleCase(node.Scalar())) - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); for (const auto& name : names) { if (name.truename == tolower(node.Scalar())) { @@ -67,6 +67,6 @@ bool convert::decode(const Node& node) { } } - BAD_DECODE_EXCEPTION + throw YAML::conversion::DecodeException(); } } // namespace YAML