This commit is contained in:
leni536 2018-02-08 07:56:44 +00:00 committed by GitHub
commit 8dac04e905
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 244 additions and 103 deletions

25
.gitignore vendored
View File

@ -1 +1,24 @@
build/ # CMake
CMakeCache.txt
CMakeFiles
CMakeScripts
Testing
Makefile
cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
/libyaml-cpp.a
/test/gtest-1.8.0/googlemock/gtest/libgtest.a
/test/gtest-1.8.0/googlemock/gtest/libgtest_main.a
/test/gtest-1.8.0/googlemock/libgmock.a
/test/gtest-1.8.0/googlemock/libgmock_main.a
/test/run-tests
/util/parse
/util/read
/util/sandbox
/yaml-cpp-config-version.cmake
/yaml-cpp-config.cmake
/yaml-cpp-targets.cmake
/yaml-cpp.pc

View File

@ -8,9 +8,11 @@
#endif #endif
#include <array> #include <array>
#include <cmath>
#include <limits> #include <limits>
#include <list> #include <list>
#include <map> #include <map>
#include <regex>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
@ -24,24 +26,32 @@
namespace YAML { namespace YAML {
class Binary; class Binary;
struct _Null; struct _Null;
template <typename T> template <typename T, typename Enable>
struct convert; struct convert;
} // namespace YAML } // namespace YAML
namespace YAML { namespace YAML {
namespace conversion { namespace conversion {
inline bool IsInfinity(const std::string& input) {
return input == ".inf" || input == ".Inf" || input == ".INF" ||
input == "+.inf" || input == "+.Inf" || input == "+.INF";
}
inline bool IsNegativeInfinity(const std::string& input) { static const std::regex re_true("true|True|TRUE");
return input == "-.inf" || input == "-.Inf" || input == "-.INF"; static const std::regex re_false("false|False|FALSE");
} static const std::regex re_decimal("[-+]?[0-9]+");
static const std::regex re_octal("0o[0-7]+");
static const std::regex re_hex("0x[0-9a-fA-F]+");
static const std::regex re_float(
"[-+]?(\\.[0-9]+|[0-9]+(\\.[0-9]*)?)([eE][-+]?[0-9]+)?");
static const std::regex re_inf("[-+]?(\\.inf|\\.Inf|\\.INF)");
static const std::regex re_nan("\\.nan|\\.NaN|\\.NAN");
inline bool IsNaN(const std::string& input) { template <typename T>
return input == ".nan" || input == ".NaN" || input == ".NAN"; struct is_character {
} using value_type = bool;
static constexpr bool value =
(std::is_same<T, char>::value || std::is_same<T, wchar_t>::value ||
std::is_same<T, char16_t>::value || std::is_same<T, char32_t>::value);
using type = std::integral_constant<bool, value>;
};
} }
// Node // Node
@ -76,7 +86,7 @@ struct convert<const char*> {
template <std::size_t N> template <std::size_t N>
struct convert<const char[N]> { struct convert<const char[N]> {
static Node encode(const char(&rhs)[N]) { return Node(rhs); } static Node encode(const char (&rhs)[N]) { return Node(rhs); }
}; };
template <> template <>
@ -88,70 +98,160 @@ struct convert<_Null> {
} }
}; };
#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \ // character types
template <> \ template <typename type>
struct convert<type> { \ struct convert<type, typename std::enable_if<
static Node encode(const type& rhs) { \ conversion::is_character<type>::value>::type> {
std::stringstream stream; \ static Node encode(const type& rhs) { return Node(std::string(1,rhs)); }
stream.precision(std::numeric_limits<type>::digits10 + 1); \
stream << rhs; \ static bool decode(const Node& node, type& rhs) {
return Node(stream.str()); \ if (node.Type() != NodeType::Scalar)
} \ return false;
\ const std::string& input = node.Scalar();
static bool decode(const Node& node, type& rhs) { \ if (input.length() != 1) {
if (node.Type() != NodeType::Scalar) \ return false;
return false; \ }
const std::string& input = node.Scalar(); \ rhs = input[0];
std::stringstream stream(input); \ return true;
stream.unsetf(std::ios::dec); \ }
if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) \ };
return true; \
if (std::numeric_limits<type>::has_infinity) { \ // signed integral (sans char)
if (conversion::IsInfinity(input)) { \ template <typename type>
rhs = std::numeric_limits<type>::infinity(); \ struct convert<
return true; \ type, typename std::enable_if<
} else if (conversion::IsNegativeInfinity(input)) { \ std::is_integral<type>::value && std::is_signed<type>::value &&
rhs = negative_op std::numeric_limits<type>::infinity(); \ !conversion::is_character<type>::value>::type> {
return true; \ static Node encode(const type& rhs) { return Node(std::to_string(rhs)); }
} \
} \ static bool decode(const Node& node, type& rhs) {
\ if (node.Type() != NodeType::Scalar)
if (std::numeric_limits<type>::has_quiet_NaN && \ return false;
conversion::IsNaN(input)) { \ const std::string& input = node.Scalar();
rhs = std::numeric_limits<type>::quiet_NaN(); \ long long num;
return true; \ if (std::regex_match(input, conversion::re_decimal)) {
} \ try {
\ num = std::stoll(input);
return false; \ } catch (const std::out_of_range&) {
} \ return false;
}
} else if (std::regex_match(input, conversion::re_octal)) {
try {
num = std::stoll(input.substr(2), nullptr, 8);
} catch (const std::out_of_range&) {
return false;
}
} else if (std::regex_match(input, conversion::re_hex)) {
try {
num = std::stoll(input.substr(2), nullptr, 16);
} catch (const std::out_of_range&) {
return false;
}
} else {
return false;
}
if (num > std::numeric_limits<type>::max() ||
num < std::numeric_limits<type>::min()) {
return false;
}
rhs = num;
return true;
}
};
// unsigned integral (sans char)
template <typename type>
struct convert<
type, typename std::enable_if<
std::is_integral<type>::value && std::is_unsigned<type>::value &&
!conversion::is_character<type>::value>::type> {
static Node encode(const type& rhs) { return Node(std::to_string(rhs)); }
static bool decode(const Node& node, type& rhs) {
if (node.Type() != NodeType::Scalar)
return false;
const std::string& input = node.Scalar();
unsigned long long num;
if (std::regex_match(input, conversion::re_decimal)) {
try {
num = std::stoull(input);
} catch (const std::out_of_range&) {
return false;
}
} else if (std::regex_match(input, conversion::re_octal)) {
try {
num = std::stoull(input.substr(2), nullptr, 8);
} catch (const std::out_of_range&) {
return false;
}
} else if (std::regex_match(input, conversion::re_hex)) {
try {
num = std::stoull(input.substr(2), nullptr, 16);
} catch (const std::out_of_range&) {
return false;
}
} else {
return false;
}
if (num > std::numeric_limits<type>::max() ||
num < std::numeric_limits<type>::min()) {
return false;
}
rhs = num;
return true;
}
};
// floating point
template <typename type>
struct convert<
type, typename std::enable_if<std::is_floating_point<type>::value>::type> {
static Node encode(const type& rhs) {
if (std::isnan(rhs)) {
return Node(".nan");
}
if (std::isinf(rhs)) {
if (std::signbit(rhs)) {
return Node("-.inf");
}
return Node(".inf");
}
std::stringstream stream;
stream.precision(std::numeric_limits<type>::max_digits10);
stream << rhs;
auto str = stream.str();
if (std::regex_match(str, conversion::re_decimal)) {
return Node(str + "."); // Disambiguate float from int
}
return Node(str);
} }
#define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \ static bool decode(const Node& node, type& rhs) {
YAML_DEFINE_CONVERT_STREAMABLE(type, -) if (node.Type() != NodeType::Scalar)
return false;
#define YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(type) \ const std::string& input = node.Scalar();
YAML_DEFINE_CONVERT_STREAMABLE(type, +) long double num;
if (std::regex_match(input, conversion::re_float)) {
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int); try {
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(short); num = std::stold(input);
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long); } catch (const std::out_of_range&) {
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long long); return false;
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned); }
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned short); } else if (std::regex_match(input, conversion::re_inf)) {
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long); if (input[0] == '-') {
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long long); num = -std::numeric_limits<long double>::infinity();
} else {
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(char); num = std::numeric_limits<long double>::infinity();
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(signed char); }
YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned char); } else if (std::regex_match(input, conversion::re_nan)) {
num = std::numeric_limits<long double>::quiet_NaN();
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(float); } else {
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(double); return false;
YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long double); }
rhs = num;
#undef YAML_DEFINE_CONVERT_STREAMABLE_SIGNED return true;
#undef YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED }
#undef YAML_DEFINE_CONVERT_STREAMABLE };
// bool // bool
template <> template <>

