Merge 5224a3563d into 5d5bb52ec2
This commit is contained in:
commit
cbc64faef3
@ -7,45 +7,139 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <vector>
|
#include <array>
|
||||||
|
#include <bitset>
|
||||||
|
#include <deque>
|
||||||
|
#include <forward_list>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <set>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#include <tuple>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace YAML {
|
namespace YAML {
|
||||||
template <typename Seq>
|
|
||||||
inline Emitter& EmitSeq(Emitter& emitter, const Seq& seq) {
|
namespace detail {
|
||||||
emitter << BeginSeq;
|
|
||||||
for (typename Seq::const_iterator it = seq.begin(); it != seq.end(); ++it)
|
template <class SequenceLike>
|
||||||
emitter << *it;
|
Emitter& EmitSeq(Emitter& emit, const SequenceLike& sequence) {
|
||||||
emitter << EndSeq;
|
emit << BeginSeq;
|
||||||
|
for (const auto& item : sequence)
|
||||||
|
emit << item;
|
||||||
|
emit << EndSeq;
|
||||||
|
return emit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class MapLike>
|
||||||
|
Emitter& EmitMap(Emitter& emit, const MapLike& map) {
|
||||||
|
emit << BeginMap;
|
||||||
|
for (const auto& kv : map)
|
||||||
|
emit << Key << kv.first << Value << kv.second;
|
||||||
|
emit << EndMap;
|
||||||
|
return emit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t Index = 0, typename... Args>
|
||||||
|
typename std::enable_if<Index == sizeof...(Args), Emitter&>::type EmitTuple(
|
||||||
|
Emitter& emit, const std::tuple<Args...>& /*tup*/) {
|
||||||
|
return emit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::size_t Index = 0, typename... Args>
|
||||||
|
typename std::enable_if<Index != sizeof...(Args), Emitter&>::type EmitTuple(
|
||||||
|
Emitter& emit, const std::tuple<Args...>& tup) {
|
||||||
|
emit << std::get<Index>(tup);
|
||||||
|
return EmitTuple<Index + 1, Args...>(emit, tup);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
// std::vector
|
||||||
|
template <class T, class Alloc>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::vector<T, Alloc>& t) {
|
||||||
|
return detail::EmitSeq(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::list
|
||||||
|
template <class T, class Alloc>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::list<T, Alloc>& t) {
|
||||||
|
return detail::EmitSeq(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::deque
|
||||||
|
template <class T, class Alloc>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::deque<T, Alloc>& t) {
|
||||||
|
return detail::EmitSeq(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::forward_list
|
||||||
|
template <class T, class Alloc>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::forward_list<T, Alloc>& t) {
|
||||||
|
return detail::EmitSeq(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::array
|
||||||
|
template <class T, std::size_t N>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::array<T, N>& t) {
|
||||||
|
return detail::EmitSeq(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::map
|
||||||
|
template <class Key, class T, class Compare, class Alloc>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::map<Key, T, Compare, Alloc>& t) {
|
||||||
|
return detail::EmitMap(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::unordered_map
|
||||||
|
template <class Key, class T, class Hash, class KeyEqual, class Alloc>
|
||||||
|
Emitter& operator<<(
|
||||||
|
Emitter& emit, const std::unordered_map<Key, T, Hash, KeyEqual, Alloc>& t) {
|
||||||
|
return detail::EmitMap(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::set
|
||||||
|
template <class Key, class Compare, class Alloc>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::set<Key, Compare, Alloc>& t) {
|
||||||
|
return detail::EmitSeq(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::unordered_set
|
||||||
|
template <class Key, class Hash, class KeyEqual, class Alloc>
|
||||||
|
Emitter& operator<<(Emitter& emit,
|
||||||
|
const std::unordered_set<Key, Hash, KeyEqual, Alloc>& t) {
|
||||||
|
return detail::EmitSeq(emit, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::bitset
|
||||||
|
template <std::size_t N>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::bitset<N>& bits) {
|
||||||
|
return emit << bits.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::pair
|
||||||
|
template <class First, class Second>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::pair<First, Second>& pair) {
|
||||||
|
emit << BeginSeq << pair.first << pair.second << EndSeq;
|
||||||
|
return emit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::tuple
|
||||||
|
template <typename... Args>
|
||||||
|
Emitter& operator<<(Emitter& emit, const std::tuple<Args...>& tup) {
|
||||||
|
emit << BeginSeq;
|
||||||
|
detail::EmitTuple(emit, tup);
|
||||||
|
emit << EndSeq;
|
||||||
|
return emit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::tuple -- empty
|
||||||
|
inline Emitter& operator<<(Emitter& emitter, const std::tuple<>& /*tup*/) {
|
||||||
|
emitter << Null;
|
||||||
return emitter;
|
return emitter;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
} // namespace YAML
|
||||||
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;
|
|
||||||
emitter << BeginMap;
|
|
||||||
for (typename map::const_iterator it = m.begin(); it != m.end(); ++it)
|
|
||||||
emitter << Key << it->first << Value << it->second;
|
|
||||||
emitter << EndMap;
|
|
||||||
return emitter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
#endif // STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|
||||||
|
|||||||
@ -3,6 +3,24 @@
|
|||||||
#include "yaml-cpp/yaml.h" // IWYU pragma: keep
|
#include "yaml-cpp/yaml.h" // IWYU pragma: keep
|
||||||
#include "gtest/gtest.h"
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
// user-defined type for emitter
|
||||||
|
struct Foo {
|
||||||
|
Foo() : x(0) {}
|
||||||
|
Foo(int x_, const std::string& bar_) : x(x_), bar(bar_) {}
|
||||||
|
|
||||||
|
int x;
|
||||||
|
std::string bar;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Provide overload for user-defined type.
|
||||||
|
YAML::Emitter& operator<<(YAML::Emitter& out, const Foo& foo) {
|
||||||
|
out << YAML::BeginMap;
|
||||||
|
out << YAML::Key << "x" << YAML::Value << foo.x;
|
||||||
|
out << YAML::Key << "bar" << YAML::Value << foo.bar;
|
||||||
|
out << YAML::EndMap;
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
namespace YAML {
|
namespace YAML {
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -497,7 +515,6 @@ TEST_F(EmitterTest, ComplexDoc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(EmitterTest, STLContainers) {
|
TEST_F(EmitterTest, STLContainers) {
|
||||||
out << BeginSeq;
|
|
||||||
std::vector<int> primes;
|
std::vector<int> primes;
|
||||||
primes.push_back(2);
|
primes.push_back(2);
|
||||||
primes.push_back(3);
|
primes.push_back(3);
|
||||||
@ -505,14 +522,267 @@ TEST_F(EmitterTest, STLContainers) {
|
|||||||
primes.push_back(7);
|
primes.push_back(7);
|
||||||
primes.push_back(11);
|
primes.push_back(11);
|
||||||
primes.push_back(13);
|
primes.push_back(13);
|
||||||
out << Flow << primes;
|
|
||||||
std::map<std::string, int> ages;
|
std::map<std::string, int> ages;
|
||||||
ages["Daniel"] = 26;
|
ages["Daniel"] = 26;
|
||||||
ages["Jesse"] = 24;
|
ages["Jesse"] = 24;
|
||||||
out << ages;
|
|
||||||
out << EndSeq;
|
|
||||||
|
|
||||||
ExpectEmit("- [2, 3, 5, 7, 11, 13]\n- Daniel: 26\n Jesse: 24");
|
// out << BeginSeq << Flow << primes << ages << EndSeq;
|
||||||
|
// ExpectEmit("- [2, 3, 5, 7, 11, 13]\n- Daniel: 26\n Jesse: 24");
|
||||||
|
|
||||||
|
const auto primesAndAges = std::make_pair(primes, ages);
|
||||||
|
out << Flow << primesAndAges; // <-- note recursiveness of `<<`
|
||||||
|
ExpectEmit("[[2, 3, 5, 7, 11, 13], {Daniel: 26, Jesse: 24}]");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdSet) {
|
||||||
|
std::set<int> primes;
|
||||||
|
primes.insert(2);
|
||||||
|
primes.insert(3);
|
||||||
|
primes.insert(5);
|
||||||
|
primes.insert(7);
|
||||||
|
primes.insert(11);
|
||||||
|
primes.insert(13);
|
||||||
|
out << Flow << primes;
|
||||||
|
ExpectEmit("[2, 3, 5, 7, 11, 13]");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, NestedSTLContainersPart1) {
|
||||||
|
|
||||||
|
std::vector<std::vector<int>> matrix;
|
||||||
|
matrix.push_back(std::vector<int>{1, 0, 0});
|
||||||
|
matrix.push_back(std::vector<int>{0, 1, 0});
|
||||||
|
matrix.push_back(std::vector<int>{0, 0, 1});
|
||||||
|
out << Block << matrix;
|
||||||
|
|
||||||
|
ExpectEmit(R"(-
|
||||||
|
- 1
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
-
|
||||||
|
- 0
|
||||||
|
- 1
|
||||||
|
- 0
|
||||||
|
-
|
||||||
|
- 0
|
||||||
|
- 0
|
||||||
|
- 1)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, NestedSTLContainersPart2) {
|
||||||
|
|
||||||
|
std::map<std::string, std::map<std::string, int>> data;
|
||||||
|
data["zero"] = std::map<std::string, int>{{"john", 0}, {"doe", 1}};
|
||||||
|
data["one"] = std::map<std::string, int>{{"hello", 2}, {"world", 3}};
|
||||||
|
out << data;
|
||||||
|
|
||||||
|
// when we iterate over a map we iterate over the sorted keys.
|
||||||
|
ExpectEmit("one:\n hello: 2\n world: 3\nzero:\n doe: 1\n john: 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, NestedSTLContainersPart3) {
|
||||||
|
|
||||||
|
std::map<std::string, std::pair<std::forward_list<std::bitset<2>>,
|
||||||
|
std::vector<std::deque<Foo>>>>
|
||||||
|
data;
|
||||||
|
|
||||||
|
std::bitset<2> bits;
|
||||||
|
bits.set(0, true);
|
||||||
|
bits.set(1, false);
|
||||||
|
|
||||||
|
std::forward_list<std::bitset<2>> thelist;
|
||||||
|
thelist.push_front(bits);
|
||||||
|
|
||||||
|
std::deque<Foo> thedeque;
|
||||||
|
thedeque.push_back(Foo(0, "hello"));
|
||||||
|
thedeque.push_back(Foo(1, "world"));
|
||||||
|
|
||||||
|
std::vector<std::deque<Foo>> thevector;
|
||||||
|
thevector.push_back(thedeque);
|
||||||
|
thedeque[1] = Foo(2, "john");
|
||||||
|
thedeque.push_back(Foo(3, "kate"));
|
||||||
|
thevector.push_back(thedeque);
|
||||||
|
|
||||||
|
data["one"] = std::make_pair(thelist, thevector);
|
||||||
|
|
||||||
|
thelist.clear();
|
||||||
|
bits.set(1, false);
|
||||||
|
thelist.push_front(bits);
|
||||||
|
bits.set(1, true);
|
||||||
|
thelist.push_front(bits);
|
||||||
|
|
||||||
|
thedeque.push_front(Foo(4, "mary"));
|
||||||
|
thedeque.push_front(Foo(5, "bob"));
|
||||||
|
thedeque.push_back(Foo(6, "ellis"));
|
||||||
|
|
||||||
|
thevector.push_back(thedeque);
|
||||||
|
|
||||||
|
data["two"] = std::make_pair(thelist, thevector);
|
||||||
|
|
||||||
|
out << data;
|
||||||
|
|
||||||
|
// something crazy that hopefully nobody will ever use in practise but at
|
||||||
|
// least this works.
|
||||||
|
// NOTE: output seems overly verbose (what with the redundant newlines)
|
||||||
|
ExpectEmit(R"(one:
|
||||||
|
-
|
||||||
|
- 01
|
||||||
|
-
|
||||||
|
-
|
||||||
|
- x: 0
|
||||||
|
bar: hello
|
||||||
|
- x: 1
|
||||||
|
bar: world
|
||||||
|
-
|
||||||
|
- x: 0
|
||||||
|
bar: hello
|
||||||
|
- x: 2
|
||||||
|
bar: john
|
||||||
|
- x: 3
|
||||||
|
bar: kate
|
||||||
|
two:
|
||||||
|
-
|
||||||
|
- 11
|
||||||
|
- 01
|
||||||
|
-
|
||||||
|
-
|
||||||
|
- x: 0
|
||||||
|
bar: hello
|
||||||
|
- x: 1
|
||||||
|
bar: world
|
||||||
|
-
|
||||||
|
- x: 0
|
||||||
|
bar: hello
|
||||||
|
- x: 2
|
||||||
|
bar: john
|
||||||
|
- x: 3
|
||||||
|
bar: kate
|
||||||
|
-
|
||||||
|
- x: 5
|
||||||
|
bar: bob
|
||||||
|
- x: 4
|
||||||
|
bar: mary
|
||||||
|
- x: 0
|
||||||
|
bar: hello
|
||||||
|
- x: 2
|
||||||
|
bar: john
|
||||||
|
- x: 3
|
||||||
|
bar: kate
|
||||||
|
- x: 6
|
||||||
|
bar: ellis)");
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class CustomAllocator : public std::allocator<T> {};
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdVectorCustomAllocator) {
|
||||||
|
std::vector<int, CustomAllocator<int>> primes;
|
||||||
|
primes.push_back(2);
|
||||||
|
primes.push_back(3);
|
||||||
|
primes.push_back(5);
|
||||||
|
primes.push_back(7);
|
||||||
|
primes.push_back(11);
|
||||||
|
primes.push_back(13);
|
||||||
|
out << primes;
|
||||||
|
ExpectEmit("- 2\n- 3\n- 5\n- 7\n- 11\n- 13");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdMapCustomAllocator) {
|
||||||
|
std::map<std::string, int, std::less<std::string>,
|
||||||
|
CustomAllocator<std::pair<const std::string, int>>>
|
||||||
|
primes;
|
||||||
|
primes["two"] = 2;
|
||||||
|
primes["three"] = 3;
|
||||||
|
primes["five"] = 5;
|
||||||
|
primes["seven"] = 7;
|
||||||
|
primes["eleven"] = 11;
|
||||||
|
primes["thirteen"] = 13;
|
||||||
|
out << primes;
|
||||||
|
|
||||||
|
// NOTE: map runs through its element sorted.
|
||||||
|
ExpectEmit("eleven: 11\nfive: 5\nseven: 7\nthirteen: 13\nthree: 3\ntwo: 2");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize0) {
|
||||||
|
out << std::tuple<>();
|
||||||
|
ExpectEmit("~");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize1) {
|
||||||
|
out << std::make_tuple(42);
|
||||||
|
ExpectEmit("- 42");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize2) {
|
||||||
|
out << std::make_tuple(42, 3.141592f);
|
||||||
|
ExpectEmit("- 42\n- 3.141592");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize3) {
|
||||||
|
out << std::make_tuple(42, 3.141592f, "hello");
|
||||||
|
ExpectEmit("- 42\n- 3.141592\n- hello");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize4) {
|
||||||
|
out << std::make_tuple(42, 3.141592f, "hello", "world");
|
||||||
|
ExpectEmit("- 42\n- 3.141592\n- hello\n- world");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize5) {
|
||||||
|
out << std::make_tuple(42, 3.141592f, "hello", "world",
|
||||||
|
std::vector<int>{2, 3, 5, 7});
|
||||||
|
ExpectEmit(
|
||||||
|
R"(- 42
|
||||||
|
- 3.141592
|
||||||
|
- hello
|
||||||
|
- world
|
||||||
|
-
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 5
|
||||||
|
- 7)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize6) {
|
||||||
|
out << std::make_tuple(42, 3.141592f, "hello", "world",
|
||||||
|
std::vector<int>{2, 3, 5, 7},
|
||||||
|
std::map<int, int>{{1, 1}, {2, 4}, {3, 9}, {4, 16}});
|
||||||
|
|
||||||
|
ExpectEmit(R"(- 42
|
||||||
|
- 3.141592
|
||||||
|
- hello
|
||||||
|
- world
|
||||||
|
-
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 5
|
||||||
|
- 7
|
||||||
|
- 1: 1
|
||||||
|
2: 4
|
||||||
|
3: 9
|
||||||
|
4: 16)");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(EmitterTest, StdTupleSize7) {
|
||||||
|
out << std::make_tuple(
|
||||||
|
42, 3.141592f, "hello", "world", std::vector<int>{2, 3, 5, 7},
|
||||||
|
std::map<int, int>{{1, 1}, {2, 4}, {3, 9}, {4, 16}}, Foo(10, "foo"));
|
||||||
|
|
||||||
|
ExpectEmit(R"(- 42
|
||||||
|
- 3.141592
|
||||||
|
- hello
|
||||||
|
- world
|
||||||
|
-
|
||||||
|
- 2
|
||||||
|
- 3
|
||||||
|
- 5
|
||||||
|
- 7
|
||||||
|
- 1: 1
|
||||||
|
2: 4
|
||||||
|
3: 9
|
||||||
|
4: 16
|
||||||
|
- x: 10
|
||||||
|
bar: foo)");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(EmitterTest, SimpleComment) {
|
TEST_F(EmitterTest, SimpleComment) {
|
||||||
@ -658,22 +928,6 @@ TEST_F(EmitterTest, DoubleQuotedUnicode) {
|
|||||||
ExpectEmit("\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\"");
|
ExpectEmit("\"\x24 \xC2\xA2 \xE2\x82\xAC \xF0\xA4\xAD\xA2\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Foo {
|
|
||||||
Foo() : x(0) {}
|
|
||||||
Foo(int x_, const std::string& bar_) : x(x_), bar(bar_) {}
|
|
||||||
|
|
||||||
int x;
|
|
||||||
std::string bar;
|
|
||||||
};
|
|
||||||
|
|
||||||
Emitter& operator<<(Emitter& out, const Foo& foo) {
|
|
||||||
out << BeginMap;
|
|
||||||
out << Key << "x" << Value << foo.x;
|
|
||||||
out << Key << "bar" << Value << foo.bar;
|
|
||||||
out << EndMap;
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_F(EmitterTest, UserType) {
|
TEST_F(EmitterTest, UserType) {
|
||||||
out << BeginSeq;
|
out << BeginSeq;
|
||||||
out << Foo(5, "hello");
|
out << Foo(5, "hello");
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user