Merge d16ecb63f6 into 6701275f19
This commit is contained in:
commit
c6ad273665
@ -269,10 +269,16 @@ inline Emitter& operator<<(Emitter& emitter, EMITTER_MANIP value) {
|
||||
inline Emitter& operator<<(Emitter& emitter, _Indent indent) {
|
||||
return emitter.SetLocalIndent(indent);
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, _Precision precision) {
|
||||
return emitter.SetLocalPrecision(precision);
|
||||
}
|
||||
|
||||
inline Emitter& operator<<(Emitter& emitter, std::nullptr_t) {
|
||||
return emitter << _Null{};
|
||||
}
|
||||
inline Emitter& operator<<(Emitter& emitter, const void* v) {
|
||||
return emitter.WriteIntegralType(v);
|
||||
}
|
||||
} // namespace YAML
|
||||
|
||||
#endif // EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
@ -7,45 +7,188 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <complex>
|
||||
#include <sstream>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include "emitter.h"
|
||||
|
||||
namespace YAML {
|
||||
template <typename Seq>
|
||||
inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <bool P, typename T = void>
|
||||
using enable_if_t = typename std::enable_if<P, T>::type;
|
||||
|
||||
template <typename... Args>
|
||||
struct make_void {
|
||||
using type = void;
|
||||
};
|
||||
|
||||
template <typename... Args>
|
||||
using void_t = typename make_void<Args...>::type;
|
||||
|
||||
template <typename T, typename Test = void>
|
||||
struct is_std_iterable : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_std_iterable<
|
||||
T, enable_if_t<std::is_same<decltype(std::begin(std::declval<T>())),
|
||||
decltype(std::end(std::declval<T>()))>::value>>
|
||||
: std::true_type {};
|
||||
|
||||
#define TRAITS_DECL_CLASS_HAS_TYPE(name) \
|
||||
template <class T, typename Test = void> \
|
||||
struct has_type_##name : std::false_type {}; \
|
||||
template <class T> \
|
||||
struct has_type_##name<T, void_t<typename T::name>> : std::true_type {};
|
||||
|
||||
TRAITS_DECL_CLASS_HAS_TYPE(element_type)
|
||||
TRAITS_DECL_CLASS_HAS_TYPE(mapped_type)
|
||||
|
||||
#undef TRAITS_DECL_CLASS_HAS_TYPE
|
||||
|
||||
template <typename T>
|
||||
inline enable_if_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, unsigned char>::value, int>
|
||||
as_numeric(const T& value) {
|
||||
return static_cast<int>(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline enable_if_t<
|
||||
!(std::is_same<T, char>::value || std::is_same<T, unsigned char>::value), T>
|
||||
as_numeric(const T& value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
template <typename T, size_t N>
|
||||
struct sequential_printer {
|
||||
template <typename S>
|
||||
inline static void print(S& stream, const T& value) {
|
||||
const auto i = N - 1;
|
||||
|
||||
sequential_printer<T, i>::print(stream, value);
|
||||
stream << std::get<i>(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct sequential_printer<T, 1> {
|
||||
template <typename S>
|
||||
inline static void print(S& stream, const T& value) {
|
||||
stream << std::get<0>(value);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename E, typename T>
|
||||
inline E& emit_sequence(E& emitter, const T& value) {
|
||||
emitter << BeginSeq;
|
||||
for (typename Seq::const_iterator it = seq.begin(); it != seq.end(); ++it)
|
||||
emitter << *it;
|
||||
emitter << EndSeq;
|
||||
return emitter;
|
||||
for (const auto& item : value) {
|
||||
emitter << item;
|
||||
}
|
||||
return emitter << EndSeq;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::vector<T>& v) {
|
||||
return EmitSeq(emitter, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::list<T>& v) {
|
||||
return EmitSeq(emitter, v);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::set<T>& v) {
|
||||
return EmitSeq(emitter, v);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::map<K, V>& m) {
|
||||
typedef typename std::map<K, V> map;
|
||||
template <typename E, typename T>
|
||||
inline E& emit_mapping(E& emitter, const T& value) {
|
||||
emitter << BeginMap;
|
||||
for (typename map::const_iterator it = m.begin(); it != m.end(); ++it)
|
||||
emitter << Key << it->first << Value << it->second;
|
||||
emitter << EndMap;
|
||||
for (const auto& key_value : value) {
|
||||
emitter << Key << std::get<0>(key_value) << Value << std::get<1>(key_value);
|
||||
}
|
||||
return emitter << EndMap;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& emit_streamable(Emitter& emitter, const T& value,
|
||||
std::stringstream* stream = nullptr) {
|
||||
std::stringstream stream_fallback;
|
||||
if (stream == nullptr) {
|
||||
stream = &stream_fallback;
|
||||
} else {
|
||||
stream->str("");
|
||||
}
|
||||
|
||||
*stream << value;
|
||||
return emitter << stream->str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& emit_complex(Emitter& emitter, const T& real, const T& imag) {
|
||||
#ifndef YAML_EMITTER_NO_COMPLEX
|
||||
|
||||
std::stringstream ss;
|
||||
ss << as_numeric(real) << '+' << as_numeric(imag) << 'j';
|
||||
emitter << LocalTag("complex") << ss.str();
|
||||
return emitter;
|
||||
|
||||
#else
|
||||
|
||||
return emitter << Flow << BeginSeq << as_numeric(real) << as_numeric(imag)
|
||||
<< EndSeq;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
//// std::complex
|
||||
|
||||
template <typename T>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::complex<T>& value) {
|
||||
// return detail::emit_streamable(emitter << LocalTag("complex"), value);
|
||||
//// stl style
|
||||
return detail::emit_complex(emitter, value.real(), value.imag());
|
||||
}
|
||||
|
||||
//// std::pair
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::pair<T1, T2>& value) {
|
||||
return emitter << Flow << BeginSeq << value.first << value.second << EndSeq;
|
||||
}
|
||||
|
||||
//// std::tuple
|
||||
|
||||
template <typename... Args>
|
||||
inline Emitter& operator<<(Emitter& emitter, const std::tuple<Args...>& value) {
|
||||
emitter << Flow << BeginSeq;
|
||||
detail::sequential_printer<std::tuple<Args...>, sizeof...(Args)>::print(
|
||||
emitter, value);
|
||||
return emitter << EndSeq;
|
||||
}
|
||||
|
||||
//// std::array, std::vector, std::deque, std::list, std::forward_list
|
||||
//// std::set, std::multiset, std::unordered_set
|
||||
|
||||
template <typename T>
|
||||
inline detail::enable_if_t<detail::is_std_iterable<T>::value &&
|
||||
!detail::has_type_mapped_type<T>::value,
|
||||
Emitter&>
|
||||
operator<<(Emitter& emitter, const T& value) {
|
||||
return detail::emit_sequence(emitter, value);
|
||||
}
|
||||
|
||||
//// std::map, std::unordered_map
|
||||
|
||||
template <typename T>
|
||||
inline detail::enable_if_t<detail::is_std_iterable<T>::value &&
|
||||
detail::has_type_mapped_type<T>::value,
|
||||
Emitter&>
|
||||
operator<<(Emitter& emitter, const T& value) {
|
||||
return detail::emit_mapping(emitter, value);
|
||||
}
|
||||
|
||||
//// std::unique_ptr, std::shared_ptr
|
||||
|
||||
template <typename T>
|
||||
inline detail::enable_if_t<detail::has_type_element_type<T>::value, Emitter&>
|
||||
operator<<(Emitter& emitter, const T& value) {
|
||||
return emitter << value.get();
|
||||
}
|
||||
|
||||
} // namespace YAML
|
||||
|
||||
#endif // STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||
|
||||
@ -198,6 +198,7 @@ void Emitter::EmitEndSeq() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
bool need_left_brace = !m_pState->HasBegunNode() || m_stream.comment();
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_pState->ForceFlow();
|
||||
|
||||
@ -205,7 +206,7 @@ void Emitter::EmitEndSeq() {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(m_pState->CurIndent());
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
if (m_pState->CurGroupChildCount() == 0 && need_left_brace)
|
||||
m_stream << "[";
|
||||
m_stream << "]";
|
||||
}
|
||||
@ -228,6 +229,7 @@ void Emitter::EmitEndMap() {
|
||||
if (!good())
|
||||
return;
|
||||
|
||||
bool need_left_brace = !m_pState->HasBegunNode() || m_stream.comment();
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
m_pState->ForceFlow();
|
||||
|
||||
@ -235,7 +237,7 @@ void Emitter::EmitEndMap() {
|
||||
if (m_stream.comment())
|
||||
m_stream << "\n";
|
||||
m_stream << IndentTo(m_pState->CurIndent());
|
||||
if (m_pState->CurGroupChildCount() == 0)
|
||||
if (m_pState->CurGroupChildCount() == 0 && need_left_brace)
|
||||
m_stream << "{";
|
||||
m_stream << "}";
|
||||
}
|
||||
|
||||
@ -211,11 +211,15 @@ bool EmitterState::CurGroupLongKey() const {
|
||||
}
|
||||
|
||||
std::size_t EmitterState::LastIndent() const {
|
||||
if (m_groups.size() <= 1) {
|
||||
return 0;
|
||||
}
|
||||
if (HasBegunNode()) {
|
||||
return m_curIndent + (m_groups.empty() ? m_indent.get() : m_groups.back()->indent);
|
||||
} else {
|
||||
if (m_groups.size() <= 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return m_curIndent - m_groups[m_groups.size() - 2]->indent;
|
||||
return m_curIndent - m_groups[m_groups.size() - 2]->indent;
|
||||
}
|
||||
}
|
||||
|
||||
void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); }
|
||||
|
||||
@ -566,7 +566,7 @@ TEST_F(EmitterTest, InitialCommentWithDocIndicator) {
|
||||
TEST_F(EmitterTest, CommentInFlowSeq) {
|
||||
out << Flow << BeginSeq << "foo" << Comment("foo!") << "bar" << EndSeq;
|
||||
|
||||
ExpectEmit("[foo, # foo!\nbar]");
|
||||
ExpectEmit("[foo, # foo!\n bar]");
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, CommentInFlowMap) {
|
||||
@ -577,7 +577,7 @@ TEST_F(EmitterTest, CommentInFlowMap) {
|
||||
out << EndMap;
|
||||
|
||||
ExpectEmit(
|
||||
"{foo: foo value, bar: bar value, # bar!\nbaz: baz value, # baz!\n}");
|
||||
"{foo: foo value, bar: bar value, # bar!\n baz: baz value, # baz!\n}");
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, Indentation) {
|
||||
@ -743,7 +743,7 @@ TEST_F(EmitterTest, NewlineInFlowSequence) {
|
||||
out << "a" << Newline << "b"
|
||||
<< "c" << Newline << "d";
|
||||
out << EndSeq;
|
||||
ExpectEmit("[a,\nb, c,\nd]");
|
||||
ExpectEmit("[a,\n b, c,\n d]");
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, NewlineInBlockMap) {
|
||||
@ -760,7 +760,7 @@ TEST_F(EmitterTest, NewlineInFlowMap) {
|
||||
out << Key << "a" << Value << "foo" << Newline;
|
||||
out << Key << "b" << Value << "bar";
|
||||
out << EndMap;
|
||||
ExpectEmit("{a: foo,\nb: bar}");
|
||||
ExpectEmit("{a: foo,\n b: bar}");
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, LotsOfNewlines) {
|
||||
@ -971,28 +971,28 @@ TEST_F(EmitterTest, QuoteNull) {
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, ValueOfDoubleQuote) {
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "foo" << YAML::Value << '"';
|
||||
out << YAML::EndMap;
|
||||
out << BeginMap;
|
||||
out << Key << "foo" << Value << '"';
|
||||
out << EndMap;
|
||||
|
||||
ExpectEmit("foo: \"\\\"\"");
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, ValueOfBackslash) {
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "foo" << YAML::Value << '\\';
|
||||
out << YAML::EndMap;
|
||||
out << BeginMap;
|
||||
out << Key << "foo" << Value << '\\';
|
||||
out << EndMap;
|
||||
|
||||
ExpectEmit("foo: \"\\\\\"");
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, Infinity) {
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "foo" << YAML::Value
|
||||
out << BeginMap;
|
||||
out << Key << "foo" << Value
|
||||
<< std::numeric_limits<float>::infinity();
|
||||
out << YAML::Key << "bar" << YAML::Value
|
||||
out << Key << "bar" << Value
|
||||
<< std::numeric_limits<double>::infinity();
|
||||
out << YAML::EndMap;
|
||||
out << EndMap;
|
||||
|
||||
ExpectEmit(
|
||||
"foo: .inf\n"
|
||||
@ -1000,12 +1000,12 @@ TEST_F(EmitterTest, Infinity) {
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, NegInfinity) {
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "foo" << YAML::Value
|
||||
out << BeginMap;
|
||||
out << Key << "foo" << Value
|
||||
<< -std::numeric_limits<float>::infinity();
|
||||
out << YAML::Key << "bar" << YAML::Value
|
||||
out << Key << "bar" << Value
|
||||
<< -std::numeric_limits<double>::infinity();
|
||||
out << YAML::EndMap;
|
||||
out << EndMap;
|
||||
|
||||
ExpectEmit(
|
||||
"foo: -.inf\n"
|
||||
@ -1013,12 +1013,12 @@ TEST_F(EmitterTest, NegInfinity) {
|
||||
}
|
||||
|
||||
TEST_F(EmitterTest, NaN) {
|
||||
out << YAML::BeginMap;
|
||||
out << YAML::Key << "foo" << YAML::Value
|
||||
out << BeginMap;
|
||||
out << Key << "foo" << Value
|
||||
<< std::numeric_limits<float>::quiet_NaN();
|
||||
out << YAML::Key << "bar" << YAML::Value
|
||||
out << Key << "bar" << Value
|
||||
<< std::numeric_limits<double>::quiet_NaN();
|
||||
out << YAML::EndMap;
|
||||
out << EndMap;
|
||||
|
||||
ExpectEmit(
|
||||
"foo: .nan\n"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user