View File

@ -138,7 +138,7 @@ YAML_CPP_API bool operator==(const Node& lhs, const Node& rhs);
YAML_CPP_API Node Clone(const Node& node); YAML_CPP_API Node Clone(const Node& node);
template <typename T> template <typename T, typename Enable = void>
struct convert; struct convert;
} }

View File

@ -24,8 +24,8 @@ EmitterState::EmitterState()
m_seqFmt.set(Block); m_seqFmt.set(Block);
m_mapFmt.set(Block); m_mapFmt.set(Block);
m_mapKeyFmt.set(Auto); m_mapKeyFmt.set(Auto);
m_floatPrecision.set(std::numeric_limits<float>::digits10 + 1); m_floatPrecision.set(std::numeric_limits<float>::max_digits10);
m_doublePrecision.set(std::numeric_limits<double>::digits10 + 1); m_doublePrecision.set(std::numeric_limits<double>::max_digits10);
} }
EmitterState::~EmitterState() {} EmitterState::~EmitterState() {}
@ -349,7 +349,7 @@ bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope) {
} }
bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) { bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) {
if (value > std::numeric_limits<float>::digits10 + 1) if (value > std::numeric_limits<float>::max_digits10)
return false; return false;
_Set(m_floatPrecision, value, scope); _Set(m_floatPrecision, value, scope);
return true; return true;
@ -357,7 +357,7 @@ bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) {
bool EmitterState::SetDoublePrecision(std::size_t value, bool EmitterState::SetDoublePrecision(std::size_t value,
FmtScope::value scope) { FmtScope::value scope) {
if (value > std::numeric_limits<double>::digits10 + 1) if (value > std::numeric_limits<double>::max_digits10)
return false; return false;
_Set(m_doublePrecision, value, scope); _Set(m_doublePrecision, value, scope);
return true; return true;

View File

@ -904,7 +904,7 @@ TEST_F(EmitterTest, DefaultPrecision) {
out << 1.234f; out << 1.234f;
out << 3.14159265358979; out << 3.14159265358979;
out << EndSeq; out << EndSeq;
ExpectEmit("- 1.234\n- 3.14159265358979"); ExpectEmit("- 1.23399997\n- 3.14159265358979");
} }
TEST_F(EmitterTest, SetPrecision) { TEST_F(EmitterTest, SetPrecision) {

View File

@ -20,7 +20,7 @@ TEST(LoadNodeTest, FallbackValues) {
} }
TEST(LoadNodeTest, NumericConversion) { TEST(LoadNodeTest, NumericConversion) {
Node node = Load("[1.5, 1, .nan, .inf, -.inf, 0x15, 015]"); Node node = Load("[1.5, 1, .nan, .inf, -.inf, 0x15, 0o15]");
EXPECT_EQ(1.5f, node[0].as<float>()); EXPECT_EQ(1.5f, node[0].as<float>());
EXPECT_EQ(1.5, node[0].as<double>()); EXPECT_EQ(1.5, node[0].as<double>());
EXPECT_THROW(node[0].as<int>(), TypedBadConversion<int>); EXPECT_THROW(node[0].as<int>(), TypedBadConversion<int>);

View File

@ -1,10 +1,10 @@
#include "yaml-cpp/emitter.h" #include "yaml-cpp/emitter.h"
#include "yaml-cpp/node/emit.h"
#include "yaml-cpp/node/node.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/node/convert.h" #include "yaml-cpp/node/convert.h"
#include "yaml-cpp/node/iterator.h"
#include "yaml-cpp/node/detail/impl.h" #include "yaml-cpp/node/detail/impl.h"
#include "yaml-cpp/node/emit.h"
#include "yaml-cpp/node/impl.h"
#include "yaml-cpp/node/iterator.h"
#include "yaml-cpp/node/node.h"
#include "gmock/gmock.h" #include "gmock/gmock.h"
#include "gtest/gtest.h" #include "gtest/gtest.h"
@ -393,6 +393,8 @@ class NodeEmitterTest : public ::testing::Test {
protected: protected:
void ExpectOutput(const std::string& output, const Node& node) { void ExpectOutput(const std::string& output, const Node& node) {
Emitter emitter; Emitter emitter;
// ASSERT_TRUE(emitter.SetFloatPrecision(3));
// ASSERT_TRUE(emitter.SetDoublePrecision(3));
emitter << node; emitter << node;
ASSERT_TRUE(emitter.good()); ASSERT_TRUE(emitter.good());
EXPECT_EQ(output, emitter.c_str()); EXPECT_EQ(output, emitter.c_str());
@ -410,29 +412,32 @@ class NodeEmitterTest : public ::testing::Test {
TEST_F(NodeEmitterTest, SimpleFlowSeqNode) { TEST_F(NodeEmitterTest, SimpleFlowSeqNode) {
Node node; Node node;
node.SetStyle(EmitterStyle::Flow); node.SetStyle(EmitterStyle::Flow);
node.push_back(1.01); node.push_back(0.32);
node.push_back(2.01); node.push_back(0.64);
node.push_back(3.01); node.push_back(10.24);
ExpectOutput("[1.01, 2.01, 3.01]", node); ExpectOutput("[0.32000000000000001, 0.64000000000000001, 10.24]", node);
} }
TEST_F(NodeEmitterTest, NestFlowSeqNode) { TEST_F(NodeEmitterTest, NestFlowSeqNode) {
Node node, cell0, cell1; Node node, cell0, cell1;
cell0.push_back(1.01); cell0.push_back(1.08);
cell0.push_back(2.01); cell0.push_back(2.08);
cell0.push_back(3.01); cell0.push_back(3.08);
cell1.push_back(4.01); cell1.push_back(4.08);
cell1.push_back(5.01); cell1.push_back(5.08);
cell1.push_back(6.01); cell1.push_back(6.08);
node.SetStyle(EmitterStyle::Flow); node.SetStyle(EmitterStyle::Flow);
node.push_back(cell0); node.push_back(cell0);
node.push_back(cell1); node.push_back(cell1);
ExpectOutput("[[1.01, 2.01, 3.01], [4.01, 5.01, 6.01]]", node); ExpectOutput(
"[[1.0800000000000001, 2.0800000000000001, 3.0800000000000001], "
"[4.0800000000000001, 5.0800000000000001, 6.0800000000000001]]",
node);
} }
TEST_F(NodeEmitterTest, MixBlockFlowSeqNode) { TEST_F(NodeEmitterTest, MixBlockFlowSeqNode) {
@ -451,7 +456,13 @@ TEST_F(NodeEmitterTest, MixBlockFlowSeqNode) {
node.push_back(cell0); node.push_back(cell0);
node.push_back(cell1); node.push_back(cell1);
ExpectOutput("- [1.01, 2.01, 3.01]\n-\n - 4.01\n - 5.01\n - 6.01", node); ExpectOutput(
R"(- [1.01, 2.0099999999999998, 3.0099999999999998]
-
- 4.0099999999999998
- 5.0099999999999998
- 6.0099999999999998)",
node);
} }
TEST_F(NodeEmitterTest, NestBlockFlowMapListNode) { TEST_F(NodeEmitterTest, NestBlockFlowMapListNode) {
@ -467,7 +478,9 @@ TEST_F(NodeEmitterTest, NestBlockFlowMapListNode) {
blockNode.push_back(1.01); blockNode.push_back(1.01);
blockNode.push_back(mapNode); blockNode.push_back(mapNode);
ExpectOutput("- 1.01\n- {position: [1.01, 2.01, 3.01]}", blockNode); ExpectOutput(
"- 1.01\n- {position: [1.01, 2.0099999999999998, 3.0099999999999998]}",
blockNode);
} }
TEST_F(NodeEmitterTest, NestBlockMixMapListNode) { TEST_F(NodeEmitterTest, NestBlockMixMapListNode) {
@ -484,8 +497,10 @@ TEST_F(NodeEmitterTest, NestBlockMixMapListNode) {
blockNode["object"] = mapNode; blockNode["object"] = mapNode;
ExpectAnyOutput(blockNode, ExpectAnyOutput(blockNode,
"scalar: 1.01\nobject: {position: [1.01, 2.01, 3.01]}", "scalar: 1.01\nobject: {position: [1.01, 2.0099999999999998, "
"object: {position: [1.01, 2.01, 3.01]}\nscalar: 1.01"); "3.0099999999999998]}",
"object: {position: [1.01, 2.0099999999999998, "
"3.0099999999999998]}\nscalar: 1.01");
} }
TEST_F(NodeEmitterTest, NestBlockMapListNode) { TEST_F(NodeEmitterTest, NestBlockMapListNode) {
@ -498,7 +513,9 @@ TEST_F(NodeEmitterTest, NestBlockMapListNode) {
mapNode.SetStyle(EmitterStyle::Block); mapNode.SetStyle(EmitterStyle::Block);
mapNode["position"] = node; mapNode["position"] = node;
ExpectOutput("position:\n - 1.01\n - 2.01\n - 3.01", mapNode); ExpectOutput(
"position:\n - 1.01\n - 2.0099999999999998\n - 3.0099999999999998",
mapNode);
} }
TEST_F(NodeEmitterTest, NestFlowMapListNode) { TEST_F(NodeEmitterTest, NestFlowMapListNode) {
@ -511,7 +528,8 @@ TEST_F(NodeEmitterTest, NestFlowMapListNode) {
mapNode.SetStyle(EmitterStyle::Flow); mapNode.SetStyle(EmitterStyle::Flow);
mapNode["position"] = node; mapNode["position"] = node;
ExpectOutput("{position: [1.01, 2.01, 3.01]}", mapNode); ExpectOutput("{position: [1.01, 2.0099999999999998, 3.0099999999999998]}",
mapNode);
} }
} }
} }