aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons/json_type_traits.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons/json_type_traits.hpp')
-rw-r--r--include/jsoncons/json_type_traits.hpp1829
1 files changed, 1829 insertions, 0 deletions
diff --git a/include/jsoncons/json_type_traits.hpp b/include/jsoncons/json_type_traits.hpp
new file mode 100644
index 0000000..7ee26b2
--- /dev/null
+++ b/include/jsoncons/json_type_traits.hpp
@@ -0,0 +1,1829 @@
+// Copyright 2013 Daniel Parker
+// Distributed under the Boost license, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+// See https://github.com/danielaparker/jsoncons for latest version
+
+#ifndef JSONCONS_JSON_TYPE_TRAITS_HPP
+#define JSONCONS_JSON_TYPE_TRAITS_HPP
+
+#include <chrono>
+#include <array>
+#include <string>
+#include <vector>
+#include <valarray>
+#include <exception>
+#include <cstring>
+#include <utility>
+#include <algorithm> // std::swap
+#include <limits> // std::numeric_limits
+#include <type_traits> // std::enable_if
+#include <iterator> // std::iterator_traits, std::input_iterator_tag
+#include <jsoncons/json_type.hpp>
+#include <jsoncons/bigint.hpp>
+#include <jsoncons/json_visitor.hpp>
+#include <jsoncons/more_type_traits.hpp>
+#include <string>
+#include <tuple>
+#include <map>
+#include <functional>
+#include <memory>
+#include <bitset> // std::bitset
+#include <jsoncons/conv_error.hpp>
+#include <jsoncons/converter.hpp>
+
+#if defined(JSONCONS_HAS_STD_VARIANT)
+ #include <variant>
+#endif
+
+namespace jsoncons {
+
+ template <class T>
+ struct is_json_type_traits_declared : public std::false_type
+ {};
+
+ #if !defined(JSONCONS_NO_DEPRECATED)
+ template <class T>
+ using is_json_type_traits_impl = is_json_type_traits_declared<T>;
+ #endif
+
+ // json_type_traits
+
+ template<typename T>
+ struct unimplemented : std::false_type
+ {};
+
+ template <class Json, class T, class Enable=void>
+ struct json_type_traits
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static constexpr bool is_compatible = false;
+
+ static constexpr bool is(const Json&) noexcept
+ {
+ return false;
+ }
+
+ static T as(const Json&)
+ {
+ static_assert(unimplemented<T>::value, "as not implemented");
+ }
+
+ static Json to_json(const T&, const allocator_type& = allocator_type())
+ {
+ static_assert(unimplemented<T>::value, "to_json not implemented");
+ }
+ };
+
+namespace detail {
+
+template<class Json, class T>
+using
+traits_can_convert_t = decltype(json_type_traits<Json,T>::can_convert(Json()));
+
+template<class Json, class T>
+using
+has_can_convert = type_traits::is_detected<traits_can_convert_t, Json, T>;
+
+ template <class T>
+ struct invoke_can_convert
+ {
+ template <class Json>
+ static
+ typename std::enable_if<has_can_convert<Json,T>::value,bool>::type
+ can_convert(const Json& j) noexcept
+ {
+ return json_type_traits<Json,T>::can_convert(j);
+ }
+ template <class Json>
+ static
+ typename std::enable_if<!has_can_convert<Json,T>::value,bool>::type
+ can_convert(const Json& j) noexcept
+ {
+ return json_type_traits<Json,T>::is(j);
+ }
+ };
+
+ // is_json_type_traits_unspecialized
+ template<class Json, class T, class Enable = void>
+ struct is_json_type_traits_unspecialized : std::false_type {};
+
+ // is_json_type_traits_unspecialized
+ template<class Json, class T>
+ struct is_json_type_traits_unspecialized<Json,T,
+ typename std::enable_if<!std::integral_constant<bool, json_type_traits<Json, T>::is_compatible>::value>::type
+ > : std::true_type {};
+
+ // is_compatible_array_type
+ template<class Json, class T, class Enable=void>
+ struct is_compatible_array_type : std::false_type {};
+
+ template<class Json, class T>
+ struct is_compatible_array_type<Json,T,
+ typename std::enable_if<!std::is_same<T,typename Json::array>::value &&
+ type_traits::is_list_like<T>::value &&
+ !is_json_type_traits_unspecialized<Json,typename std::iterator_traits<typename T::iterator>::value_type>::value
+ >::type> : std::true_type {};
+
+} // namespace detail
+
+ // is_json_type_traits_specialized
+ template<class Json, class T, class Enable=void>
+ struct is_json_type_traits_specialized : std::false_type {};
+
+ template<class Json, class T>
+ struct is_json_type_traits_specialized<Json,T,
+ typename std::enable_if<!jsoncons::detail::is_json_type_traits_unspecialized<Json,T>::value
+ >::type> : std::true_type {};
+
+ template<class Json>
+ struct json_type_traits<Json, const typename std::decay<typename Json::char_type>::type*>
+ {
+ using char_type = typename Json::char_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_string();
+ }
+ static const char_type* as(const Json& j)
+ {
+ return j.as_cstring();
+ }
+ template <class ... Args>
+ static Json to_json(const char_type* s, Args&&... args)
+ {
+ return Json(s, semantic_tag::none, std::forward<Args>(args)...);
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, typename std::decay<typename Json::char_type>::type*>
+ {
+ using char_type = typename Json::char_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_string();
+ }
+ template <class ... Args>
+ static Json to_json(const char_type* s, Args&&... args)
+ {
+ return Json(s, semantic_tag::none, std::forward<Args>(args)...);
+ }
+ };
+
+ // integer
+
+ template<class Json, class T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<type_traits::is_integer<T>::value
+ >::type>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.template is_integer<T>();
+ }
+ static T as(const Json& j)
+ {
+ return j.template as_integer<T>();
+ }
+
+ static Json to_json(T val, allocator_type alloc = allocator_type())
+ {
+ return Json(val, semantic_tag::none, alloc);
+ }
+ };
+
+ template<class Json, class T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<std::is_floating_point<T>::value
+ >::type>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_double();
+ }
+ static T as(const Json& j)
+ {
+ return static_cast<T>(j.as_double());
+ }
+ static Json to_json(T val, allocator_type = allocator_type())
+ {
+ return Json(val, semantic_tag::none);
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, typename Json::object>
+ {
+ using json_object = typename Json::object;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_object();
+ }
+ static Json to_json(const json_object& o, const allocator_type& = allocator_type())
+ {
+ return Json(o,semantic_tag::none);
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, typename Json::array>
+ {
+ using json_array = typename Json::array;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_array();
+ }
+ static Json to_json(const json_array& a, const allocator_type& = allocator_type())
+ {
+ return Json(a, semantic_tag::none);
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, Json>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json&) noexcept
+ {
+ return true;
+ }
+ static Json as(Json j)
+ {
+ return j;
+ }
+ static Json to_json(const Json& val, allocator_type = allocator_type())
+ {
+ return val;
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, jsoncons::null_type>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_null();
+ }
+ static typename jsoncons::null_type as(const Json& j)
+ {
+ if (!j.is_null())
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_jsoncons_null_type));
+ }
+ return jsoncons::null_type();
+ }
+ static Json to_json(jsoncons::null_type, allocator_type = allocator_type())
+ {
+ return Json::null();
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, bool>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_bool();
+ }
+ static bool as(const Json& j)
+ {
+ return j.as_bool();
+ }
+ static Json to_json(bool val, allocator_type = allocator_type())
+ {
+ return Json(val, semantic_tag::none);
+ }
+ };
+
+ template<class Json, class T>
+ struct json_type_traits<Json, T, typename std::enable_if<std::is_same<T,
+ std::conditional<!std::is_same<bool,std::vector<bool>::const_reference>::value,
+ std::vector<bool>::const_reference,
+ void>::type>::value>::type>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_bool();
+ }
+ static bool as(const Json& j)
+ {
+ return j.as_bool();
+ }
+ static Json to_json(bool val, allocator_type = allocator_type())
+ {
+ return Json(val, semantic_tag::none);
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, std::vector<bool>::reference>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_bool();
+ }
+ static bool as(const Json& j)
+ {
+ return j.as_bool();
+ }
+ static Json to_json(bool val, allocator_type = allocator_type())
+ {
+ return Json(val, semantic_tag::none);
+ }
+ };
+
+ template<class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ type_traits::is_basic_string<T>::value &&
+ std::is_same<typename Json::char_type,typename T::value_type>::value>::type>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_string();
+ }
+
+ static T as(const Json& j)
+ {
+ return T(j.as_string());
+ }
+
+ static Json to_json(const T& val)
+ {
+ return Json(val, semantic_tag::none);
+ }
+
+ static Json to_json(const T& val, const allocator_type& alloc)
+ {
+ return Json(val, semantic_tag::none, alloc);
+ }
+ };
+
+ template<class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ type_traits::is_basic_string<T>::value &&
+ !std::is_same<typename Json::char_type,typename T::value_type>::value>::type>
+ {
+ using char_type = typename Json::char_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_string();
+ }
+
+ static T as(const Json& j)
+ {
+ auto s = j.as_string();
+ T val;
+ unicode_traits::convert(s.data(), s.size(), val);
+ return val;
+ }
+
+ static Json to_json(const T& val)
+ {
+ std::basic_string<char_type> s;
+ unicode_traits::convert(val.data(), val.size(), s);
+
+ return Json(s, semantic_tag::none);
+ }
+
+ static Json to_json(const T& val, const allocator_type& alloc)
+ {
+ std::basic_string<char_type> s;
+ unicode_traits::convert(val.data(), val.size(), s);
+ return Json(s, semantic_tag::none, alloc);
+ }
+ };
+
+ template<class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ type_traits::is_basic_string_view<T>::value &&
+ std::is_same<typename Json::char_type,typename T::value_type>::value>::type>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_string_view();
+ }
+
+ static T as(const Json& j)
+ {
+ return T(j.as_string_view().data(),j.as_string_view().size());
+ }
+
+ static Json to_json(const T& val)
+ {
+ return Json(val, semantic_tag::none);
+ }
+
+ static Json to_json(const T& val, const allocator_type& alloc)
+ {
+ return Json(val, semantic_tag::none, alloc);
+ }
+ };
+
+ // array back insertable
+
+ template<class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ jsoncons::detail::is_compatible_array_type<Json,T>::value &&
+ type_traits::is_back_insertable<T>::value
+ >::type>
+ {
+ typedef typename std::iterator_traits<typename T::iterator>::value_type value_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ bool result = j.is_array();
+ if (result)
+ {
+ for (auto e : j.array_range())
+ {
+ if (!e.template is<value_type>())
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ // array back insertable non-byte container
+
+ template <class Container = T>
+ static typename std::enable_if<!type_traits::is_byte<typename Container::value_type>::value,Container>::type
+ as(const Json& j)
+ {
+ if (j.is_array())
+ {
+ T result;
+ visit_reserve_(typename std::integral_constant<bool, type_traits::has_reserve<T>::value>::type(),result,j.size());
+ for (const auto& item : j.array_range())
+ {
+ result.push_back(item.template as<value_type>());
+ }
+
+ return result;
+ }
+ else
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_vector));
+ }
+ }
+
+ // array back insertable byte container
+
+ template <class Container = T>
+ static typename std::enable_if<type_traits::is_byte<typename Container::value_type>::value,Container>::type
+ as(const Json& j)
+ {
+ converter<T> convert;
+ std::error_code ec;
+ if (j.is_array())
+ {
+ T result;
+ visit_reserve_(typename std::integral_constant<bool, type_traits::has_reserve<T>::value>::type(),result,j.size());
+ for (const auto& item : j.array_range())
+ {
+ result.push_back(item.template as<value_type>());
+ }
+
+ return result;
+ }
+ else if (j.is_byte_string_view())
+ {
+ auto v = convert.from(j.as_byte_string_view(),j.tag(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(conv_error(ec));
+ }
+ return v;
+ }
+ else if (j.is_string())
+ {
+ auto v = convert.from(j.as_string_view(),j.tag(), ec);
+ if (ec)
+ {
+ JSONCONS_THROW(conv_error(ec));
+ }
+ return v;
+ }
+ else
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_vector));
+ }
+ }
+
+ template <class Container = T>
+ static typename std::enable_if<!type_traits::is_std_byte<typename Container::value_type>::value,Json>::type
+ to_json(const T& val)
+ {
+ Json j(json_array_arg);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first,last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+
+ template <class Container = T>
+ static typename std::enable_if<!type_traits::is_std_byte<typename Container::value_type>::value,Json>::type
+ to_json(const T& val, const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first, last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+
+ template <class Container = T>
+ static typename std::enable_if<type_traits::is_std_byte<typename Container::value_type>::value,Json>::type
+ to_json(const T& val)
+ {
+ Json j(byte_string_arg, val);
+ return j;
+ }
+
+ template <class Container = T>
+ static typename std::enable_if<type_traits::is_std_byte<typename Container::value_type>::value,Json>::type
+ to_json(const T& val, const allocator_type& alloc)
+ {
+ Json j(byte_string_arg, val, semantic_tag::none, alloc);
+ return j;
+ }
+
+ static void visit_reserve_(std::true_type, T& v, std::size_t size)
+ {
+ v.reserve(size);
+ }
+
+ static void visit_reserve_(std::false_type, T&, std::size_t)
+ {
+ }
+ };
+
+ // array, not back insertable but insertable
+
+ template<class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ jsoncons::detail::is_compatible_array_type<Json,T>::value &&
+ !type_traits::is_back_insertable<T>::value &&
+ type_traits::is_insertable<T>::value>::type>
+ {
+ typedef typename std::iterator_traits<typename T::iterator>::value_type value_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ bool result = j.is_array();
+ if (result)
+ {
+ for (auto e : j.array_range())
+ {
+ if (!e.template is<value_type>())
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ static T as(const Json& j)
+ {
+ if (j.is_array())
+ {
+ T result;
+ for (const auto& item : j.array_range())
+ {
+ result.insert(item.template as<value_type>());
+ }
+
+ return result;
+ }
+ else
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_vector));
+ }
+ }
+
+ static Json to_json(const T& val)
+ {
+ Json j(json_array_arg);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first,last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+
+ static Json to_json(const T& val, const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first, last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+ };
+
+ // array not back insertable or insertable, but front insertable
+
+ template<class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ jsoncons::detail::is_compatible_array_type<Json,T>::value &&
+ !type_traits::is_back_insertable<T>::value &&
+ !type_traits::is_insertable<T>::value &&
+ type_traits::is_front_insertable<T>::value>::type>
+ {
+ typedef typename std::iterator_traits<typename T::iterator>::value_type value_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ bool result = j.is_array();
+ if (result)
+ {
+ for (auto e : j.array_range())
+ {
+ if (!e.template is<value_type>())
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ static T as(const Json& j)
+ {
+ if (j.is_array())
+ {
+ T result;
+
+ auto it = j.array_range().rbegin();
+ auto end = j.array_range().rend();
+ for (; it != end; ++it)
+ {
+ result.push_front((*it).template as<value_type>());
+ }
+
+ return result;
+ }
+ else
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_vector));
+ }
+ }
+
+ static Json to_json(const T& val)
+ {
+ Json j(json_array_arg);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first,last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+
+ static Json to_json(const T& val, const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first, last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+ };
+
+ // std::array
+
+ template<class Json, class E, std::size_t N>
+ struct json_type_traits<Json, std::array<E, N>>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ using value_type = E;
+
+ static bool is(const Json& j) noexcept
+ {
+ bool result = j.is_array() && j.size() == N;
+ if (result)
+ {
+ for (auto e : j.array_range())
+ {
+ if (!e.template is<value_type>())
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ static std::array<E, N> as(const Json& j)
+ {
+ std::array<E, N> buff;
+ if (j.size() != N)
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_array));
+ }
+ for (std::size_t i = 0; i < N; i++)
+ {
+ buff[i] = j[i].template as<E>();
+ }
+ return buff;
+ }
+
+ static Json to_json(const std::array<E, N>& val)
+ {
+ Json j(json_array_arg);
+ j.reserve(N);
+ for (auto it = val.begin(); it != val.end(); ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+
+ static Json to_json(const std::array<E, N>& val,
+ const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ j.reserve(N);
+ for (auto it = val.begin(); it != val.end(); ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+ };
+
+ // map like
+ template<class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ type_traits::is_map_like<T>::value &&
+ type_traits::is_constructible_from_const_pointer_and_size<typename T::key_type>::value &&
+ is_json_type_traits_specialized<Json,typename T::mapped_type>::value>::type
+ >
+ {
+ using mapped_type = typename T::mapped_type;
+ using value_type = typename T::value_type;
+ using key_type = typename T::key_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ bool result = j.is_object();
+ for (auto member : j.object_range())
+ {
+ if (!member.value().template is<mapped_type>())
+ {
+ result = false;
+ }
+ }
+ return result;
+ }
+
+ static T as(const Json& j)
+ {
+ if (!j.is_object())
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_map));
+ }
+ T result;
+ for (const auto& item : j.object_range())
+ {
+ result.emplace(key_type(item.key().data(),item.key().size()), item.value().template as<mapped_type>());
+ }
+
+ return result;
+ }
+
+ static Json to_json(const T& val)
+ {
+ Json j(json_object_arg, val.begin(), val.end());
+ return j;
+ }
+
+ static Json to_json(const T& val, const allocator_type& alloc)
+ {
+ Json j(json_object_arg, val.begin(), val.end(), alloc);
+ return j;
+ }
+ };
+
+ template <class Json, typename T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<!is_json_type_traits_declared<T>::value &&
+ type_traits::is_map_like<T>::value &&
+ !type_traits::is_constructible_from_const_pointer_and_size<typename T::key_type>::value &&
+ is_json_type_traits_specialized<Json,typename T::key_type>::value &&
+ is_json_type_traits_specialized<Json,typename T::mapped_type>::value>::type
+ >
+ {
+ using mapped_type = typename T::mapped_type;
+ using value_type = typename T::value_type;
+ using key_type = typename T::key_type;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& val) noexcept
+ {
+ if (!val.is_object())
+ return false;
+ for (const auto& item : val.object_range())
+ {
+ Json j(item.key());
+ if (!j.template is<key_type>())
+ {
+ return false;
+ }
+ if (!item.value().template is<mapped_type>())
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ static T as(const Json& val)
+ {
+ T result;
+ for (const auto& item : val.object_range())
+ {
+ Json j(item.key());
+ auto key = json_type_traits<Json,key_type>::as(j);
+ result.emplace(std::move(key), item.value().template as<mapped_type>());
+ }
+
+ return result;
+ }
+
+ static Json to_json(const T& val)
+ {
+ Json j(json_object_arg);
+ j.reserve(val.size());
+ for (const auto& item : val)
+ {
+ auto temp = json_type_traits<Json,key_type>::to_json(item.first);
+ typename Json::key_type key;
+ temp.dump(key);
+ j.try_emplace(std::move(key), item.second);
+ }
+ return j;
+ }
+
+ static Json to_json(const T& val, const allocator_type& alloc)
+ {
+ Json j(json_object_arg, semantic_tag::none, alloc);
+ j.reserve(val.size());
+ for (const auto& item : val)
+ {
+ auto temp = json_type_traits<Json,key_type>::to_json(item.first, alloc);
+ typename Json::key_type key(alloc);
+ temp.dump(key);
+ j.try_emplace(std::move(key), item.second, alloc);
+ }
+ return j;
+ }
+ };
+
+ namespace tuple_detail
+ {
+ template<size_t Pos, std::size_t Size, class Json, class Tuple>
+ struct json_tuple_helper
+ {
+ using element_type = typename std::tuple_element<Size-Pos, Tuple>::type;
+ using next = json_tuple_helper<Pos-1, Size, Json, Tuple>;
+
+ static bool is(const Json& j) noexcept
+ {
+ if (j[Size-Pos].template is<element_type>())
+ {
+ return next::is(j);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ static void as(Tuple& tuple, const Json& j)
+ {
+ std::get<Size-Pos>(tuple) = j[Size-Pos].template as<element_type>();
+ next::as(tuple, j);
+ }
+
+ static void to_json(const Tuple& tuple, Json& j)
+ {
+ j.push_back(json_type_traits<Json, element_type>::to_json(std::get<Size-Pos>(tuple)));
+ next::to_json(tuple, j);
+ }
+ };
+
+ template<size_t Size, class Json, class Tuple>
+ struct json_tuple_helper<0, Size, Json, Tuple>
+ {
+ static bool is(const Json&) noexcept
+ {
+ return true;
+ }
+
+ static void as(Tuple&, const Json&)
+ {
+ }
+
+ static void to_json(const Tuple&, Json&)
+ {
+ }
+ };
+ } // namespace detail
+
+ template<class Json, typename... E>
+ struct json_type_traits<Json, std::tuple<E...>>
+ {
+ private:
+ using helper = tuple_detail::json_tuple_helper<sizeof...(E), sizeof...(E), Json, std::tuple<E...>>;
+
+ public:
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return helper::is(j);
+ }
+
+ static std::tuple<E...> as(const Json& j)
+ {
+ std::tuple<E...> buff;
+ helper::as(buff, j);
+ return buff;
+ }
+
+ static Json to_json(const std::tuple<E...>& val)
+ {
+ Json j(json_array_arg);
+ j.reserve(sizeof...(E));
+ helper::to_json(val, j);
+ return j;
+ }
+
+ static Json to_json(const std::tuple<E...>& val,
+ const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ j.reserve(sizeof...(E));
+ helper::to_json(val, j);
+ return j;
+ }
+ };
+
+ template<class Json, class T1, class T2>
+ struct json_type_traits<Json, std::pair<T1,T2>>
+ {
+ public:
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_array() && j.size() == 2;
+ }
+
+ static std::pair<T1,T2> as(const Json& j)
+ {
+ return std::make_pair<T1,T2>(j[0].template as<T1>(),j[1].template as<T2>());
+ }
+
+ static Json to_json(const std::pair<T1,T2>& val)
+ {
+ Json j(json_array_arg);
+ j.reserve(2);
+ j.push_back(val.first);
+ j.push_back(val.second);
+ return j;
+ }
+
+ static Json to_json(const std::pair<T1, T2>& val, const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ j.reserve(2);
+ j.push_back(val.first);
+ j.push_back(val.second);
+ return j;
+ }
+ };
+
+ template<class Json, class T>
+ struct json_type_traits<Json, T,
+ typename std::enable_if<type_traits::is_basic_byte_string<T>::value>::type>
+ {
+ public:
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_byte_string();
+ }
+
+ static T as(const Json& j)
+ {
+ return j.template as_byte_string<typename T::allocator_type>();
+ }
+
+ static Json to_json(const T& val,
+ const allocator_type& alloc = allocator_type())
+ {
+ return Json(byte_string_arg, val, semantic_tag::none, alloc);
+ }
+ };
+
+ template<class Json, class ValueType>
+ struct json_type_traits<Json, std::shared_ptr<ValueType>,
+ typename std::enable_if<!is_json_type_traits_declared<std::shared_ptr<ValueType>>::value &&
+ !std::is_polymorphic<ValueType>::value
+ >::type>
+ {
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_null() || j.template is<ValueType>();
+ }
+
+ static std::shared_ptr<ValueType> as(const Json& j)
+ {
+ return j.is_null() ? std::shared_ptr<ValueType>(nullptr) : std::make_shared<ValueType>(j.template as<ValueType>());
+ }
+
+ static Json to_json(const std::shared_ptr<ValueType>& ptr)
+ {
+ if (ptr.get() != nullptr)
+ {
+ Json j(*ptr);
+ return j;
+ }
+ else
+ {
+ return Json::null();
+ }
+ }
+ };
+
+ template<class Json, class ValueType>
+ struct json_type_traits<Json, std::unique_ptr<ValueType>,
+ typename std::enable_if<!is_json_type_traits_declared<std::unique_ptr<ValueType>>::value &&
+ !std::is_polymorphic<ValueType>::value
+ >::type>
+ {
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_null() || j.template is<ValueType>();
+ }
+
+ static std::unique_ptr<ValueType> as(const Json& j)
+ {
+ return j.is_null() ? std::unique_ptr<ValueType>(nullptr) : jsoncons::make_unique<ValueType>(j.template as<ValueType>());
+ }
+
+ static Json to_json(const std::unique_ptr<ValueType>& ptr)
+ {
+ if (ptr.get() != nullptr)
+ {
+ Json j(*ptr);
+ return j;
+ }
+ else
+ {
+ return Json::null();
+ }
+ }
+ };
+
+ template<class Json, class T>
+ struct json_type_traits<Json, jsoncons::optional<T>,
+ typename std::enable_if<!is_json_type_traits_declared<jsoncons::optional<T>>::value>::type>
+ {
+ public:
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_null() || j.template is<T>();
+ }
+
+ static jsoncons::optional<T> as(const Json& j)
+ {
+ return j.is_null() ? jsoncons::optional<T>() : jsoncons::optional<T>(j.template as<T>());
+ }
+
+ static Json to_json(const jsoncons::optional<T>& val)
+ {
+ return val.has_value() ? Json(*val) : Json::null();
+ }
+ };
+
+ template<class Json>
+ struct json_type_traits<Json, byte_string_view>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ public:
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_byte_string_view();
+ }
+
+ static byte_string_view as(const Json& j)
+ {
+ return j.as_byte_string_view();
+ }
+
+ static Json to_json(const byte_string_view& val, const allocator_type& alloc = allocator_type())
+ {
+ return Json(byte_string_arg, val, semantic_tag::none, alloc);
+ }
+ };
+
+ // basic_bigint
+
+ template<class Json, class Allocator>
+ struct json_type_traits<Json, basic_bigint<Allocator>>
+ {
+ public:
+ using char_type = typename Json::char_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ switch (j.type())
+ {
+ case json_type::string_value:
+ return jsoncons::detail::is_base10(j.as_string_view().data(), j.as_string_view().length());
+ case json_type::int64_value:
+ case json_type::uint64_value:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ static basic_bigint<Allocator> as(const Json& j)
+ {
+ switch (j.type())
+ {
+ case json_type::string_value:
+ if (!jsoncons::detail::is_base10(j.as_string_view().data(), j.as_string_view().length()))
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_bigint));
+ }
+ return basic_bigint<Allocator>::from_string(j.as_string_view().data(), j.as_string_view().length());
+ case json_type::half_value:
+ case json_type::double_value:
+ return basic_bigint<Allocator>(j.template as<int64_t>());
+ case json_type::int64_value:
+ return basic_bigint<Allocator>(j.template as<int64_t>());
+ case json_type::uint64_value:
+ return basic_bigint<Allocator>(j.template as<uint64_t>());
+ default:
+ JSONCONS_THROW(conv_error(conv_errc::not_bigint));
+ }
+ }
+
+ static Json to_json(const basic_bigint<Allocator>& val)
+ {
+ std::basic_string<char_type> s;
+ val.write_string(s);
+ return Json(s,semantic_tag::bigint);
+ }
+ };
+
+ // std::valarray
+
+ template<class Json, class T>
+ struct json_type_traits<Json, std::valarray<T>>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ bool result = j.is_array();
+ if (result)
+ {
+ for (auto e : j.array_range())
+ {
+ if (!e.template is<T>())
+ {
+ result = false;
+ break;
+ }
+ }
+ }
+ return result;
+ }
+
+ static std::valarray<T> as(const Json& j)
+ {
+ if (j.is_array())
+ {
+ std::valarray<T> v(j.size());
+ for (std::size_t i = 0; i < j.size(); ++i)
+ {
+ v[i] = j[i].template as<T>();
+ }
+ return v;
+ }
+ else
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_array));
+ }
+ }
+
+ static Json to_json(const std::valarray<T>& val)
+ {
+ Json j(json_array_arg);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first,last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+
+ static Json to_json(const std::valarray<T>& val, const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ auto first = std::begin(val);
+ auto last = std::end(val);
+ std::size_t size = std::distance(first,last);
+ j.reserve(size);
+ for (auto it = first; it != last; ++it)
+ {
+ j.push_back(*it);
+ }
+ return j;
+ }
+ };
+
+#if defined(JSONCONS_HAS_STD_VARIANT)
+
+namespace variant_detail
+{
+ template<int N, class Json, class Variant, class ... Args>
+ typename std::enable_if<N == std::variant_size_v<Variant>, bool>::type
+ is_variant(const Json& /*j*/)
+ {
+ return false;
+ }
+
+ template<std::size_t N, class Json, class Variant, class T, class ... U>
+ typename std::enable_if<N < std::variant_size_v<Variant>, bool>::type
+ is_variant(const Json& j)
+ {
+ if (j.template is<T>())
+ {
+ return true;
+ }
+ else
+ {
+ return is_variant<N+1, Json, Variant, U...>(j);
+ }
+ }
+
+ template<int N, class Json, class Variant, class ... Args>
+ typename std::enable_if<N == std::variant_size_v<Variant>, Variant>::type
+ as_variant(const Json& /*j*/)
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_variant));
+ }
+
+ template<std::size_t N, class Json, class Variant, class T, class ... U>
+ typename std::enable_if<N < std::variant_size_v<Variant>, Variant>::type
+ as_variant(const Json& j)
+ {
+ if (j.template is<T>())
+ {
+ Variant var(j.template as<T>());
+ return var;
+ }
+ else
+ {
+ return as_variant<N+1, Json, Variant, U...>(j);
+ }
+ }
+
+ template <class Json>
+ struct variant_to_json_visitor
+ {
+ Json& j_;
+
+ variant_to_json_visitor(Json& j) : j_(j) {}
+
+ template<class T>
+ void operator()(const T& value) const
+ {
+ j_ = value;
+ }
+ };
+
+} // namespace variant_detail
+
+ template<class Json, typename... VariantTypes>
+ struct json_type_traits<Json, std::variant<VariantTypes...>>
+ {
+ public:
+ using variant_type = typename std::variant<VariantTypes...>;
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return variant_detail::is_variant<0,Json,variant_type, VariantTypes...>(j);
+ }
+
+ static std::variant<VariantTypes...> as(const Json& j)
+ {
+ return variant_detail::as_variant<0,Json,variant_type, VariantTypes...>(j);
+ }
+
+ static Json to_json(const std::variant<VariantTypes...>& var)
+ {
+ Json j(json_array_arg);
+ variant_detail::variant_to_json_visitor<Json> visitor(j);
+ std::visit(visitor, var);
+ return j;
+ }
+
+ static Json to_json(const std::variant<VariantTypes...>& var,
+ const allocator_type& alloc)
+ {
+ Json j(json_array_arg, alloc);
+ variant_detail::variant_to_json_visitor<Json> visitor(j);
+ std::visit(visitor, var);
+ return j;
+ }
+ };
+#endif
+
+ // std::chrono::duration
+ template<class Json,class Rep,class Period>
+ struct json_type_traits<Json,std::chrono::duration<Rep,Period>>
+ {
+ using duration_type = std::chrono::duration<Rep,Period>;
+
+ using allocator_type = typename Json::allocator_type;
+
+ static constexpr int64_t nanos_in_milli = 1000000;
+ static constexpr int64_t nanos_in_second = 1000000000;
+ static constexpr int64_t millis_in_second = 1000;
+
+ static bool is(const Json& j) noexcept
+ {
+ return (j.tag() == semantic_tag::epoch_second || j.tag() == semantic_tag::epoch_milli || j.tag() == semantic_tag::epoch_nano);
+ }
+
+ static duration_type as(const Json& j)
+ {
+ return from_json_(j);
+ }
+
+ static Json to_json(const duration_type& val, allocator_type = allocator_type())
+ {
+ return to_json_(val);
+ }
+
+ template <class PeriodT=Period>
+ static
+ typename std::enable_if<std::is_same<PeriodT,std::ratio<1>>::value, duration_type>::type
+ from_json_(const Json& j)
+ {
+ if (j.is_int64() || j.is_uint64() || j.is_double())
+ {
+ auto count = j.template as<Rep>();
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ return duration_type(count);
+ case semantic_tag::epoch_milli:
+ return duration_type(count == 0 ? 0 : count/millis_in_second);
+ case semantic_tag::epoch_nano:
+ return duration_type(count == 0 ? 0 : count/nanos_in_second);
+ default:
+ return duration_type(count);
+ }
+ }
+ else if (j.is_string())
+ {
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ {
+ auto count = j.template as<Rep>();
+ return duration_type(count);
+ }
+ case semantic_tag::epoch_milli:
+ {
+ auto sv = j.as_string_view();
+ bigint n = bigint::from_string(sv.data(), sv.length());
+ if (n != 0)
+ {
+ n = n / millis_in_second;
+ }
+ return duration_type(static_cast<Rep>(n));
+ }
+ case semantic_tag::epoch_nano:
+ {
+ auto sv = j.as_string_view();
+ bigint n = bigint::from_string(sv.data(), sv.length());
+ if (n != 0)
+ {
+ n = n / nanos_in_second;
+ }
+ return duration_type(static_cast<Rep>(n));
+ }
+ default:
+ {
+ auto count = j.template as<Rep>();
+ return duration_type(count);
+ }
+ }
+ }
+ else
+ {
+ return duration_type();
+ }
+ }
+
+ template <class PeriodT=Period>
+ static
+ typename std::enable_if<std::is_same<PeriodT,std::milli>::value, duration_type>::type
+ from_json_(const Json& j)
+ {
+ if (j.is_int64() || j.is_uint64())
+ {
+ auto count = j.template as<Rep>();
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ return duration_type(count*millis_in_second);
+ case semantic_tag::epoch_milli:
+ return duration_type(count);
+ case semantic_tag::epoch_nano:
+ return duration_type(count == 0 ? 0 : count/nanos_in_milli);
+ default:
+ return duration_type(count);
+ }
+ }
+ else if (j.is_double())
+ {
+ auto count = j.template as<double>();
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ return duration_type(static_cast<Rep>(count * millis_in_second));
+ case semantic_tag::epoch_milli:
+ return duration_type(static_cast<Rep>(count));
+ case semantic_tag::epoch_nano:
+ return duration_type(count == 0 ? 0 : static_cast<Rep>(count / nanos_in_milli));
+ default:
+ return duration_type(static_cast<Rep>(count));
+ }
+ }
+ else if (j.is_string())
+ {
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ {
+ auto count = j.template as<Rep>();
+ return duration_type(count*millis_in_second);
+ }
+ case semantic_tag::epoch_milli:
+ {
+ auto sv = j.as_string_view();
+ Rep n{0};
+ auto result = jsoncons::detail::to_integer_decimal(sv.data(), sv.size(), n);
+ if (!result)
+ {
+ return duration_type();
+ }
+ return duration_type(n);
+ }
+ case semantic_tag::epoch_nano:
+ {
+ auto sv = j.as_string_view();
+ bigint n = bigint::from_string(sv.data(), sv.length());
+ if (n != 0)
+ {
+ n = n / nanos_in_milli;
+ }
+ return duration_type(static_cast<Rep>(n));
+ }
+ default:
+ {
+ auto count = j.template as<Rep>();
+ return duration_type(count);
+ }
+ }
+ }
+ else
+ {
+ return duration_type();
+ }
+ }
+
+ template <class PeriodT=Period>
+ static
+ typename std::enable_if<std::is_same<PeriodT,std::nano>::value, duration_type>::type
+ from_json_(const Json& j)
+ {
+ if (j.is_int64() || j.is_uint64() || j.is_double())
+ {
+ auto count = j.template as<Rep>();
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ return duration_type(count*nanos_in_second);
+ case semantic_tag::epoch_milli:
+ return duration_type(count*nanos_in_milli);
+ case semantic_tag::epoch_nano:
+ return duration_type(count);
+ default:
+ return duration_type(count);
+ }
+ }
+ else if (j.is_double())
+ {
+ auto count = j.template as<double>();
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ return duration_type(static_cast<Rep>(count * nanos_in_second));
+ case semantic_tag::epoch_milli:
+ return duration_type(static_cast<Rep>(count * nanos_in_milli));
+ case semantic_tag::epoch_nano:
+ return duration_type(static_cast<Rep>(count));
+ default:
+ return duration_type(static_cast<Rep>(count));
+ }
+ }
+ else if (j.is_string())
+ {
+ auto count = j.template as<Rep>();
+ switch (j.tag())
+ {
+ case semantic_tag::epoch_second:
+ return duration_type(count*nanos_in_second);
+ case semantic_tag::epoch_milli:
+ return duration_type(count*nanos_in_milli);
+ case semantic_tag::epoch_nano:
+ return duration_type(count);
+ default:
+ return duration_type(count);
+ }
+ }
+ else
+ {
+ return duration_type();
+ }
+ }
+
+ template <class PeriodT=Period>
+ static
+ typename std::enable_if<std::is_same<PeriodT,std::ratio<1>>::value,Json>::type
+ to_json_(const duration_type& val)
+ {
+ return Json(val.count(), semantic_tag::epoch_second);
+ }
+
+ template <class PeriodT=Period>
+ static
+ typename std::enable_if<std::is_same<PeriodT,std::milli>::value,Json>::type
+ to_json_(const duration_type& val)
+ {
+ return Json(val.count(), semantic_tag::epoch_milli);
+ }
+
+ template <class PeriodT=Period>
+ static
+ typename std::enable_if<std::is_same<PeriodT,std::nano>::value,Json>::type
+ to_json_(const duration_type& val)
+ {
+ return Json(val.count(), semantic_tag::epoch_nano);
+ }
+ };
+
+ // std::nullptr_t
+ template <class Json>
+ struct json_type_traits<Json,std::nullptr_t>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ return j.is_null();
+ }
+
+ static std::nullptr_t as(const Json& j)
+ {
+ if (!j.is_null())
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_nullptr));
+ }
+ return nullptr;
+ }
+
+ static Json to_json(const std::nullptr_t&, allocator_type = allocator_type())
+ {
+ return Json::null();
+ }
+ };
+
+ // std::bitset
+
+ struct null_back_insertable_byte_container
+ {
+ using value_type = uint8_t;
+
+ void push_back(value_type)
+ {
+ }
+ };
+
+ template<class Json, std::size_t N>
+ struct json_type_traits<Json, std::bitset<N>>
+ {
+ using allocator_type = typename Json::allocator_type;
+
+ static bool is(const Json& j) noexcept
+ {
+ if (j.is_byte_string())
+ {
+ return true;
+ }
+ else if (j.is_string())
+ {
+ jsoncons::string_view sv = j.as_string_view();
+ null_back_insertable_byte_container cont;
+ auto result = decode_base16(sv.begin(), sv.end(), cont);
+ return result.ec == conv_errc::success ? true : false;
+ }
+ return false;
+ }
+
+ static std::bitset<N> as(const Json& j)
+ {
+ if (j.template is<uint64_t>())
+ {
+ auto bits = j.template as<uint64_t>();
+ std::bitset<N> bs = static_cast<unsigned long long>(bits);
+ return bs;
+ }
+ else if (j.is_byte_string() || j.is_string())
+ {
+ std::bitset<N> bs;
+ std::vector<uint8_t> bits;
+ if (j.is_byte_string())
+ {
+ bits = j.template as<std::vector<uint8_t>>();
+ }
+ else
+ {
+ jsoncons::string_view sv = j.as_string_view();
+ auto result = decode_base16(sv.begin(), sv.end(), bits);
+ if (result.ec != conv_errc::success)
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_bitset));
+ }
+ }
+ std::uint8_t byte = 0;
+ std::uint8_t mask = 0;
+
+ std::size_t pos = 0;
+ for (std::size_t i = 0; i < N; ++i)
+ {
+ if (mask == 0)
+ {
+ if (pos >= bits.size())
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_bitset));
+ }
+ byte = bits.at(pos++);
+ mask = 0x80;
+ }
+
+ if (byte & mask)
+ {
+ bs[i] = 1;
+ }
+
+ mask = static_cast<std::uint8_t>(mask >> 1);
+ }
+ return bs;
+ }
+ else
+ {
+ JSONCONS_THROW(conv_error(conv_errc::not_bitset));
+ }
+ }
+
+ static Json to_json(const std::bitset<N>& val,
+ const allocator_type& alloc = allocator_type())
+ {
+ std::vector<uint8_t> bits;
+
+ uint8_t byte = 0;
+ uint8_t mask = 0x80;
+
+ for (std::size_t i = 0; i < N; ++i)
+ {
+ if (val[i])
+ {
+ byte |= mask;
+ }
+
+ mask = static_cast<uint8_t>(mask >> 1);
+
+ if (mask == 0)
+ {
+ bits.push_back(byte);
+ byte = 0;
+ mask = 0x80;
+ }
+ }
+
+ // Encode remainder
+ if (mask != 0x80)
+ {
+ bits.push_back(byte);
+ }
+
+ Json j(byte_string_arg, bits, semantic_tag::base16, alloc);
+ return j;
+ }
+ };
+
+} // jsoncons
+
+#endif