Skip to content
Merged
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
1 change: 1 addition & 0 deletions include/yaml-cpp/node/detail/iterator.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

#include "yaml-cpp/dll.h"
#include "yaml-cpp/node/detail/node_iterator.h"
#include "yaml-cpp/node/detail/reverse_iterator.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/ptr.h"
#include <cstddef>
Expand Down
4 changes: 4 additions & 0 deletions include/yaml-cpp/node/detail/iterator_fwd.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,14 @@ namespace detail {
struct iterator_value;
template <typename V>
class iterator_base;
template <typename V>
class reverse_iterator_base;
}

using iterator = detail::iterator_base<detail::iterator_value>;
using const_iterator = detail::iterator_base<const detail::iterator_value>;
using reverse_iterator = detail::reverse_iterator_base<iterator>;
using const_reverse_iterator = detail::reverse_iterator_base<const_iterator>;
}

#endif // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66
98 changes: 98 additions & 0 deletions include/yaml-cpp/node/detail/reverse_iterator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
#ifndef VALUE_DETAIL_REVERSE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
#define VALUE_DETAIL_REVERSE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66

#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 "yaml-cpp/dll.h"
#include "yaml-cpp/node/ptr.h"
#include <cstddef>
#include <iterator>

namespace YAML {
namespace detail {

// detail::iterator_base and detail::node_iterator_base are incompatible with
// std::reverse_iterator because their operator->() return a proxy object rather
// than a pointer, so a customized wrapper is needed to implement
// reverse_iterator for them.
template <typename Iter>
class reverse_iterator_base {
private:
Iter current;
template <typename>
friend class reverse_iterator_base;
struct enabler {};
using proxy_type = decltype(current.operator->());

public:
using iterator_type = Iter;
using iterator_category = typename std::iterator_traits<Iter>::iterator_category;
using value_type = typename std::iterator_traits<Iter>::value_type;
using difference_type = typename std::iterator_traits<Iter>::difference_type;
using pointer = typename std::iterator_traits<Iter>::pointer;
using reference = typename std::iterator_traits<Iter>::reference;

public:
reverse_iterator_base() : current() {}
explicit reverse_iterator_base(Iter _base) : current(_base) {}
template <class Iter2>
reverse_iterator_base(const reverse_iterator_base<Iter2>& _other,
typename std::enable_if<std::is_convertible<Iter2, Iter>::value,
enabler>::type = enabler())
: current(_other.current) {}

reverse_iterator_base<Iter>& operator++() {
--current;
return *this;
}

reverse_iterator_base<Iter> operator++(int) {
reverse_iterator_base<Iter> iterator_pre(*this);
++(*this);
return iterator_pre;
}

reverse_iterator_base<Iter>& operator--() {
++current;
return *this;
}

reverse_iterator_base<Iter> operator--(int) {
reverse_iterator_base<Iter> iterator_pre(*this);
--(*this);
return iterator_pre;
}

template <typename Iter2>
bool operator==(const reverse_iterator_base<Iter2>& rhs) const {
return current == rhs.current;
}

template <typename Iter2>
bool operator!=(const reverse_iterator_base<Iter2>& rhs) const {
return current != rhs.current;
}

iterator_type base() const {
return current;
}

value_type operator*() const YAML_ATTRIBUTE_LIFETIME_BOUND {
Iter _tmp = current;
return *(--_tmp);
}

proxy_type operator->() const YAML_ATTRIBUTE_LIFETIME_BOUND {
Iter _tmp = current;
--_tmp;
return _tmp.operator->();
}
};
}
}

#endif // VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66
16 changes: 16 additions & 0 deletions include/yaml-cpp/node/impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,14 @@ inline iterator Node::begin() {
return m_pNode ? iterator(m_pNode->begin(), m_pMemory) : iterator();
}

inline const_reverse_iterator Node::rbegin() const {
return const_reverse_iterator(end());
}

inline reverse_iterator Node::rbegin() {
return reverse_iterator(end());
}

