liuxiaolong
2021-07-20 58d904a328c0d849769b483e901a0be9426b8209
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
//
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
// Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// Official repository: https://github.com/boostorg/json
//
 
#ifndef BOOST_JSON_DETAIL_VALUE_FROM_HPP
#define BOOST_JSON_DETAIL_VALUE_FROM_HPP
 
#include <boost/json/storage_ptr.hpp>
#include <boost/json/value.hpp>
#include <boost/json/detail/value_traits.hpp>
 
BOOST_JSON_NS_BEGIN
 
struct value_from_tag { };
 
template<class T, class = void>
struct has_value_from;
 
namespace detail {
 
// The integral_constant parameter here is an
// rvalue reference to make the standard conversion
// sequence to that parameter better, see
// http://eel.is/c++draft/over.ics.rank#3.2.6
template<std::size_t N, class T>
void
tuple_to_array(
    T&&,
    array&,
    std::integral_constant<std::size_t, N>&&)
{
}
 
template<std::size_t N, std::size_t I, class T>
void
tuple_to_array(
    T&& t,
    array& arr,
    const std::integral_constant<std::size_t, I>&)
{
    using std::get;
    arr.emplace_back(value_from(
        get<I>(std::forward<T>(t)), arr.storage()));
    return detail::tuple_to_array<N>(std::forward<T>(t),
        arr, std::integral_constant<std::size_t, I + 1>());
}
 
//----------------------------------------------------------
// Native conversion
 
template<class T, typename std::enable_if<
    detail::value_constructible<T>::value>::type* = nullptr>
void
tag_invoke(
    value_from_tag,
    value& jv,
    T&& from)
{
    jv = std::forward<T>(from);
}
 
template<class T, typename std::enable_if<
    std::is_same<detail::remove_cvref<T>, 
        std::nullptr_t>::value>::type* = nullptr>
void
tag_invoke(
    value_from_tag,
    value& jv,
    T&&)
{
    // do nothing
    BOOST_ASSERT(jv.is_null());
    (void)jv;
}
 
//----------------------------------------------------------
// Generic conversions
 
// string-like types
// NOTE: original check for size used is_convertible but 
// MSVC-140 selects wrong specialisation if used
template<class T, typename std::enable_if<
    std::is_constructible<remove_cvref<T>, const char*, std::size_t>::value &&
    std::is_convertible<decltype(std::declval<T&>().data()), const char*>::value && 
    std::is_integral<decltype(std::declval<T&>().size())>::value
>::type* = nullptr>
void 
value_from_generic(
    value& jv,
    T&& from,
    priority_tag<3>)
{
    jv.emplace_string().assign(
        from.data(), from.size());
}
 
// tuple-like types
template<class T, typename std::enable_if<
    (std::tuple_size<remove_cvref<T>>::value > 0)>::type* = nullptr>
void
value_from_generic(
    value& jv,
    T&& from,
    priority_tag<2>)
{
    constexpr std::size_t n =
        std::tuple_size<remove_cvref<T>>::value;
    array& arr = jv.emplace_array();
    arr.reserve(n);
    detail::tuple_to_array<n>(std::forward<T>(from),
        arr, std::integral_constant<std::size_t, 0>());
}
 
// map-like types
template<class T, typename std::enable_if<
    map_traits<T>::has_unique_keys && 
        has_value_from<typename map_traits<T>::pair_value_type>::value &&
    std::is_convertible<typename map_traits<T>::pair_key_type, 
        string_view>::value>::type* = nullptr>
void
value_from_generic(
    value& jv,
    T&& from,
    priority_tag<1>)
{
    using std::get;
    object& obj = jv.emplace_object();
    obj.reserve(container_traits<T>::try_size(from));
    for (auto&& elem : from)
        obj.emplace(get<0>(elem), value_from(
            get<1>(elem), obj.storage()));
}
 
// all other containers
template<class T, typename std::enable_if<
    has_value_from<typename container_traits<T>::
        value_type>::value>::type* = nullptr>
void
value_from_generic(
    value& jv,
    T&& from,
    priority_tag<0>)
{
    array& result = jv.emplace_array();
    result.reserve(container_traits<T>::try_size(from));
    for (auto&& elem : from)
        result.emplace_back(
            value_from(elem, result.storage()));
}
 
template<class T, void_t<typename std::enable_if<
    ! detail::value_constructible<T>::value && ! std::is_same<
        detail::remove_cvref<T>, std::nullptr_t>::value>::type,
    decltype(detail::value_from_generic(std::declval<value&>(), 
        std::declval<T&&>(), priority_tag<3>()))>* = nullptr>
void
tag_invoke(
    value_from_tag,
    value& jv,
    T&& from)
{
    detail::value_from_generic(jv,
        std::forward<T>(from), priority_tag<3>());
}
 
//----------------------------------------------------------
 
// Calls to value_from are forwarded to this function
// so we can use ADL and hide the built-in tag_invoke
// overloads in the detail namespace
template<class T, void_t<
    decltype(tag_invoke(std::declval<value_from_tag&>(),
        std::declval<value&>(), std::declval<T&&>()))>* = nullptr>
value
value_from_impl(
    T&& from,
    storage_ptr sp)
{
    value jv(std::move(sp));
    tag_invoke(value_from_tag(), jv, std::forward<T>(from));
    return jv;
}
 
} // detail
BOOST_JSON_NS_END
 
#endif