Compare commits

..

18 Commits

Author SHA1 Message Date
Jesse Beder
b57efe94e7 Bump version to 0.5.3. 2016-01-10 12:11:40 -06:00
Jesse Beder
36fd93a8d5 Fix formatting when writing " as a character. 2016-01-10 12:08:42 -06:00
Jesse Beder
97d56c3f36 Remove 'const' modifier on return of Node::as.
This enables the return value to be moved, rather than copied.
2015-11-22 11:27:55 -06:00
Michael Welsh Duggan
320b02b14a Allow using a Node as the key in force_insert.
Node::force_insert() uses convert<> to convert its key to a node.
Add a specialization for convert<Node>.
2015-11-22 11:21:08 -06:00
Haydn Trigg
03d6e7d672 Removed boost requirement from memory.h (detail)
Removed the boost requirement from memory.h using the shared_memory type defined in ptr.h
2015-07-25 11:45:10 +09:30
Jonathan Hamilton
b426fafff6 Fix some Node::operator[] regressions from 0.5.1
"const Node Node::operator[](const Key& key) const" changed from
returning new empty node if the key was missing in 0.5.1 to returning
a shared 'zombie' node in 0.5.2 to resolve a memory leak.

(Specifically 1025f76df1 was where this
was introduced)

This caused some regressions where this 'zombie' object threw exceptions
in some functions where the 'empty' object would not.

This change fixes the Node::as(fallback) method (to return the
'fallback' instead of throwing an exception) and the
Node::begin()/Node::end() methods to return default-constructed
iterators (so begin() == end() in such cases) instead of another
exception.
2015-06-08 11:47:10 -07:00
Sébastien Rombauts
b0a4de3dd9 Fix missing/TODO links to 0.3.0 and 0.5.2 releases in README 2015-05-26 18:24:22 +02:00
Jesse Beder
b43db54810 Add CONTRIBUTING file.
Initial description of style, tests, and pull request process.
2015-04-08 14:30:07 -05:00
Jesse Beder
5c390e8d6c Merge pull request #303 from bdutro/patch-1-squashed
Fix compiler error by updating node_data::remove to use new equals() method.
2015-04-08 13:59:56 -05:00
bdutro
aa928b925b Update node_data::remove to use new equals() method
- Update the call to equals() in node_data::remove() to match the new implementation
- Add unit test for node::remove() to catch this type of bug in the future
2015-04-08 13:41:59 -05:00
Jesse Beder
908d38ebef Merge pull request #296 from WrinklyNinja/useful-conversion-errors
Add more error messages that include the location in a parsed file.
2015-04-03 09:41:02 -05:00
Oliver Hamlet
ec8aa4fa62 More useful error messages.
Applied the patch given in jbeder/yaml-cpp#200 with the correct code
style.
2015-04-02 20:50:11 +01:00
Jesse Beder
5de38a76b6 Merge pull request #294 from WrinklyNinja/add-gitignore
Add a .gitignore file.
2015-03-31 08:11:28 -05:00
Oliver Hamlet
25f3935b7c Add a .gitignore file.
Ignore the CMake build directory.
2015-03-31 09:33:49 +01:00
Jesse Beder
4d44602a5d Remove mercurial files 2015-03-30 20:33:45 -05:00
Jesse Beder
897cfd5b2e Rename license file and update copyright date. 2015-03-30 20:32:46 -05:00
Jesse Beder
1a6cb7376a Add README. 2015-03-30 20:31:59 -05:00
Jesse Beder
66acd0d54b Added tag release-0.5.2 for changeset 90238df1f398 2015-03-29 21:32:17 -05:00
23 changed files with 212 additions and 39 deletions

1
.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
build/

4
.hgeol
View File

@@ -1,4 +0,0 @@
**.h = native
**.c = native
**.cpp = native
**.txt = native

View File

@@ -1 +0,0 @@
syntax: glob

View File

@@ -23,7 +23,7 @@ project(YAML_CPP)
set(YAML_CPP_VERSION_MAJOR "0")
set(YAML_CPP_VERSION_MINOR "5")
set(YAML_CPP_VERSION_PATCH "2")
set(YAML_CPP_VERSION_PATCH "3")
set(YAML_CPP_VERSION "${YAML_CPP_VERSION_MAJOR}.${YAML_CPP_VERSION_MINOR}.${YAML_CPP_VERSION_PATCH}")
enable_testing()