inline const_iterator Node::end() const {
if (!m_isValid)
return const_iterator();
Expand All @@ -315,6 +323,14 @@ inline iterator Node::end() {
return m_pNode ? iterator(m_pNode->end(), m_pMemory) : iterator();
}

inline const_reverse_iterator Node::rend() const {
return const_reverse_iterator(begin());
}

inline reverse_iterator Node::rend() {
return reverse_iterator(begin());
}

// sequence
template <typename T>
inline void Node::push_back(const T& rhs) {
Expand Down
6 changes: 6 additions & 0 deletions include/yaml-cpp/node/node.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ class YAML_CPP_API Node {

using iterator = YAML::iterator;
using const_iterator = YAML::const_iterator;
using reverse_iterator = YAML::reverse_iterator;
using const_reverse_iterator = YAML::const_reverse_iterator;

Node();
explicit Node(NodeType::value type);
Expand Down Expand Up @@ -89,9 +91,13 @@ class YAML_CPP_API Node {

const_iterator begin() const;
iterator begin();
const_reverse_iterator rbegin() const;
reverse_iterator rbegin();

const_iterator end() const;
iterator end();
const_reverse_iterator rend() const;
reverse_iterator rend();

// sequence
template <typename T>
Expand Down
70 changes: 70 additions & 0 deletions test/node/node_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,17 @@ TEST(NodeTest, MapIteratorWithUndefinedValuesBackward) {
EXPECT_EQ(1, count);
}

TEST(NodeTest, MapReverseIteratorWithUndefinedValues) {
Node node;
node["key"] = "value";
node["undefined"];

std::size_t count = 0;
for (const_reverse_iterator it = node.rbegin(); it != node.rend(); ++it)
count++;
EXPECT_EQ(1, count);
}

TEST(NodeTest, DestroyedMapIterator) {
Node node;
node["key"] = "value";
Expand All @@ -375,6 +386,18 @@ TEST(NodeTest, ConstIteratorOnConstUndefinedNode) {
EXPECT_EQ(0, count);
}

TEST(NodeTest, ConstReverseIteratorOnConstUndefinedNode) {
Node node;
const Node& cn = node;
const Node& undefinedCn = cn["undefined"];

std::size_t count = 0;
for (const_reverse_iterator it = undefinedCn.rbegin(); it != undefinedCn.rend(); ++it) {
count++;
}
EXPECT_EQ(0, count);
}

TEST(NodeTest, IteratorOnConstUndefinedNode) {
Node node;
const Node& cn = node;
Expand All @@ -389,6 +412,21 @@ TEST(NodeTest, IteratorOnConstUndefinedNode) {
}
EXPECT_EQ(0, count);
}

TEST(NodeTest, ReverseIteratorOnConstUndefinedNode) {
Node node;
const Node& cn = node;
const Node& undefinedCn = cn["undefined"];

Node& nonConstUndefinedNode = const_cast<Node&>(undefinedCn);

std::size_t count = 0;
for (reverse_iterator it = nonConstUndefinedNode.rbegin();
it != nonConstUndefinedNode.rend(); ++it) {
count++;
}
EXPECT_EQ(0, count);
}

TEST(NodeTest, InteratorOnSequence) {
Node node;
Expand Down Expand Up @@ -422,6 +460,22 @@ TEST(NodeTest, InteratorOnSequenceBackward) {
EXPECT_EQ(3, count);
}

TEST(NodeTest, ReverseInteratorOnSequence) {
Node node;
node[0] = "a";
node[1] = "b";
node[2] = "c";
EXPECT_TRUE(node.IsSequence());

std::size_t count = 0;
for (reverse_iterator it = node.rbegin(); it != node.rend(); ++it)
{
EXPECT_FALSE(it->IsNull());
count++;
}
EXPECT_EQ(3, count);
}

TEST(NodeTest, ConstInteratorOnSequence) {
Node node;
node[0] = "a";
Expand All @@ -437,6 +491,22 @@ TEST(NodeTest, ConstInteratorOnSequence) {
}
EXPECT_EQ(3, count);
}

TEST(NodeTest, ConstReverseInteratorOnSequence) {
Node node;
node[0] = "a";
node[1] = "b";
node[2] = "c";
EXPECT_TRUE(node.IsSequence());

std::size_t count = 0;
for (const_reverse_iterator it = node.rbegin(); it != node.rend(); ++it)
{
EXPECT_FALSE(it->IsNull());
count++;
}
EXPECT_EQ(3, count);
}

#if __cplusplus >= 201703L
TEST(NodeTest, StdStringViewAsKey) {
Expand Down