Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

node: id hash_value UnshareSubtrees Deep+ShallowClone ModifyValues #1128

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions include/yaml-cpp/node/detail/impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,14 @@ inline void node_data::force_insert(const Key& key, const Value& value,
insert_map_pair(k, v);
}

inline void node_data::seq_push_back(node& rhs) {
m_sequence.push_back(&rhs);
}

inline void node_data::map_force_insert(node& key, node& value) {
insert_map_pair(key, value);
}

template <typename T>
inline node& node_data::convert_to_node(const T& rhs,
shared_memory_holder pMemory) {
Expand Down
34 changes: 33 additions & 1 deletion include/yaml-cpp/node/detail/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ class node {
node(const node&) = delete;
node& operator=(const node&) = delete;

bool is(const node& rhs) const { return m_pRef == rhs.m_pRef; }
// if set_data points us at the same data as another node then we want the
// same id. maybe set_data has single-owner semantics and this is unnecessary,
// but this is not clear (yet)
// alt: return m_pRef->id(); // (void*)this;
void *id() const YAML_CPP_NOEXCEPT { return m_pRef.get(); }
bool is(const node& rhs) const { return id() == rhs.id(); }
const node_ref* ref() const { return m_pRef.get(); }

bool is_defined() const { return m_pRef->is_defined(); }
Expand Down Expand Up @@ -71,6 +76,14 @@ class node {
m_pRef->set_data(*rhs.m_pRef);
}

void copy_contents(const node& rhs) {
if (&rhs == this) return;
m_pRef = std::make_shared<node_ref>();
if (rhs.is_defined())
mark_defined();
m_pRef->copy_contents(*rhs.m_pRef);
}

void set_mark(const Mark& mark) { m_pRef->set_mark(mark); }

void set_type(NodeType::value type) {
Expand Down Expand Up @@ -110,17 +123,36 @@ class node {
}
node_iterator end() { return m_pRef->end(); }

void modify(modify_values const& f) {
m_pRef->modify(f);
}

void map_modify(modify_key_values const& f) {
m_pRef->map_modify(f);
}

// sequence
void push_back(node& input, shared_memory_holder pMemory) {
m_pRef->push_back(input, pMemory);
input.add_dependency(*this);
m_index = m_amount.fetch_add(1);
}
// \pre IsSequence(), rhs held in our memory
void seq_push_back(node& rhs) {
m_pRef->seq_push_back(rhs);
}
// map
void insert(node& key, node& value, shared_memory_holder pMemory) {
m_pRef->insert(key, value, pMemory);
key.add_dependency(*this);
value.add_dependency(*this);
}
// \pre IsMap(), key, value held in our memory
void map_force_insert(node& key, node& value) {
m_pRef->map_force_insert(key, value);
key.add_dependency(*this);
value.add_dependency(*this);
}

// indexing
template <typename Key>
Expand Down
21 changes: 20 additions & 1 deletion include/yaml-cpp/node/detail/node_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace detail {
class YAML_CPP_API node_data {
public:
node_data();
node_data(const node_data&) = delete;
node_data(const node_data&) = default;
node_data& operator=(const node_data&) = delete;

void mark_defined();
Expand Down Expand Up @@ -61,6 +61,10 @@ class YAML_CPP_API node_data {

// sequence
void push_back(node& node, const shared_memory_holder& pMemory);
// \pre IsSequence, node in our memory
void seq_push_back(node& node);

// map
void insert(node& key, node& value, const shared_memory_holder& pMemory);

// indexing
Expand All @@ -80,6 +84,21 @@ class YAML_CPP_API node_data {
void force_insert(const Key& key, const Value& value,
shared_memory_holder pMemory);

// map. \pre IsMap()
void map_force_insert(node& key, node& value);

void modify(modify_values const& f)
{
if (m_type == NodeType::Sequence)
seq_modify(f);
else if (m_type == NodeType::Map)
map_modify(f);
}

void seq_modify(modify_values const& f);
void map_modify(modify_values const& f);
void map_modify(modify_key_values const& f);

public:
static const std::string& empty_scalar();

Expand Down
25 changes: 25 additions & 0 deletions include/yaml-cpp/node/detail/node_ref.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,15 @@ class node_ref {
const std::string& tag() const { return m_pData->tag(); }
EmitterStyle::value style() const { return m_pData->style(); }

// needed if we allow copy_contents
void *id() const YAML_CPP_NOEXCEPT { return m_pData.get(); }
void mark_defined() { m_pData->mark_defined(); }
void set_data(const node_ref& rhs) { m_pData = rhs.m_pData; }
void copy_contents(const node_ref& rhs) {
if (&rhs == this) return;
node_data *r = rhs.m_pData.get();
m_pData = std::make_shared<node_data>(*r);
}

void set_mark(const Mark& mark) { m_pData->set_mark(mark); }
void set_type(NodeType::value type) { m_pData->set_type(type); }
Expand All @@ -50,13 +57,31 @@ class node_ref {
}
node_iterator end() { return m_pData->end(); }

void modify(modify_values const& f) {
m_pData->modify(f);
}

void map_modify(modify_key_values const& f) {
m_pData->map_modify(f);
}

// sequence
void push_back(node& node, shared_memory_holder pMemory) {
m_pData->push_back(node, pMemory);
}
// \pre IsSequence, node in our memory
void seq_push_back(node& node) {
m_pData->seq_push_back(node);
}

// map
void insert(node& key, node& value, shared_memory_holder pMemory) {
m_pData->insert(key, value, pMemory);
}
// \pre IsMap, key value held in our memory
void map_force_insert(node& key, node& value) {
m_pData->map_force_insert(key, value);
}

// indexing
template <typename Key>
Expand Down
14 changes: 13 additions & 1 deletion include/yaml-cpp/node/impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ inline Node::Node(Zombie)
inline Node::Node(Zombie, const std::string& key)
: m_isValid(false), m_invalidKey(key), m_pMemory{}, m_pNode(nullptr) {}

inline Node::Node(detail::node& node, detail::shared_memory_holder pMemory)
inline Node::Node(detail::node& node, detail::shared_memory_holder const& pMemory)
: m_isValid(true), m_invalidKey{}, m_pMemory(pMemory), m_pNode(&node) {}

inline Node::~Node() = default;
Expand Down Expand Up @@ -191,6 +191,8 @@ inline void Node::SetStyle(EmitterStyle::value style) {
m_pNode->set_style(style);
}

inline void* Node::id() const YAML_CPP_NOEXCEPT { return m_pNode ? m_pNode->id() : nullptr; }

// assignment
inline bool Node::is(const Node& rhs) const {
if (!m_isValid || !rhs.m_isValid)
Expand Down Expand Up @@ -371,12 +373,22 @@ inline bool Node::remove(const Node& key) {
return m_pNode->remove(*key.m_pNode, m_pMemory);
}

inline void Node::seq_push_back(const Node& rhs) {
m_pMemory->merge(*rhs.m_pMemory);
m_pNode->seq_push_back(*rhs.m_pNode);
}

// map
template <typename Key, typename Value>
inline void Node::force_insert(const Key& key, const Value& value) {
EnsureNodeExists();
m_pNode->force_insert(key, value, m_pMemory);
}
inline void Node::map_force_insert(Node const& key, Node const& value) {
m_pMemory->merge(*key.m_pMemory);
m_pMemory->merge(*value.m_pMemory);
m_pNode->map_force_insert(*key.m_pNode, *value.m_pNode);
}

// free functions
inline bool operator==(const Node& lhs, const Node& rhs) { return lhs.is(rhs); }
Expand Down
26 changes: 26 additions & 0 deletions include/yaml-cpp/node/modify.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef YAMLCPP__NODE_MODIFY_H
#define YAMLCPP__NODE_MODIFY_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 <functional>

namespace YAML {
namespace detail {
class node;
} // namespace detail
} // namespace YAML

namespace YAML {
/// \return 0 to remove key, identity to leave value unchanged, or new node to replace old value
typedef std::function<detail::node *(detail::node *)> modify_values;
/// as above but first arg is pointer to string key (or 0 if non-scalar)
typedef std::function<detail::node *(std::string const*, detail::node *)> modify_key_values;
}


#endif
62 changes: 60 additions & 2 deletions include/yaml-cpp/node/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
#include "yaml-cpp/emitterstyle.h"
#include "yaml-cpp/mark.h"
#include "yaml-cpp/node/detail/iterator_fwd.h"
#include "yaml-cpp/node/modify.h"
#include "yaml-cpp/node/ptr.h"
#include "yaml-cpp/node/type.h"
#include "yaml-cpp/noexcept.h"

namespace YAML {
namespace detail {
Expand All @@ -26,6 +28,11 @@ struct iterator_value;
} // namespace YAML

namespace YAML {
// Node ctor tags
struct UnshareSubtrees {};
struct ShallowClone {};
struct DeepClone {};

class YAML_CPP_API Node {
public:
friend class NodeBuilder;
Expand All @@ -47,8 +54,38 @@ class YAML_CPP_API Node {
explicit Node(const T& rhs);
explicit Node(const detail::iterator_value& rhs);
Node(const Node& rhs);
// newly allocated shallow clone (copies data incl anchors/tags). subtrees may
// still have sharing
Node(const Node& rhs, ShallowClone);
// Node(Node(rhs, memory), ShallowClone())
Node(detail::node& rhs, detail::shared_memory_holder const& memory,
ShallowClone);
// newly allocated deep (recursive) clone (recurisvely copies data but
// possibly not anchors/tags). no cycle detection (i.e. pathological input
// with itself as subtree will expand infinitely)
Node(const Node& rhs, DeepClone);
// Node(Node(rhs, memory), DeepClone())
Node(detail::node& rhs, detail::shared_memory_holder const& memory,
DeepClone);
// rhs but with no shared subtrees (may be is(rhs) if none were shared)
Node(const Node& rhs, UnshareSubtrees);
Node(detail::node& rhs, detail::shared_memory_holder const& memory);
~Node();

detail::node& node() const { return *m_pNode; }
detail::shared_memory_holder const& memory() const { return m_pMemory; }

// \post no anchor-shared subtrees (all but one will be clones instead).
void UnshareSubtrees();
// \post *this = Node(*this, ShallowClone) - copy data.
void OwnData() const;
// f takes and returns a detail::node * for each value in sequence or map;
// value is updated. does nothing for other types
void ModifyValues(modify_values const& f);
// \pre IsMap(). f(std::string const* key, detail::node* val)->detail::node*
// as above but with key (if Scalar) else 0 arg
void ModifyKeyValues(modify_key_values const& f);

YAML::Mark Mark() const;
NodeType::value Type() const;
bool IsDefined() const;
Expand Down Expand Up @@ -76,7 +113,15 @@ class YAML_CPP_API Node {
EmitterStyle::value Style() const;
void SetStyle(EmitterStyle::value style);

// a.id() == b.id() <=> a.is(b). \pre valid
void* id() const YAML_CPP_NOEXCEPT;
friend inline std::size_t hash_value(Node const& n) YAML_CPP_NOEXCEPT {
return n.hash();
}
std::size_t hash() const YAML_CPP_NOEXCEPT { return (std::size_t)id() >> 5; }

// assignment
// note: default/invalid nodes return false; undefined may return true
bool is(const Node& rhs) const;
template <typename T>
Node& operator=(const T& rhs);
Expand All @@ -96,6 +141,8 @@ class YAML_CPP_API Node {
template <typename T>
void push_back(const T& rhs);
void push_back(const Node& rhs);
// \pre IsSequence
void seq_push_back(const Node& rhs);

// indexing
template <typename Key>
Expand All @@ -112,12 +159,13 @@ class YAML_CPP_API Node {
// map
template <typename Key, typename Value>
void force_insert(const Key& key, const Value& value);
// \pre IsMap()
void map_force_insert(Node const& key, Node const& value);

private:
enum Zombie { ZombieNode };
explicit Node(Zombie);
explicit Node(Zombie, const std::string&);
explicit Node(detail::node& node, detail::shared_memory_holder pMemory);

void EnsureNodeExists() const;

Expand All @@ -137,12 +185,22 @@ class YAML_CPP_API Node {
mutable detail::node* m_pNode;
};

// lhs.is(rhs)
YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);

// keeps anchors etc intact
YAML_CPP_API Node Clone(const Node& node);

template <typename T>
struct convert;
}
} // namespace YAML

namespace std {
template <>
struct hash<YAML::Node> {
std::size_t operator()(YAML::Node const& n) { return n.hash(); }
std::size_t operator()(YAML::Node const* n) { return n->hash(); }
};
} // namespace std

#endif // NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66
Loading