17
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,17 @@
# Style
This project is formatted with [clang-format][fmt] using the style file at the root of the repository. Please run clang-format before sending a pull request.
In general, try to follow the style of surrounding code.
[fmt]: http://clang.llvm.org/docs/ClangFormat.html
# Tests
Please verify the tests pass by running the target `tests/run_tests`.
If you are adding functionality, add tests accordingly.
# Pull request process
Every pull request undergoes a code review. Unfortunately, github's code review process isn't great, but we'll manage. During the code review, if you make changes, add new commits to the pull request for each change. Once the code review is complete, rebase against the master branch and squash into a single commit.

View File

@@ -1,4 +1,4 @@
Copyright (c) 2008 Jesse Beder.
Copyright (c) 2008-2015 Jesse Beder.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

52
README.md Normal file
View File

@@ -0,0 +1,52 @@
# yaml-cpp
yaml-cpp is a [YAML](http://www.yaml.org/) parser and emitter in C++ matching the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html).
To get a feel for how it can be used, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) or [How to Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML). For the old API (version < 0.5.0), see [How To Parse A Document](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)).
# Problems? #
If you find a bug, post an [issue](https://github.com/jbeder/yaml-cpp/issues)! If you have questions about how to use yaml-cpp, please post it on http://stackoverflow.com and tag it `yaml-cpp`.
# How to Build #
yaml-cpp uses [CMake](http://www.cmake.org) to support cross-platform building. The basic steps to build are:
1. Download and install [CMake](http://www.cmake.org) (Resources -> Download).
**Note:** If you don't use the provided installer for your platform, make sure that you add CMake's bin folder to your path.
2. Navigate into the source directory, and type:
```
mkdir build
cd build
```
3. Run CMake. The basic syntax is:
```
cmake [-G generator] [-DBUILD_SHARED_LIBS=ON|OFF] ..
```
* The `generator` is whatever type of build system you'd like to use. To see a full list of generators on your platform, just run `cmake` (with no arguments). For example:
* On Windows, you might use "Visual Studio 12 2013" to generate a Visual Studio 2013 solution
* On OS X, you might use "Xcode" to generate an Xcode project
* On a UNIX-y system, simply omit the option to generate a makefile
* yaml-cpp defaults to building a static library, but you may build a shared library by specifying `-DBUILD_SHARED_LIBS=ON`.
* For more options on customizing the build, see the [CMakeLists.txt](https://github.com/jbeder/yaml-cpp/blob/master/CMakeLists.txt) file.
4. Build it!
5. To clean up, just remove the `build` directory.
# Recent Release #
[yaml-cpp 0.5.2](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.5.2) has been released! This is a bug fix release.
[yaml-cpp 0.3.0](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.3.0) is still available if you want the old API.
**The old API will continue to be supported, and will still receive bugfixes!** The 0.3.x and 0.4.x versions will be old API releases, and 0.5.x and above will all be new API releases.

View File

@@ -120,6 +120,10 @@ class Exception : public std::runtime_error {
private:
static const std::string build_what(const Mark& mark,
const std::string& msg) {
if (mark.is_null()) {
return msg.c_str();
}
std::stringstream output;
output << "yaml-cpp: error at line " << mark.line + 1 << ", column "
<< mark.column + 1 << ": " << msg;
@@ -178,14 +182,14 @@ class InvalidNode : public RepresentationException {
class BadConversion : public RepresentationException {
public:
BadConversion()
: RepresentationException(Mark::null_mark(), ErrorMsg::BAD_CONVERSION) {}
explicit BadConversion(const Mark& mark_)
: RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {}
};
template <typename T>
class TypedBadConversion : public BadConversion {
public:
TypedBadConversion() : BadConversion() {}
explicit TypedBadConversion(const Mark& mark_) : BadConversion(mark_) {}
};
class BadDereference : public RepresentationException {

View File

@@ -15,6 +15,8 @@ struct YAML_CPP_API Mark {
static const Mark null_mark() { return Mark(-1, -1, -1); }
bool is_null() const { return pos == -1 && line == -1 && column == -1; }
int pos;
int line, column;

View File

@@ -43,6 +43,17 @@ inline bool IsNaN(const std::string& input) {
}
}
// Node
template <>
struct convert<Node> {
static Node encode(const Node& rhs) { return rhs; }
static bool decode(const Node& node, Node& rhs) {
rhs.reset(node);
return true;
}
};
// std::string
template <>
struct convert<std::string> {

View File

@@ -133,7 +133,7 @@ inline bool node_data::remove(const Key& key, shared_memory_holder pMemory) {
return false;
for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) {
if (equals(*it->first, key, pMemory)) {
if (it->first->equals(key, pMemory)) {
m_map.erase(it);
return true;
}

View File

@@ -7,8 +7,6 @@
#pragma once
#endif
#include <boost/shared_ptr.hpp>
#include <boost/smart_ptr/shared_ptr.hpp>
#include <set>
#include "yaml-cpp/dll.h"
@@ -40,7 +38,7 @@ class YAML_CPP_API memory_holder {
void merge(memory_holder& rhs);
private:
boost::shared_ptr<memory> m_pMemory;
shared_memory m_pMemory;
};
}
}

View File

@@ -25,6 +25,7 @@ class node : private boost::noncopyable {
const node_ref* ref() const { return m_pRef.get(); }
bool is_defined() const { return m_pRef->is_defined(); }
const Mark& mark() const { return m_pRef->mark(); }
NodeType::value type() const { return m_pRef->type(); }
const std::string& scalar() const { return m_pRef->scalar(); }
@@ -64,6 +65,10 @@ class node : private boost::noncopyable {
m_pRef->set_data(*rhs.m_pRef);
}
void set_mark(const Mark& mark) {
m_pRef->set_mark(mark);
}
void set_type(NodeType::value type) {
if (type != NodeType::Undefined)
mark_defined();

View File

@@ -34,6 +34,7 @@ class YAML_CPP_API node_data : private boost::noncopyable {
node_data();
void mark_defined();
void set_mark(const Mark& mark);
void set_type(NodeType::value type);
void set_tag(const std::string& tag);
void set_null();
@@ -41,6 +42,7 @@ class YAML_CPP_API node_data : private boost::noncopyable {
void set_style(EmitterStyle::value style);
bool is_defined() const { return m_isDefined; }
const Mark& mark() const { return m_mark; }
NodeType::value type() const {
return m_isDefined ? m_type : NodeType::Undefined;
}
@@ -97,6 +99,7 @@ class YAML_CPP_API node_data : private boost::noncopyable {
private:
bool m_isDefined;
Mark m_mark;
NodeType::value m_type;
std::string m_tag;
EmitterStyle::value m_style;

View File

@@ -20,6 +20,7 @@ class node_ref : private boost::noncopyable {
node_ref() : m_pData(new node_data) {}
bool is_defined() const { return m_pData->is_defined(); }
const Mark& mark() const { return m_pData->mark(); }
NodeType::value type() const { return m_pData->type(); }
const std::string& scalar() const { return m_pData->scalar(); }
const std::string& tag() const { return m_pData->tag(); }
@@ -28,6 +29,7 @@ class node_ref : private boost::noncopyable {
void mark_defined() { m_pData->mark_defined(); }
void set_data(const node_ref& rhs) { m_pData = rhs.m_pData; }
void set_mark(const Mark& mark) { m_pData->set_mark(mark); }
void set_type(NodeType::value type) { m_pData->set_type(type); }
void set_tag(const std::string& tag) { m_pData->set_tag(tag); }
void set_null() { m_pData->set_null(); }

View File

@@ -66,6 +66,13 @@ inline bool Node::IsDefined() const {
return m_pNode ? m_pNode->is_defined() : true;
}
inline Mark Node::Mark() const {
if (!m_isValid) {
throw InvalidNode();
}
return m_pNode ? m_pNode->mark() : Mark::null_mark();
}
inline NodeType::value Node::Type() const {
if (!m_isValid)
throw InvalidNode();
@@ -80,7 +87,7 @@ struct as_if {
explicit as_if(const Node& node_) : node(node_) {}
const Node& node;
const T operator()(const S& fallback) const {
T operator()(const S& fallback) const {
if (!node.m_pNode)
return fallback;
@@ -110,12 +117,12 @@ struct as_if<T, void> {
const T operator()() const {
if (!node.m_pNode)
throw TypedBadConversion<T>();
throw TypedBadConversion<T>(node.Mark());
T t;
if (convert<T>::decode(node, t))
return t;
throw TypedBadConversion<T>();
throw TypedBadConversion<T>(node.Mark());
}
};
@@ -126,23 +133,23 @@ struct as_if<std::string, void> {
const std::string operator()() const {
if (node.Type() != NodeType::Scalar)
throw TypedBadConversion<std::string>();
throw TypedBadConversion<std::string>(node.Mark());
return node.Scalar();
}
};
// access functions
template <typename T>
inline const T Node::as() const {
inline T Node::as() const {
if (!m_isValid)
throw InvalidNode();
return as_if<T, void>(*this)();
}
template <typename T, typename S>
inline const T Node::as(const S& fallback) const {
inline T Node::as(const S& fallback) const {
if (!m_isValid)
throw InvalidNode();
return fallback;
return as_if<T, S>(*this)(fallback);
}
@@ -275,26 +282,26 @@ inline std::size_t Node::size() const {
inline const_iterator Node::begin() const {
if (!m_isValid)
throw InvalidNode();
return const_iterator();
return m_pNode ? const_iterator(m_pNode->begin(), m_pMemory)
: const_iterator();
}
inline iterator Node::begin() {
if (!m_isValid)
throw InvalidNode();
return iterator();
return m_pNode ? iterator(m_pNode->begin(), m_pMemory) : iterator();
}
inline const_iterator Node::end() const {
if (!m_isValid)
throw InvalidNode();
return const_iterator();
return m_pNode ? const_iterator(m_pNode->end(), m_pMemory) : const_iterator();
}
inline iterator Node::end() {
if (!m_isValid)
throw InvalidNode();
return iterator();
return m_pNode ? iterator(m_pNode->end(), m_pMemory) : iterator();
}

View File

@@ -11,6 +11,7 @@
#include "yaml-cpp/dll.h"
#include "yaml-cpp/emitterstyle.h"
#include "yaml-cpp/mark.h"
#include "yaml-cpp/node/detail/bool_type.h"
#include "yaml-cpp/node/detail/iterator_fwd.h"
#include "yaml-cpp/node/ptr.h"
@@ -48,6 +49,7 @@ class YAML_CPP_API Node {
Node(const Node& rhs);
~Node();
YAML::Mark Mark() const;
NodeType::value Type() const;
bool IsDefined() const;
bool IsNull() const { return Type() == NodeType::Null; }
@@ -61,9 +63,9 @@ class YAML_CPP_API Node {
// access
template <typename T>
const T as() const;
T as() const;
template <typename T, typename S>
const T as(const S& fallback) const;
T as(const S& fallback) const;
const std::string& Scalar() const;
const std::string& Tag() const;

View File

@@ -375,14 +375,16 @@ bool WriteLiteralString(ostream_wrapper& out, const std::string& str,
bool WriteChar(ostream_wrapper& out, char ch) {
if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) {
out << ch;
} else if ((0x20 <= ch && ch <= 0x7e) || ch == ' ') {
out << "\"" << ch << "\"";
} else if (ch == '\"') {
out << "\"\\\"\"";
} else if (ch == '\t') {
out << "\"\\t\"";
} else if (ch == '\n') {
out << "\"\\n\"";
} else if (ch == '\b') {
out << "\"\\b\"";
} else if ((0x20 <= ch && ch <= 0x7e) || ch == ' ') {
out << "\"" << ch << "\"";
} else {
out << "\"";
WriteDoubleQuoteEscapeSequence(out, ch);

View File

@@ -17,6 +17,7 @@ std::string node_data::empty_scalar;
node_data::node_data()
: m_isDefined(false),
m_mark(Mark::null_mark()),
m_type(NodeType::Null),
m_style(EmitterStyle::Default),
m_seqSize(0) {}
@@ -27,6 +28,10 @@ void node_data::mark_defined() {
m_isDefined = true;
}
void node_data::set_mark(const Mark& mark) {
m_mark = mark;
}
void node_data::set_type(NodeType::value type) {
if (type == NodeType::Undefined) {
m_type = type;

View File

@@ -28,8 +28,8 @@ void NodeBuilder::OnDocumentStart(const Mark&) {}
void NodeBuilder::OnDocumentEnd() {}
void NodeBuilder::OnNull(const Mark& /* mark */, anchor_t anchor) {
detail::node& node = Push(anchor);
void NodeBuilder::OnNull(const Mark& mark, anchor_t anchor) {
detail::node& node = Push(mark, anchor);
node.set_null();
Pop();
}
@@ -40,18 +40,18 @@ void NodeBuilder::OnAlias(const Mark& /* mark */, anchor_t anchor) {
Pop();
}
void NodeBuilder::OnScalar(const Mark& /* mark */, const std::string& tag,
void NodeBuilder::OnScalar(const Mark& mark, const std::string& tag,
anchor_t anchor, const std::string& value) {
detail::node& node = Push(anchor);
detail::node& node = Push(mark, anchor);
node.set_scalar(value);
node.set_tag(tag);
Pop();
}
void NodeBuilder::OnSequenceStart(const Mark& /* mark */,
void NodeBuilder::OnSequenceStart(const Mark& mark,
const std::string& tag, anchor_t anchor,
EmitterStyle::value style) {
detail::node& node = Push(anchor);
detail::node& node = Push(mark, anchor);
node.set_tag(tag);
node.set_type(NodeType::Sequence);
node.set_style(style);
@@ -59,9 +59,9 @@ void NodeBuilder::OnSequenceStart(const Mark& /* mark */,
void NodeBuilder::OnSequenceEnd() { Pop(); }
void NodeBuilder::OnMapStart(const Mark& /* mark */, const std::string& tag,
void NodeBuilder::OnMapStart(const Mark& mark, const std::string& tag,
anchor_t anchor, EmitterStyle::value style) {
detail::node& node = Push(anchor);
detail::node& node = Push(mark, anchor);
node.set_type(NodeType::Map);
node.set_tag(tag);
node.set_style(style);
@@ -74,8 +74,9 @@ void NodeBuilder::OnMapEnd() {
Pop();
}
detail::node& NodeBuilder::Push(anchor_t anchor) {
detail::node& NodeBuilder::Push(const Mark& mark, anchor_t anchor) {
detail::node& node = m_pMemory->create_node();
node.set_mark(mark);
RegisterAnchor(anchor, node);
Push(node);
return node;

View File

@@ -48,7 +48,7 @@ class NodeBuilder : public EventHandler {
virtual void OnMapEnd();
private:
detail::node& Push(anchor_t anchor);
detail::node& Push(const Mark& mark, anchor_t anchor);
void Push(detail::node& node);
void Pop();
void RegisterAnchor(anchor_t anchor, detail::node& node);

View File

@@ -962,6 +962,14 @@ TEST_F(EmitterTest, QuoteNull) {
ExpectEmit("\"null\"");
}
TEST_F(EmitterTest, ValueOfDoubleQuote) {
out << YAML::BeginMap;
out << YAML::Key << "foo" << YAML::Value << '"';
out << YAML::EndMap;
ExpectEmit("foo: \"\\\"\"");
}
class EmitterErrorTest : public ::testing::Test {
protected:
void ExpectEmitError(const std::string& expectedError) {

View File

@@ -39,6 +39,13 @@ TEST(NodeTest, SimpleAppendSequence) {
EXPECT_TRUE(node.IsSequence());
}
TEST(NodeTest, MapElementRemoval) {
Node node;
node["foo"] = "bar";
node.remove("foo");
EXPECT_TRUE(!node["foo"]);
}
TEST(NodeTest, SimpleAssignSequence) {
Node node;
node[0] = 10;
@@ -73,6 +80,31 @@ TEST(NodeTest, MapWithUndefinedValues) {
EXPECT_EQ(2, node.size());
}
TEST(NodeTest, MapForceInsert) {
Node node;
Node k1("k1");
Node k2("k2");
Node v1("v1");
Node v2("v2");
node[k1] = v1;
node[k2] = v1;
EXPECT_TRUE(node.IsMap());
EXPECT_EQ("v1", node["k1"].as<std::string>());
EXPECT_EQ("v1", node["k2"].as<std::string>());
EXPECT_EQ(2, node.size());
node.force_insert(k2, v2);
EXPECT_EQ("v1", node["k1"].as<std::string>());
EXPECT_EQ("v2", node["k2"].as<std::string>());
EXPECT_EQ(2, node.size());
}
TEST(NodeTest, UndefinedConstNodeWithFallback) {
Node node;
const Node& cn = node;
EXPECT_EQ(cn["undefined"].as<int>(3), 3);
}
TEST(NodeTest, MapIteratorWithUndefinedValues) {
Node node;
node["key"] = "value";
@@ -84,6 +116,32 @@ TEST(NodeTest, MapIteratorWithUndefinedValues) {
EXPECT_EQ(1, count);
}
TEST(NodeTest, ConstIteratorOnConstUndefinedNode) {
Node node;
const Node& cn = node;
const Node& undefinedCn = cn["undefined"];
std::size_t count = 0;
for (const_iterator it = undefinedCn.begin(); it != undefinedCn.end(); ++it) {
count++;
}
EXPECT_EQ(0, count);
}
TEST(NodeTest, IteratorOnConstUndefinedNode) {
Node node;
const Node& cn = node;
const Node& undefinedCn = cn["undefined"];
Node& nonConstUndefinedNode = const_cast<Node&>(undefinedCn);
std::size_t count = 0;
for (iterator it = nonConstUndefinedNode.begin(); it != nonConstUndefinedNode.end(); ++it) {
count++;
}
EXPECT_EQ(0, count);
}
TEST(NodeTest, SimpleSubkeys) {
Node node;
node["device"]["udid"] = "12345";