Skip to content

Commit

Permalink
Make Node move constructor and assignment operator noexcept (#809)
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
TedLyngmo committed Feb 5, 2020
1 parent 9ab22ef commit 4267ca1
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 2 deletions.
47 changes: 46 additions & 1 deletion include/yaml-cpp/node/impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,28 @@
#include "yaml-cpp/node/detail/node.h"
#include "yaml-cpp/node/iterator.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/noexcept.h"
#include <sstream>
#include <string>
#include <utility>

namespace YAML {
inline Node::Node()
namespace detail {
#if __cplusplus >= 201402L
using ::std::exchange;
#else
template<class T, class U = T>
T exchange(T& obj, U&& new_value) {
T old_value = std::move(obj);
obj = std::forward<U>(new_value);
return old_value;
}
#endif
} // namespace detail
} // namespace YAML

namespace YAML {
inline Node::Node() YAML_CPP_NOEXCEPT
: m_isValid(true), m_invalidKey{}, m_pMemory(nullptr), m_pNode(nullptr) {}

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

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

inline Node::Node(Node&& rhs) YAML_CPP_NOEXCEPT
: m_isValid(detail::exchange(rhs.m_isValid, true)),
m_invalidKey(std::move(rhs.m_invalidKey)),
m_pMemory(std::move(rhs.m_pMemory)),
m_pNode(detail::exchange(rhs.m_pNode, nullptr)) {
}

inline Node::Node(Zombie)
: m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {}

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

// assignment
inline bool Node::CheckValid(const Node& rhs) const YAML_CPP_NOEXCEPT {
return
m_isValid && rhs.m_isValid &&
m_pNode != nullptr && rhs.m_pNode != nullptr &&
!m_pNode->is(*rhs.m_pNode);
}

inline bool Node::is(const Node& rhs) const {
if (!m_isValid || !rhs.m_isValid)
throw InvalidNode(m_invalidKey);
Expand All @@ -209,6 +240,16 @@ inline Node& Node::operator=(const Node& rhs) {
return *this;
}

inline Node& Node::operator=(Node&& rhs) YAML_CPP_NOEXCEPT {
if (!CheckValid(rhs))
return *this;

Node tmp(std::move(rhs));
AssignNodeDetail(tmp);

return *this;
}

inline void Node::reset(const YAML::Node& rhs) {
if (!m_isValid || !rhs.m_isValid)
throw InvalidNode(m_invalidKey);
Expand Down Expand Up @@ -258,6 +299,10 @@ inline void Node::AssignNode(const Node& rhs) {
return;
}

AssignNodeDetail(rhs);
}

inline void Node::AssignNodeDetail(const Node& rhs) YAML_CPP_NOEXCEPT {
m_pNode->set_ref(*rhs.m_pNode);
m_pMemory->merge(*rhs.m_pMemory);
m_pNode = rhs.m_pNode;
Expand Down
7 changes: 6 additions & 1 deletion include/yaml-cpp/node/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "yaml-cpp/node/detail/iterator_fwd.h"
#include "yaml-cpp/node/ptr.h"
#include "yaml-cpp/node/type.h"
#include "yaml-cpp/noexcept.h"

namespace YAML {
namespace detail {
Expand All @@ -41,12 +42,13 @@ class YAML_CPP_API Node {
using iterator = YAML::iterator;
using const_iterator = YAML::const_iterator;

Node();
Node() YAML_CPP_NOEXCEPT;
explicit Node(NodeType::value type);
template <typename T>
explicit Node(const T& rhs);
explicit Node(const detail::iterator_value& rhs);
Node(const Node& rhs);
Node(Node&& rhs) YAML_CPP_NOEXCEPT;
~Node();

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

// assignment
bool CheckValid(const Node& rhs) const YAML_CPP_NOEXCEPT;
bool is(const Node& rhs) const;
template <typename T>
Node& operator=(const T& rhs);
Node& operator=(const Node& rhs);
Node& operator=(Node&& rhs) YAML_CPP_NOEXCEPT;
void reset(const Node& rhs = Node());

// size/iterator
Expand Down Expand Up @@ -128,6 +132,7 @@ class YAML_CPP_API Node {

void AssignData(const Node& rhs);
void AssignNode(const Node& rhs);
void AssignNodeDetail(const Node& rhs) YAML_CPP_NOEXCEPT;

private:
bool m_isValid;
Expand Down

0 comments on commit 4267ca1

Please sign in to comment.