From 8bfb33f6057a399d7b71d0517d59f20e9c34c15a Mon Sep 17 00:00:00 2001 From: beda Date: Fri, 28 Dec 2018 17:20:36 +0100 Subject: [PATCH] Better error messages --- include/yaml-cpp/exceptions.h | 40 +++++++++++++-- include/yaml-cpp/node/detail/impl.h | 4 +- include/yaml-cpp/node/impl.h | 79 ++++++++++++++++++----------- include/yaml-cpp/node/node.h | 2 + include/yaml-cpp/traits.h | 16 ++++++ src/node_data.cpp | 4 +- 6 files changed, 106 insertions(+), 39 deletions(-) diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index 87b92f5..e49a32a 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -114,6 +114,35 @@ inline const std::string KEY_NOT_FOUND_WITH_KEY( stream << KEY_NOT_FOUND << ": " << key; return stream.str(); } + +template +inline const std::string BAD_SUBSCRIPT_WITH_KEY( + const T&, typename disable_if>::type* = 0) { + return BAD_SUBSCRIPT; +} + +inline const std::string BAD_SUBSCRIPT_WITH_KEY(const std::string& key) { + std::stringstream stream; + stream << BAD_SUBSCRIPT << " (key: '" << key << "')"; + return stream.str(); +} + +template +inline const std::string BAD_SUBSCRIPT_WITH_KEY( + const T& key, typename enable_if>::type* = 0) { + std::stringstream stream; + stream << BAD_SUBSCRIPT << " (key: '" << key << "')"; + return stream.str(); +} + +inline const std::string INVALID_NODE_WITH_KEY(const std::string& key) { + std::stringstream stream; + if (key.empty()) { + return INVALID_NODE; + } + stream << "invalid node - first invalid key: '" << key << "'"; + return stream.str(); +} } class YAML_CPP_API Exception : public std::runtime_error { @@ -194,8 +223,9 @@ inline TypedKeyNotFound MakeTypedKeyNotFound(const Mark& mark, class YAML_CPP_API InvalidNode : public RepresentationException { public: - InvalidNode() - : RepresentationException(Mark::null_mark(), ErrorMsg::INVALID_NODE) {} + InvalidNode(std::string key) + : RepresentationException(Mark::null_mark(), + ErrorMsg::INVALID_NODE_WITH_KEY(key)) {} InvalidNode(const InvalidNode&) = default; virtual ~InvalidNode() YAML_CPP_NOEXCEPT; }; @@ -224,8 +254,10 @@ class YAML_CPP_API BadDereference : public RepresentationException { class YAML_CPP_API BadSubscript : public RepresentationException { public: - BadSubscript() - : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_SUBSCRIPT) {} + template + BadSubscript(const Key& key) + : RepresentationException(Mark::null_mark(), + ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {} BadSubscript(const BadSubscript&) = default; virtual ~BadSubscript() YAML_CPP_NOEXCEPT; }; diff --git a/include/yaml-cpp/node/detail/impl.h b/include/yaml-cpp/node/detail/impl.h index c8853cf..46615a9 100644 --- a/include/yaml-cpp/node/detail/impl.h +++ b/include/yaml-cpp/node/detail/impl.h @@ -115,7 +115,7 @@ inline node* node_data::get(const Key& key, return pNode; return NULL; case NodeType::Scalar: - throw BadSubscript(); + throw BadSubscript(key); } for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { @@ -143,7 +143,7 @@ inline node& node_data::get(const Key& key, shared_memory_holder pMemory) { convert_to_map(pMemory); break; case NodeType::Scalar: - throw BadSubscript(); + throw BadSubscript(key); } for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { diff --git a/include/yaml-cpp/node/impl.h b/include/yaml-cpp/node/impl.h index de2bf44..2a80494 100644 --- a/include/yaml-cpp/node/impl.h +++ b/include/yaml-cpp/node/impl.h @@ -12,6 +12,7 @@ #include "yaml-cpp/node/detail/memory.h" #include "yaml-cpp/node/detail/node.h" #include "yaml-cpp/exceptions.h" +#include #include namespace YAML { @@ -34,16 +35,21 @@ inline Node::Node(const T& rhs) inline Node::Node(const detail::iterator_value& rhs) : m_isValid(rhs.m_isValid), + m_invalidKey(rhs.m_invalidKey), m_pMemory(rhs.m_pMemory), m_pNode(rhs.m_pNode) {} inline Node::Node(const Node& rhs) : m_isValid(rhs.m_isValid), + m_invalidKey(rhs.m_invalidKey), m_pMemory(rhs.m_pMemory), m_pNode(rhs.m_pNode) {} inline Node::Node(Zombie) : m_isValid(false), m_pNode(NULL) {} +inline Node::Node(Zombie, std::string key) + : m_isValid(false), m_invalidKey(key), m_pNode(NULL) {} + inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory) : m_isValid(true), m_pMemory(pMemory), m_pNode(&node) {} @@ -51,7 +57,7 @@ inline Node::~Node() {} inline void Node::EnsureNodeExists() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); if (!m_pNode) { m_pMemory.reset(new detail::memory_holder); m_pNode = &m_pMemory->create_node(); @@ -68,14 +74,14 @@ inline bool Node::IsDefined() const { inline Mark Node::Mark() const { if (!m_isValid) { - throw InvalidNode(); + throw InvalidNode(m_invalidKey); } return m_pNode ? m_pNode->mark() : Mark::null_mark(); } inline NodeType::value Node::Type() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->type() : NodeType::Null; } @@ -142,7 +148,7 @@ struct as_if { template inline T Node::as() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return as_if(*this)(); } @@ -155,32 +161,32 @@ inline T Node::as(const S& fallback) const { inline const std::string& Node::Scalar() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->scalar() : detail::node_data::empty_scalar(); } inline const std::string& Node::Tag() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->tag() : detail::node_data::empty_scalar(); } inline void Node::SetTag(const std::string& tag) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); m_pNode->set_tag(tag); } inline EmitterStyle::value Node::Style() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->style() : EmitterStyle::Default; } inline void Node::SetStyle(EmitterStyle::value style) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); m_pNode->set_style(style); } @@ -188,7 +194,7 @@ inline void Node::SetStyle(EmitterStyle::value style) { // assignment inline bool Node::is(const Node& rhs) const { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); if (!m_pNode || !rhs.m_pNode) return false; return m_pNode->is(*rhs.m_pNode); @@ -197,14 +203,14 @@ inline bool Node::is(const Node& rhs) const { template inline Node& Node::operator=(const T& rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); Assign(rhs); return *this; } inline void Node::reset(const YAML::Node& rhs) { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); m_pMemory = rhs.m_pMemory; m_pNode = rhs.m_pNode; } @@ -212,35 +218,35 @@ inline void Node::reset(const YAML::Node& rhs) { template inline void Node::Assign(const T& rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); AssignData(convert::encode(rhs)); } template <> inline void Node::Assign(const std::string& rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); m_pNode->set_scalar(rhs); } inline void Node::Assign(const char* rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); m_pNode->set_scalar(rhs); } inline void Node::Assign(char* rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); m_pNode->set_scalar(rhs); } inline Node& Node::operator=(const Node& rhs) { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); if (is(rhs)) return *this; AssignNode(rhs); @@ -249,7 +255,7 @@ inline Node& Node::operator=(const Node& rhs) { inline void Node::AssignData(const Node& rhs) { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); rhs.EnsureNodeExists(); @@ -259,7 +265,7 @@ inline void Node::AssignData(const Node& rhs) { inline void Node::AssignNode(const Node& rhs) { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); rhs.EnsureNodeExists(); if (!m_pNode) { @@ -276,7 +282,7 @@ inline void Node::AssignNode(const Node& rhs) { // size/iterator inline std::size_t Node::size() const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); return m_pNode ? m_pNode->size() : 0; } @@ -309,13 +315,13 @@ inline iterator Node::end() { template inline void Node::push_back(const T& rhs) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); push_back(Node(rhs)); } inline void Node::push_back(const Node& rhs) { if (!m_isValid || !rhs.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); rhs.EnsureNodeExists(); @@ -368,16 +374,27 @@ inline typename to_value_t::return_type to_value(const T& t) { } } +template +std::string key_to_string(const Key& key) { + std::stringstream ss; + if (is_streamable::value) { + ss << key; + return ss.str(); + } else { + return std::string(); + } +} + // indexing template inline const Node Node::operator[](const Key& key) const { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); detail::node* value = static_cast(*m_pNode) .get(detail::to_value(key), m_pMemory); if (!value) { - return Node(ZombieNode); + return Node(ZombieNode, key_to_string(key)); } return Node(*value, m_pMemory); } @@ -385,7 +402,7 @@ inline const Node Node::operator[](const Key& key) const { template inline Node Node::operator[](const Key& key) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); detail::node& value = m_pNode->get(detail::to_value(key), m_pMemory); return Node(value, m_pMemory); @@ -394,28 +411,28 @@ inline Node Node::operator[](const Key& key) { template inline bool Node::remove(const Key& key) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); return m_pNode->remove(detail::to_value(key), m_pMemory); } inline const Node Node::operator[](const Node& key) const { if (!m_isValid || !key.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); key.EnsureNodeExists(); m_pMemory->merge(*key.m_pMemory); detail::node* value = static_cast(*m_pNode).get(*key.m_pNode, m_pMemory); if (!value) { - return Node(ZombieNode); + return Node(ZombieNode, key_to_string(key)); } return Node(*value, m_pMemory); } inline Node Node::operator[](const Node& key) { if (!m_isValid || !key.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); key.EnsureNodeExists(); m_pMemory->merge(*key.m_pMemory); @@ -425,7 +442,7 @@ inline Node Node::operator[](const Node& key) { inline bool Node::remove(const Node& key) { if (!m_isValid || !key.m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); key.EnsureNodeExists(); return m_pNode->remove(*key.m_pNode, m_pMemory); @@ -435,7 +452,7 @@ inline bool Node::remove(const Node& key) { template inline void Node::force_insert(const Key& key, const Value& value) { if (!m_isValid) - throw InvalidNode(); + throw InvalidNode(m_invalidKey); EnsureNodeExists(); m_pNode->force_insert(detail::to_value(key), detail::to_value(value), m_pMemory); diff --git a/include/yaml-cpp/node/node.h b/include/yaml-cpp/node/node.h index 1ded7d2..40e0743 100644 --- a/include/yaml-cpp/node/node.h +++ b/include/yaml-cpp/node/node.h @@ -116,6 +116,7 @@ class YAML_CPP_API Node { private: enum Zombie { ZombieNode }; explicit Node(Zombie); + explicit Node(Zombie, std::string); explicit Node(detail::node& node, detail::shared_memory_holder pMemory); void EnsureNodeExists() const; @@ -130,6 +131,7 @@ class YAML_CPP_API Node { private: bool m_isValid; + std::string m_invalidKey; mutable detail::shared_memory_holder m_pMemory; mutable detail::node* m_pNode; }; diff --git a/include/yaml-cpp/traits.h b/include/yaml-cpp/traits.h index f33d0e1..e7079d7 100644 --- a/include/yaml-cpp/traits.h +++ b/include/yaml-cpp/traits.h @@ -7,6 +7,9 @@ #pragma once #endif +#include +#include + namespace YAML { template struct is_numeric { @@ -100,4 +103,17 @@ template struct disable_if : public disable_if_c {}; } +template +class is_streamable { + template + static auto test(int) + -> decltype(std::declval() << std::declval(), std::true_type()); + + template + static auto test(...) -> std::false_type; + + public: + static const bool value = decltype(test(0))::value; +}; + #endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/src/node_data.cpp b/src/node_data.cpp index 04104b7..56e24ad 100644 --- a/src/node_data.cpp +++ b/src/node_data.cpp @@ -191,7 +191,7 @@ void node_data::insert(node& key, node& value, shared_memory_holder pMemory) { convert_to_map(pMemory); break; case NodeType::Scalar: - throw BadSubscript(); + throw BadSubscript(key); } insert_map_pair(key, value); @@ -221,7 +221,7 @@ node& node_data::get(node& key, shared_memory_holder pMemory) { convert_to_map(pMemory); break; case NodeType::Scalar: - throw BadSubscript(); + throw BadSubscript(key); } for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {