| #ifndef NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 | |
| #define NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 | |
| #if defined(_MSC_VER) || \ | |
| (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ | |
| (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 | |
| #pragma once | |
| #endif | |
| #include <array> | |
| #include <cmath> | |
| #include <limits> | |
| #include <list> | |
| #include <map> | |
| #include <unordered_map> | |
| #include <sstream> | |
| #include <type_traits> | |
| #include <valarray> | |
| #include <vector> | |
| #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) | |
| #include <string_view> | |
| #endif | |
| #include "yaml-cpp/binary.h" | |
| #include "yaml-cpp/node/impl.h" | |
| #include "yaml-cpp/node/iterator.h" | |
| #include "yaml-cpp/node/node.h" | |
| #include "yaml-cpp/node/type.h" | |
| #include "yaml-cpp/null.h" | |
| #include "yaml-cpp/fptostring.h" | |
| namespace YAML { | |
| class Binary; | |
| struct _Null; | |
| template <typename T> | |
| struct convert; | |
| } // namespace YAML | |
| namespace YAML { | |
| 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) { | |
| return input == "-.inf" || input == "-.Inf" || input == "-.INF"; | |
| } | |
| inline bool IsNaN(const std::string& input) { | |
| return input == ".nan" || input == ".NaN" || input == ".NAN"; | |
| } | |
| } | |
| // Node | |
| template <> | |
| struct convert<Node> { | |
| static Node encode(const Node& rhs) { return rhs; } | |
| static bool decode(const Node& node, Node& rhs) { | |
| rhs.reset(node); | |
| return true; | |
| } | |
| }; | |
| // std::string | |
| template <> | |
| struct convert<std::string> { | |
| static Node encode(const std::string& rhs) { return Node(rhs); } | |
| static bool decode(const Node& node, std::string& rhs) { | |
| if (!node.IsScalar()) | |
| return false; | |
| rhs = node.Scalar(); | |
| return true; | |
| } | |
| }; | |
| // C-strings can only be encoded | |
| template <> | |
| struct convert<const char*> { | |
| static Node encode(const char* rhs) { return Node(rhs); } | |
| }; | |
| template <> | |
| struct convert<char*> { | |
| static Node encode(const char* rhs) { return Node(rhs); } | |
| }; | |
| template <std::size_t N> | |
| struct convert<char[N]> { | |
| static Node encode(const char* rhs) { return Node(rhs); } | |
| }; | |
| #if ((defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) || __cplusplus >= 201703L) | |
| template <> | |
| struct convert<std::string_view> { | |
| static Node encode(std::string_view rhs) { return Node(std::string(rhs)); } | |
| static bool decode(const Node& node, std::string_view& rhs) { | |
| if (!node.IsScalar()) | |
| return false; | |
| rhs = node.Scalar(); | |
| return true; | |
| } | |
| }; | |
| #endif | |
| template <> | |
| struct convert<_Null> { | |
| static Node encode(const _Null& /* rhs */) { return Node(); } | |
| static bool decode(const Node& node, _Null& /* rhs */) { | |
| return node.IsNull(); | |
| } | |
| }; | |
| namespace conversion { | |
| template <typename T> | |
| typename std::enable_if< std::is_floating_point<T>::value, void>::type | |
| inner_encode(const T& rhs, std::stringstream& stream){ | |
| if (std::isnan(rhs)) { | |
| stream << ".nan"; | |
| } else if (std::isinf(rhs)) { | |
| if (std::signbit(rhs)) { | |
| stream << "-.inf"; | |
| } else { | |
| stream << ".inf"; | |
| } | |
| } else { | |
| stream << FpToString(rhs, stream.precision()); | |
| } | |
| } | |
| template <typename T> | |
| typename std::enable_if<!std::is_floating_point<T>::value, void>::type | |
| inner_encode(const T& rhs, std::stringstream& stream){ | |
| stream << rhs; | |
| } | |
| template <typename T> | |
| typename std::enable_if<(std::is_same<T, unsigned char>::value || | |
| std::is_same<T, signed char>::value), bool>::type | |
| ConvertStreamTo(std::stringstream& stream, T& rhs) { | |
| int num; | |
| if ((stream >> std::noskipws >> num) && (stream >> std::ws).eof()) { | |
| if (num >= (std::numeric_limits<T>::min)() && | |
| num <= (std::numeric_limits<T>::max)()) { | |
| rhs = static_cast<T>(num); | |
| return true; | |
| } | |
| } | |
| return false; | |
| } | |
| template <typename T> | |
| typename std::enable_if<!(std::is_same<T, unsigned char>::value || | |
| std::is_same<T, signed char>::value), bool>::type | |
| ConvertStreamTo(std::stringstream& stream, T& rhs) { | |
| if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| } | |
| #define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \ | |
| template <> \ | |
| struct convert<type> { \ | |
| \ | |
| static Node encode(const type& rhs) { \ | |
| std::stringstream stream; \ | |
| stream.imbue(std::locale::classic()); \ | |
| stream.precision(std::numeric_limits<type>::max_digits10); \ | |
| conversion::inner_encode(rhs, stream); \ | |
| return Node(stream.str()); \ | |
| } \ | |
| \ | |
| static bool decode(const Node& node, type& rhs) { \ | |
| if (node.Type() != NodeType::Scalar) { \ | |
| return false; \ | |
| } \ | |
| const std::string& input = node.Scalar(); \ | |
| std::stringstream stream(input); \ | |
| stream.imbue(std::locale::classic()); \ | |
| stream.unsetf(std::ios::dec); \ | |
| if ((stream.peek() == '-') && std::is_unsigned<type>::value) { \ | |
| return false; \ | |
| } \ | |
| if (conversion::ConvertStreamTo(stream, rhs)) { \ | |
| return true; \ | |
| } \ | |
| if (std::numeric_limits<type>::has_infinity) { \ | |
| if (conversion::IsInfinity(input)) { \ | |
| rhs = std::numeric_limits<type>::infinity(); \ | |
| return true; \ | |
| } else if (conversion::IsNegativeInfinity(input)) { \ | |
| rhs = negative_op std::numeric_limits<type>::infinity(); \ | |
| return true; \ | |
| } \ | |
| } \ | |
| \ | |
| if (std::numeric_limits<type>::has_quiet_NaN) { \ | |
| if (conversion::IsNaN(input)) { \ | |
| rhs = std::numeric_limits<type>::quiet_NaN(); \ | |
| return true; \ | |
| } \ | |
| } \ | |
| \ | |
| return false; \ | |
| } \ | |
| } | |
| #define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \ | |
| YAML_DEFINE_CONVERT_STREAMABLE(type, -) | |
| #define YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(type) \ | |
| YAML_DEFINE_CONVERT_STREAMABLE(type, +) | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(short); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long long); | |
| YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned); | |
| YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned short); | |
| YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long); | |
| YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long long); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(char); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(signed char); | |
| YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned char); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(float); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(double); | |
| YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long double); | |
| #undef YAML_DEFINE_CONVERT_STREAMABLE_SIGNED | |
| #undef YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED | |
| #undef YAML_DEFINE_CONVERT_STREAMABLE | |
| // bool | |
| template <> | |
| struct convert<bool> { | |
| static Node encode(bool rhs) { return rhs ? Node("true") : Node("false"); } | |
| YAML_CPP_API static bool decode(const Node& node, bool& rhs); | |
| }; | |
| // std::map | |
| template <typename K, typename V, typename C, typename A> | |
| struct convert<std::map<K, V, C, A>> { | |
| static Node encode(const std::map<K, V, C, A>& rhs) { | |
| Node node(NodeType::Map); | |
| for (const auto& element : rhs) | |
| node.force_insert(element.first, element.second); | |
| return node; | |
| } | |
| static bool decode(const Node& node, std::map<K, V, C, A>& rhs) { | |
| if (!node.IsMap()) | |
| return false; | |
| rhs.clear(); | |
| for (const auto& element : node) | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs[element.first.template as<K>()] = element.second.template as<V>(); | |
| #else | |
| rhs[element.first.as<K>()] = element.second.as<V>(); | |
| #endif | |
| return true; | |
| } | |
| }; | |
| // std::unordered_map | |
| template <typename K, typename V, typename H, typename P, typename A> | |
| struct convert<std::unordered_map<K, V, H, P, A>> { | |
| static Node encode(const std::unordered_map<K, V, H, P, A>& rhs) { | |
| Node node(NodeType::Map); | |
| for (const auto& element : rhs) | |
| node.force_insert(element.first, element.second); | |
| return node; | |
| } | |
| static bool decode(const Node& node, std::unordered_map<K, V, H, P, A>& rhs) { | |
| if (!node.IsMap()) | |
| return false; | |
| rhs.clear(); | |
| for (const auto& element : node) | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs[element.first.template as<K>()] = element.second.template as<V>(); | |
| #else | |
| rhs[element.first.as<K>()] = element.second.as<V>(); | |
| #endif | |
| return true; | |
| } | |
| }; | |
| // std::vector | |
| template <typename T, typename A> | |
| struct convert<std::vector<T, A>> { | |
| static Node encode(const std::vector<T, A>& rhs) { | |
| Node node(NodeType::Sequence); | |
| for (const auto& element : rhs) | |
| node.push_back(element); | |
| return node; | |
| } | |
| static bool decode(const Node& node, std::vector<T, A>& rhs) { | |
| if (!node.IsSequence()) | |
| return false; | |
| rhs.clear(); | |
| for (const auto& element : node) | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs.push_back(element.template as<T>()); | |
| #else | |
| rhs.push_back(element.as<T>()); | |
| #endif | |
| return true; | |
| } | |
| }; | |
| // std::list | |
| template <typename T, typename A> | |
| struct convert<std::list<T,A>> { | |
| static Node encode(const std::list<T,A>& rhs) { | |
| Node node(NodeType::Sequence); | |
| for (const auto& element : rhs) | |
| node.push_back(element); | |
| return node; | |
| } | |
| static bool decode(const Node& node, std::list<T,A>& rhs) { | |
| if (!node.IsSequence()) | |
| return false; | |
| rhs.clear(); | |
| for (const auto& element : node) | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs.push_back(element.template as<T>()); | |
| #else | |
| rhs.push_back(element.as<T>()); | |
| #endif | |
| return true; | |
| } | |
| }; | |
| // std::array | |
| template <typename T, std::size_t N> | |
| struct convert<std::array<T, N>> { | |
| static Node encode(const std::array<T, N>& rhs) { | |
| Node node(NodeType::Sequence); | |
| for (const auto& element : rhs) { | |
| node.push_back(element); | |
| } | |
| return node; | |
| } | |
| static bool decode(const Node& node, std::array<T, N>& rhs) { | |
| if (!isNodeValid(node)) { | |
| return false; | |
| } | |
| for (auto i = 0u; i < node.size(); ++i) { | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs[i] = node[i].template as<T>(); | |
| #else | |
| rhs[i] = node[i].as<T>(); | |
| #endif | |
| } | |
| return true; | |
| } | |
| private: | |
| static bool isNodeValid(const Node& node) { | |
| return node.IsSequence() && node.size() == N; | |
| } | |
| }; | |
| // std::valarray | |
| template <typename T> | |
| struct convert<std::valarray<T>> { | |
| static Node encode(const std::valarray<T>& rhs) { | |
| Node node(NodeType::Sequence); | |
| for (const auto& element : rhs) { | |
| node.push_back(element); | |
| } | |
| return node; | |
| } | |
| static bool decode(const Node& node, std::valarray<T>& rhs) { | |
| if (!node.IsSequence()) { | |
| return false; | |
| } | |
| rhs.resize(node.size()); | |
| for (auto i = 0u; i < node.size(); ++i) { | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs[i] = node[i].template as<T>(); | |
| #else | |
| rhs[i] = node[i].as<T>(); | |
| #endif | |
| } | |
| return true; | |
| } | |
| }; | |
| // std::pair | |
| template <typename T, typename U> | |
| struct convert<std::pair<T, U>> { | |
| static Node encode(const std::pair<T, U>& rhs) { | |
| Node node(NodeType::Sequence); | |
| node.push_back(rhs.first); | |
| node.push_back(rhs.second); | |
| return node; | |
| } | |
| static bool decode(const Node& node, std::pair<T, U>& rhs) { | |
| if (!node.IsSequence()) | |
| return false; | |
| if (node.size() != 2) | |
| return false; | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs.first = node[0].template as<T>(); | |
| #else | |
| rhs.first = node[0].as<T>(); | |
| #endif | |
| #if defined(__GNUC__) && __GNUC__ < 4 | |
| // workaround for GCC 3: | |
| rhs.second = node[1].template as<U>(); | |
| #else | |
| rhs.second = node[1].as<U>(); | |
| #endif | |
| return true; | |
| } | |
| }; | |
| // binary | |
| template <> | |
| struct convert<Binary> { | |
| static Node encode(const Binary& rhs) { | |
| return Node(EncodeBase64(rhs.data(), rhs.size())); | |
| } | |
| static bool decode(const Node& node, Binary& rhs) { | |
| if (!node.IsScalar()) | |
| return false; | |
| std::vector<unsigned char> data = DecodeBase64(node.Scalar()); | |
| if (data.empty() && !node.Scalar().empty()) | |
| return false; | |
| rhs.swap(data); | |
| return true; | |
| } | |
| }; | |
| } | |
| #endif // NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 |