Skip to content

Commit 4267ca1

Browse files
committed
Make Node move constructor and assignment operator noexcept (#809)
Move constructor: * m_isValid (bool) exchange(rhs.m_isValid, true) * m_invalidKey (std::string) std::move() * m_pMemory (shared_memory_holder) std::move() * m_pNode (node*) exchange(rhs.m_pNode, nullptr) This leaves the moved-from Node as if it was just default constructed. Move assignment: A temporary Node is move constructed (using the above) leaving the moved-from Node as if it was just default constructed. *this then assigns the temporary, using AssignNodeDetail() directly to avoid a second self-assignment check. Signed-off-by: Ted Lyngmo <ted@lyncon.se>
1 parent 9ab22ef commit 4267ca1

File tree

2 files changed

+52
-2
lines changed

2 files changed

+52
-2
lines changed

include/yaml-cpp/node/impl.h

+46-1
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,28 @@
1212
#include "yaml-cpp/node/detail/node.h"
1313
#include "yaml-cpp/node/iterator.h"
1414
#include "yaml-cpp/node/node.h"
15+
#include "yaml-cpp/noexcept.h"
1516
#include <sstream>
1617
#include <string>
18+
#include <utility>
1719

1820
namespace YAML {
19-
inline Node::Node()
21+
namespace detail {
22+
#if __cplusplus >= 201402L
23+
using ::std::exchange;
24+
#else
25+
template<class T, class U = T>
26+
T exchange(T& obj, U&& new_value) {
27+
T old_value = std::move(obj);
28+
obj = std::forward<U>(new_value);
29+
return old_value;
30+
}
31+
#endif
32+
} // namespace detail
33+
} // namespace YAML
34+
35+
namespace YAML {
36+
inline Node::Node() YAML_CPP_NOEXCEPT
2037
: m_isValid(true), m_invalidKey{}, m_pMemory(nullptr), m_pNode(nullptr) {}
2138

2239
inline Node::Node(NodeType::value type)
@@ -44,6 +61,13 @@ inline Node::Node(const detail::iterator_value& rhs)
4461

4562
inline Node::Node(const Node& rhs) = default;
4663

64+
inline Node::Node(Node&& rhs) YAML_CPP_NOEXCEPT
65+
: m_isValid(detail::exchange(rhs.m_isValid, true)),
66+
m_invalidKey(std::move(rhs.m_invalidKey)),
67+
m_pMemory(std::move(rhs.m_pMemory)),
68+
m_pNode(detail::exchange(rhs.m_pNode, nullptr)) {
69+
}
70+
4771
inline Node::Node(Zombie)
4872
: m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {}
4973

@@ -188,6 +212,13 @@ inline void Node::SetStyle(EmitterStyle::value style) {
188212
}
189213

190214
// assignment
215+
inline bool Node::CheckValid(const Node& rhs) const YAML_CPP_NOEXCEPT {
216+
return
217+
m_isValid && rhs.m_isValid &&
218+
m_pNode != nullptr && rhs.m_pNode != nullptr &&
219+
!m_pNode->is(*rhs.m_pNode);
220+
}
221+
191222
inline bool Node::is(const Node& rhs) const {
192223
if (!m_isValid || !rhs.m_isValid)
193224
throw InvalidNode(m_invalidKey);
@@ -209,6 +240,16 @@ inline Node& Node::operator=(const Node& rhs) {
209240
return *this;
210241
}
211242

243+
inline Node& Node::operator=(Node&& rhs) YAML_CPP_NOEXCEPT {
244+
if (!CheckValid(rhs))
245+
return *this;
246+
247+
Node tmp(std::move(rhs));
248+
AssignNodeDetail(tmp);
249+
250+
return *this;
251+
}
252+
212253
inline void Node::reset(const YAML::Node& rhs) {
213254
if (!m_isValid || !rhs.m_isValid)
214255
throw InvalidNode(m_invalidKey);
@@ -258,6 +299,10 @@ inline void Node::AssignNode(const Node& rhs) {
258299
return;
259300
}
260301

302+
AssignNodeDetail(rhs);
303+
}
304+
305+
inline void Node::AssignNodeDetail(const Node& rhs) YAML_CPP_NOEXCEPT {
261306
m_pNode->set_ref(*rhs.m_pNode);
262307
m_pMemory->merge(*rhs.m_pMemory);
263308
m_pNode = rhs.m_pNode;

include/yaml-cpp/node/node.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "yaml-cpp/node/detail/iterator_fwd.h"
1717
#include "yaml-cpp/node/ptr.h"
1818
#include "yaml-cpp/node/type.h"
19+
#include "yaml-cpp/noexcept.h"
1920

2021
namespace YAML {
2122
namespace detail {
@@ -41,12 +42,13 @@ class YAML_CPP_API Node {
4142
using iterator = YAML::iterator;
4243
using const_iterator = YAML::const_iterator;
4344

44-
Node();
45+
Node() YAML_CPP_NOEXCEPT;
4546
explicit Node(NodeType::value type);
4647
template <typename T>
4748
explicit Node(const T& rhs);
4849
explicit Node(const detail::iterator_value& rhs);
4950
Node(const Node& rhs);
51+
Node(Node&& rhs) YAML_CPP_NOEXCEPT;
5052
~Node();
5153

5254
YAML::Mark Mark() const;
@@ -77,10 +79,12 @@ class YAML_CPP_API Node {
7779
void SetStyle(EmitterStyle::value style);
7880

7981
// assignment
82+
bool CheckValid(const Node& rhs) const YAML_CPP_NOEXCEPT;
8083
bool is(const Node& rhs) const;
8184
template <typename T>
8285
Node& operator=(const T& rhs);
8386
Node& operator=(const Node& rhs);
87+
Node& operator=(Node&& rhs) YAML_CPP_NOEXCEPT;
8488
void reset(const Node& rhs = Node());
8589

8690
// size/iterator
@@ -128,6 +132,7 @@ class YAML_CPP_API Node {
128132

129133
void AssignData(const Node& rhs);
130134
void AssignNode(const Node& rhs);
135+
void AssignNodeDetail(const Node& rhs) YAML_CPP_NOEXCEPT;
131136

132137
private:
133138
bool m_isValid;

0 commit comments

Comments
 (0)