diff --git a/include/yaml-cpp/exceptions.h b/include/yaml-cpp/exceptions.h index f5dd1cf78..4a91249ab 100644 --- a/include/yaml-cpp/exceptions.h +++ b/include/yaml-cpp/exceptions.h @@ -90,6 +90,7 @@ const char* const INVALID_ALIAS = "invalid alias"; const char* const INVALID_TAG = "invalid tag"; const char* const BAD_FILE = "bad file"; const char* const UNEXPECTED_TOKEN_AFTER_DOC = "unexpected token after end of document"; +const char* const NON_UNIQUE_MAP_KEY = "map keys must be unique"; template inline const std::string KEY_NOT_FOUND_WITH_KEY( @@ -301,6 +302,16 @@ class YAML_CPP_API BadFile : public Exception { BadFile(const BadFile&) = default; ~BadFile() YAML_CPP_NOEXCEPT override; }; + +class YAML_CPP_API NonUniqueMapKey : public RepresentationException { + public: + template + NonUniqueMapKey(const Mark& mark_, const Key& key) + : RepresentationException(mark_, ErrorMsg::NON_UNIQUE_MAP_KEY) {} + NonUniqueMapKey(const NonUniqueMapKey&) = default; + ~NonUniqueMapKey() YAML_CPP_NOEXCEPT override; +}; + } // namespace YAML #if defined(_MSC_VER) diff --git a/include/yaml-cpp/node/detail/impl.h b/include/yaml-cpp/node/detail/impl.h index b38038dfd..9138fe6b0 100644 --- a/include/yaml-cpp/node/detail/impl.h +++ b/include/yaml-cpp/node/detail/impl.h @@ -218,7 +218,7 @@ inline void node_data::force_insert(const Key& key, const Value& value, node& k = convert_to_node(key, pMemory); node& v = convert_to_node(value, pMemory); - insert_map_pair(k, v); + insert_map_pair(k, v, true); } template diff --git a/include/yaml-cpp/node/detail/node_data.h b/include/yaml-cpp/node/detail/node_data.h index 07cf81aa0..ed7d9cdbf 100644 --- a/include/yaml-cpp/node/detail/node_data.h +++ b/include/yaml-cpp/node/detail/node_data.h @@ -90,7 +90,7 @@ class YAML_CPP_API node_data { void reset_sequence(); void reset_map(); - void insert_map_pair(node& key, node& value); + void insert_map_pair(node& key, node& value, bool force = false); void convert_to_map(const shared_memory_holder& pMemory); void convert_sequence_to_map(const shared_memory_holder& pMemory); diff --git a/src/exceptions.cpp b/src/exceptions.cpp index 43a7976e9..af99fd6b7 100644 --- a/src/exceptions.cpp +++ b/src/exceptions.cpp @@ -17,4 +17,5 @@ BadPushback::~BadPushback() YAML_CPP_NOEXCEPT = default; BadInsert::~BadInsert() YAML_CPP_NOEXCEPT = default; EmitterException::~EmitterException() YAML_CPP_NOEXCEPT = default; BadFile::~BadFile() YAML_CPP_NOEXCEPT = default; +NonUniqueMapKey::~NonUniqueMapKey() YAML_CPP_NOEXCEPT = default; } // namespace YAML diff --git a/src/node_data.cpp b/src/node_data.cpp index 6653bc17a..dbfb94191 100644 --- a/src/node_data.cpp +++ b/src/node_data.cpp @@ -279,7 +279,12 @@ void node_data::reset_map() { m_undefinedPairs.clear(); } -void node_data::insert_map_pair(node& key, node& value) { +void node_data::insert_map_pair(node& key, node& value, bool force) { + if (!force && !key.scalar().empty()) + for (const auto& mapEntry : m_map) + if (mapEntry.first->scalar() == key.scalar()) + throw NonUniqueMapKey(m_mark, key); + m_map.emplace_back(&key, &value); if (!key.is_defined() || !value.is_defined()) diff --git a/test/integration/load_node_test.cpp b/test/integration/load_node_test.cpp index 19376a430..d7698434c 100644 --- a/test/integration/load_node_test.cpp +++ b/test/integration/load_node_test.cpp @@ -465,6 +465,9 @@ TEST(LoadNodeTest, IncorrectSeqEnd) { EXPECT_THROW(Load("[foo]_bar"), ParserException); } +TEST(LoadNodeTest, NonUniqueMapKey) { + EXPECT_THROW(Load("{a: A, b: B, a: A}"), NonUniqueMapKey); +} } // namespace } // namespace YAML