This commit is contained in:
MacroBull 2020-05-27 09:40:54 +08:00 committed by GitHub
commit c6ad273665
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 215 additions and 60 deletions

View File

@ -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

View File

@ -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

View File

@ -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 << "}";
}

View File

@ -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(); }

View File

@ -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"