Line data Source code
1 : #ifndef NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
2 : #define NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
3 :
4 : #if defined(_MSC_VER) || \
5 : (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \
6 : (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4
7 : #pragma once
8 : #endif
9 :
10 : #include <array>
11 : #include <cmath>
12 : #include <limits>
13 : #include <list>
14 : #include <map>
15 : #include <sstream>
16 : #include <type_traits>
17 : #include <vector>
18 :
19 : #include "yaml-cpp/binary.h"
20 : #include "yaml-cpp/node/impl.h"
21 : #include "yaml-cpp/node/iterator.h"
22 : #include "yaml-cpp/node/node.h"
23 : #include "yaml-cpp/node/type.h"
24 : #include "yaml-cpp/null.h"
25 :
26 :
27 : namespace YAML {
28 : class Binary;
29 : struct _Null;
30 : template <typename T>
31 : struct convert;
32 : } // namespace YAML
33 :
34 : namespace YAML {
35 : namespace conversion {
36 0 : inline bool IsInfinity(const std::string& input) {
37 0 : return input == ".inf" || input == ".Inf" || input == ".INF" ||
38 0 : input == "+.inf" || input == "+.Inf" || input == "+.INF";
39 : }
40 :
41 0 : inline bool IsNegativeInfinity(const std::string& input) {
42 0 : return input == "-.inf" || input == "-.Inf" || input == "-.INF";
43 : }
44 :
45 0 : inline bool IsNaN(const std::string& input) {
46 0 : return input == ".nan" || input == ".NaN" || input == ".NAN";
47 : }
48 : }
49 :
50 : // Node
51 : template <>
52 : struct convert<Node> {
53 : static Node encode(const Node& rhs) { return rhs; }
54 :
55 589 : static bool decode(const Node& node, Node& rhs) {
56 589 : rhs.reset(node);
57 589 : return true;
58 : }
59 : };
60 :
61 : // std::string
62 : template <>
63 : struct convert<std::string> {
64 : static Node encode(const std::string& rhs) { return Node(rhs); }
65 :
66 29918 : static bool decode(const Node& node, std::string& rhs) {
67 29918 : if (!node.IsScalar())
68 0 : return false;
69 29918 : rhs = node.Scalar();
70 29918 : return true;
71 : }
72 : };
73 :
74 : // C-strings can only be encoded
75 : template <>
76 : struct convert<const char*> {
77 : static Node encode(const char* rhs) { return Node(rhs); }
78 : };
79 :
80 : template <>
81 : struct convert<char*> {
82 : static Node encode(const char* rhs) { return Node(rhs); }
83 : };
84 :
85 : template <std::size_t N>
86 : struct convert<char[N]> {
87 8616 : static Node encode(const char* rhs) { return Node(rhs); }
88 : };
89 :
90 : template <>
91 : struct convert<_Null> {
92 : static Node encode(const _Null& /* rhs */) { return Node(); }
93 :
94 : static bool decode(const Node& node, _Null& /* rhs */) {
95 : return node.IsNull();
96 : }
97 : };
98 :
99 : namespace conversion {
100 : template <typename T>
101 : typename std::enable_if< std::is_floating_point<T>::value, void>::type
102 : inner_encode(const T& rhs, std::stringstream& stream){
103 : if (std::isnan(rhs)) {
104 : stream << ".nan";
105 : } else if (std::isinf(rhs)) {
106 : if (std::signbit(rhs)) {
107 : stream << "-.inf";
108 : } else {
109 : stream << ".inf";
110 : }
111 : } else {
112 : stream << rhs;
113 : }
114 : }
115 :
116 : template <typename T>
117 : typename std::enable_if<!std::is_floating_point<T>::value, void>::type
118 : inner_encode(const T& rhs, std::stringstream& stream){
119 : stream << rhs;
120 : }
121 :
122 : template <typename T>
123 : typename std::enable_if<(std::is_same<T, unsigned char>::value ||
124 : std::is_same<T, signed char>::value), bool>::type
125 : ConvertStreamTo(std::stringstream& stream, T& rhs) {
126 : int num;
127 : if ((stream >> std::noskipws >> num) && (stream >> std::ws).eof()) {
128 : if (num >= (std::numeric_limits<T>::min)() &&
129 : num <= (std::numeric_limits<T>::max)()) {
130 : rhs = (T)num;
131 : return true;
132 : }
133 : }
134 : return false;
135 : }
136 :
137 : template <typename T>
138 : typename std::enable_if<!(std::is_same<T, unsigned char>::value ||
139 : std::is_same<T, signed char>::value), bool>::type
140 360 : ConvertStreamTo(std::stringstream& stream, T& rhs) {
141 360 : if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) {
142 360 : return true;
143 : }
144 0 : return false;
145 : }
146 : }
147 :
148 : #define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \
149 : template <> \
150 : struct convert<type> { \
151 : \
152 : static Node encode(const type& rhs) { \
153 : std::stringstream stream; \
154 : stream.precision(std::numeric_limits<type>::max_digits10); \
155 : conversion::inner_encode(rhs, stream); \
156 : return Node(stream.str()); \
157 : } \
158 : \
159 : static bool decode(const Node& node, type& rhs) { \
160 : if (node.Type() != NodeType::Scalar) { \
161 : return false; \
162 : } \
163 : const std::string& input = node.Scalar(); \
164 : std::stringstream stream(input); \
165 : stream.unsetf(std::ios::dec); \
166 : if ((stream.peek() == '-') && std::is_unsigned<type>::value) { \
167 : return false; \
168 : } \
169 : if (conversion::ConvertStreamTo(stream, rhs)) { \
170 : return true; \
171 : } \
172 : if (std::numeric_limits<type>::has_infinity) { \
173 : if (conversion::IsInfinity(input)) { \
174 : rhs = std::numeric_limits<type>::infinity(); \
175 : return true; \
176 : } else if (conversion::IsNegativeInfinity(input)) { \
177 : rhs = negative_op std::numeric_limits<type>::infinity(); \
178 : return true; \
179 : } \
180 : } \
181 : \
182 : if (std::numeric_limits<type>::has_quiet_NaN) { \
183 : if (conversion::IsNaN(input)) { \
184 : rhs = std::numeric_limits<type>::quiet_NaN(); \
185 : return true; \
186 : } \
187 : } \
188 : \
189 : return false; \
190 : } \
191 : }
192 :
193 : #define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \
194 : YAML_DEFINE_CONVERT_STREAMABLE(type, -)
195 :
196 : #define YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(type) \
197 : YAML_DEFINE_CONVERT_STREAMABLE(type, +)
198 :
199 300 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int);
200 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(short);
201 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long);
202 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long long);
203 0 : YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned);
204 0 : YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned short);
205 : YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long);
206 : YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long long);
207 :
208 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(char);
209 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(signed char);
210 : YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned char);
211 :
212 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(float);
213 60 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(double);
214 : YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long double);
215 :
216 : #undef YAML_DEFINE_CONVERT_STREAMABLE_SIGNED
217 : #undef YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED
218 : #undef YAML_DEFINE_CONVERT_STREAMABLE
219 :
220 : // bool
221 : template <>
222 : struct convert<bool> {
223 : static Node encode(bool rhs) { return rhs ? Node("true") : Node("false"); }
224 :
225 : YAML_CPP_API static bool decode(const Node& node, bool& rhs);
226 : };
227 :
228 : // std::map
229 : template <typename K, typename V, typename C, typename A>
230 : struct convert<std::map<K, V, C, A>> {
231 : static Node encode(const std::map<K, V, C, A>& rhs) {
232 : Node node(NodeType::Map);
233 : for (const auto& element : rhs)
234 : node.force_insert(element.first, element.second);
235 : return node;
236 : }
237 :
238 : static bool decode(const Node& node, std::map<K, V, C, A>& rhs) {
239 : if (!node.IsMap())
240 : return false;
241 :
242 : rhs.clear();
243 : for (const auto& element : node)
244 : #if defined(__GNUC__) && __GNUC__ < 4
245 : // workaround for GCC 3:
246 : rhs[element.first.template as<K>()] = element.second.template as<V>();
247 : #else
248 : rhs[element.first.as<K>()] = element.second.as<V>();
249 : #endif
250 : return true;
251 : }
252 : };
253 :
254 : // std::vector
255 : template <typename T, typename A>
256 : struct convert<std::vector<T, A>> {
257 : static Node encode(const std::vector<T, A>& rhs) {
258 : Node node(NodeType::Sequence);
259 : for (const auto& element : rhs)
260 : node.push_back(element);
261 : return node;
262 : }
263 :
264 20 : static bool decode(const Node& node, std::vector<T, A>& rhs) {
265 20 : if (!node.IsSequence())
266 0 : return false;
267 :
268 20 : rhs.clear();
269 70 : for (const auto& element : node)
270 : #if defined(__GNUC__) && __GNUC__ < 4
271 : // workaround for GCC 3:
272 : rhs.push_back(element.template as<T>());
273 : #else
274 30 : rhs.push_back(element.as<T>());
275 : #endif
276 20 : return true;
277 : }
278 : };
279 :
280 : // std::list
281 : template <typename T, typename A>
282 : struct convert<std::list<T,A>> {
283 : static Node encode(const std::list<T,A>& rhs) {
284 : Node node(NodeType::Sequence);
285 : for (const auto& element : rhs)
286 : node.push_back(element);
287 : return node;
288 : }
289 :
290 : static bool decode(const Node& node, std::list<T,A>& rhs) {
291 : if (!node.IsSequence())
292 : return false;
293 :
294 : rhs.clear();
295 : for (const auto& element : node)
296 : #if defined(__GNUC__) && __GNUC__ < 4
297 : // workaround for GCC 3:
298 : rhs.push_back(element.template as<T>());
299 : #else
300 : rhs.push_back(element.as<T>());
301 : #endif
302 : return true;
303 : }
304 : };
305 :
306 : // std::array
307 : template <typename T, std::size_t N>
308 : struct convert<std::array<T, N>> {
309 : static Node encode(const std::array<T, N>& rhs) {
310 : Node node(NodeType::Sequence);
311 : for (const auto& element : rhs) {
312 : node.push_back(element);
313 : }
314 : return node;
315 : }
316 :
317 : static bool decode(const Node& node, std::array<T, N>& rhs) {
318 : if (!isNodeValid(node)) {
319 : return false;
320 : }
321 :
322 : for (auto i = 0u; i < node.size(); ++i) {
323 : #if defined(__GNUC__) && __GNUC__ < 4
324 : // workaround for GCC 3:
325 : rhs[i] = node[i].template as<T>();
326 : #else
327 : rhs[i] = node[i].as<T>();
328 : #endif
329 : }
330 : return true;
331 : }
332 :
333 : private:
334 : static bool isNodeValid(const Node& node) {
335 : return node.IsSequence() && node.size() == N;
336 : }
337 : };
338 :
339 : // std::pair
340 : template <typename T, typename U>
341 : struct convert<std::pair<T, U>> {
342 : static Node encode(const std::pair<T, U>& rhs) {
343 : Node node(NodeType::Sequence);
344 : node.push_back(rhs.first);
345 : node.push_back(rhs.second);
346 : return node;
347 : }
348 :
349 : static bool decode(const Node& node, std::pair<T, U>& rhs) {
350 : if (!node.IsSequence())
351 : return false;
352 : if (node.size() != 2)
353 : return false;
354 :
355 : #if defined(__GNUC__) && __GNUC__ < 4
356 : // workaround for GCC 3:
357 : rhs.first = node[0].template as<T>();
358 : #else
359 : rhs.first = node[0].as<T>();
360 : #endif
361 : #if defined(__GNUC__) && __GNUC__ < 4
362 : // workaround for GCC 3:
363 : rhs.second = node[1].template as<U>();
364 : #else
365 : rhs.second = node[1].as<U>();
366 : #endif
367 : return true;
368 : }
369 : };
370 :
371 : // binary
372 : template <>
373 : struct convert<Binary> {
374 : static Node encode(const Binary& rhs) {
375 : return Node(EncodeBase64(rhs.data(), rhs.size()));
376 : }
377 :
378 0 : static bool decode(const Node& node, Binary& rhs) {
379 0 : if (!node.IsScalar())
380 0 : return false;
381 :
382 0 : std::vector<unsigned char> data = DecodeBase64(node.Scalar());
383 0 : if (data.empty() && !node.Scalar().empty())
384 0 : return false;
385 :
386 0 : rhs.swap(data);
387 0 : return true;
388 0 : }
389 : };
390 : }
391 :
392 : #endif // NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66
|