|
|
@ -11,6 +11,7 @@ |
|
|
|
#include <locale> |
|
|
|
#include <locale> |
|
|
|
#include <codecvt> |
|
|
|
#include <codecvt> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace tser{ |
|
|
|
namespace tser{ |
|
|
|
//implementation details for C++20 is_detected
|
|
|
|
//implementation details for C++20 is_detected
|
|
|
|
namespace detail { |
|
|
|
namespace detail { |
|
|
@ -85,52 +86,6 @@ namespace tser{ |
|
|
|
|
|
|
|
|
|
|
|
template<class T> constexpr bool is_pointer_like_v = std::is_pointer_v<T> || is_detected_v<has_element_t, T> || is_detected_v<has_optional_t, T>; |
|
|
|
template<class T> constexpr bool is_pointer_like_v = std::is_pointer_v<T> || is_detected_v<has_element_t, T> || is_detected_v<has_optional_t, T>; |
|
|
|
|
|
|
|
|
|
|
|
//implementation of the recursive json printing
|
|
|
|
|
|
|
|
template<typename T> |
|
|
|
|
|
|
|
constexpr inline decltype(auto) print(std::ostream& os, T&& val) { |
|
|
|
|
|
|
|
using V = std::decay_t<T>; |
|
|
|
|
|
|
|
if constexpr (std::is_constructible_v<std::string, T> || std::is_same_v<V, char>) { |
|
|
|
|
|
|
|
os << "\"" << val << "\""; |
|
|
|
|
|
|
|
} else if constexpr (std::is_constructible_v<std::wstring, T> || std::is_same_v<V, char>) { |
|
|
|
|
|
|
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; |
|
|
|
|
|
|
|
os << "\"" << converter.to_bytes(val) << "\""; |
|
|
|
|
|
|
|
} else if constexpr (is_container_v<V>) { |
|
|
|
|
|
|
|
size_t i = 0; |
|
|
|
|
|
|
|
os << "\n["; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& elem : val) { |
|
|
|
|
|
|
|
os << (i++ == 0 ? "" : ",") << tser::print(os, elem); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
os << "]\n"; |
|
|
|
|
|
|
|
} else if constexpr (is_tser_t_v<V> && !is_detected_v<has_outstream_op_t, V>) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
auto pMem = [&](auto& ... memberVal) { |
|
|
|
|
|
|
|
size_t i = 0; |
|
|
|
|
|
|
|
(((os << (i != 0 ? ", " : "") << '\"'), os << V::_memberNames[i++] << "\" : " << tser::print(os, memberVal)), ...); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
os << "{ \"" << V::_typeName << "\": {"; std::apply(pMem, val.members()); os << "}}\n"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} else if constexpr (std::is_enum_v<V> &&! is_detected_v<has_outstream_op_t, V>) { |
|
|
|
|
|
|
|
os << tser::print(os, static_cast<std::underlying_type_t<V>>(val)); |
|
|
|
|
|
|
|
} else if constexpr (is_tuple_v<V> && !is_detected_v<has_outstream_op_t, V>) { |
|
|
|
|
|
|
|
std::apply([&](auto& ... t) { |
|
|
|
|
|
|
|
int i = 0; |
|
|
|
|
|
|
|
os << "{"; |
|
|
|
|
|
|
|
(((i++ != 0 ? os << ", " : os), |
|
|
|
|
|
|
|
tser::print(os, t)), ...); // WTF
|
|
|
|
|
|
|
|
os << "}"; |
|
|
|
|
|
|
|
}, val); |
|
|
|
|
|
|
|
} else if constexpr (is_pointer_like_v<V>) { |
|
|
|
|
|
|
|
os << (val ? (os << (tser::print(os, *val)), "") : "null"); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
os << val; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return ""; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class BinaryArchive { |
|
|
|
class BinaryArchive { |
|
|
|
std::string m_bytes = std::string(1024, '\0'); |
|
|
|
std::string m_bytes = std::string(1024, '\0'); |
|
|
|
size_t m_bufferSize = 0, m_readOffset = 0; |
|
|
|
size_t m_bufferSize = 0, m_readOffset = 0; |
|
|
@ -262,6 +217,4 @@ static constexpr std::array<const char*, tser::detail::n_args(#__VA_ARGS__)> _me |
|
|
|
[](){ std::array<const char*, tser::detail::n_args(#__VA_ARGS__)> out{ }; \
|
|
|
|
[](){ std::array<const char*, tser::detail::n_args(#__VA_ARGS__)> out{ }; \
|
|
|
|
for(size_t _i = 0, nArgs = 0; nArgs < tser::detail::n_args(#__VA_ARGS__) ; ++_i) { \
|
|
|
|
for(size_t _i = 0, nArgs = 0; nArgs < tser::detail::n_args(#__VA_ARGS__) ; ++_i) { \
|
|
|
|
while(Type::_memberNameData[_i] == '\0') _i++; out[nArgs++] = &Type::_memberNameData[_i]; \
|
|
|
|
while(Type::_memberNameData[_i] == '\0') _i++; out[nArgs++] = &Type::_memberNameData[_i]; \
|
|
|
|
while(Type::_memberNameData[++_i] != '\0'); } return out;}();\
|
|
|
|
while(Type::_memberNameData[++_i] != '\0'); } return out;}(); |
|
|
|
template<typename OT, std::enable_if_t<std::is_same_v<OT,Type> && !tser::is_detected_v<tser::has_outstream_op_t, OT>, int> = 0>\
|
|
|
|
|
|
|
|
friend std::ostream& operator<<(std::ostream& os, const OT& t) { tser::print(os, t); return os; } |
|
|
|
|
|
|
|