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
194
195
//
// 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_TO_HPP
#define BOOST_JSON_DETAIL_VALUE_TO_HPP
 
#include <boost/json/value.hpp>
#include <boost/json/detail/value_traits.hpp>
 
#include <type_traits>
 
BOOST_JSON_NS_BEGIN
 
template<class>
struct value_to_tag { };
 
template<class, class = void>
struct has_value_to;
 
template<class T, class U,
    typename std::enable_if<
        ! std::is_reference<T>::value &&
    std::is_same<U, value>::value>::type* = nullptr>
T value_to(U const&);
 
namespace detail {
 
//----------------------------------------------------------
// Use native conversion
 
// identity conversion
inline
value
tag_invoke(
    value_to_tag<value>,
    value const& jv)
{
    return jv;
}
 
// object
inline
object
tag_invoke(
    value_to_tag<object>,
    value const& jv)
{
    return jv.as_object();
}
 
// array
inline
array
tag_invoke(
    value_to_tag<array>,
    value const& jv)
{
    return jv.as_array();
}
 
// string
inline
string
tag_invoke(
    value_to_tag<string>,
    value const& jv)
{
    return jv.as_string();
}
 
// bool
inline
bool
tag_invoke(
    value_to_tag<bool>,
    value const& jv)
{
    return jv.as_bool();
}
 
// integral and floating point
template<class T, typename std::enable_if<
    std::is_arithmetic<T>::value>::type* = nullptr>
T
tag_invoke(
    value_to_tag<T>,
    value const& jv)
{
    return jv.to_number<T>();
}
 
//----------------------------------------------------------
// Use generic conversion
 
// 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<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>
T
value_to_generic(
    const value& jv,
    priority_tag<2>)
{
    auto& str = jv.as_string();
    return T(str.data(), str.size());
}
 
// map like containers
template<class T, typename std::enable_if<
    has_value_to<typename map_traits<T>::pair_value_type>::value &&
        std::is_constructible<typename map_traits<T>::pair_key_type, 
    string_view>::value>::type* = nullptr>
T
value_to_generic(
    const value& jv, 
    priority_tag<1>)
{
    using value_type = typename
        container_traits<T>::value_type;
    const object& obj = jv.as_object();
    T result;
    container_traits<T>::try_reserve(
        result, obj.size());
    for (const auto& val : obj)
        result.insert(value_type{typename map_traits<T>::
            pair_key_type(val.key()), value_to<typename
                map_traits<T>::pair_value_type>(val.value())});
    return result;
}
 
// all other containers
template<class T, typename std::enable_if<
    has_value_to<typename container_traits<T>::
        value_type>::value>::type* = nullptr>
T
value_to_generic(
    const value& jv,
    priority_tag<0>)
{
    const array& arr = jv.as_array();
    T result;
    container_traits<T>::try_reserve(
        result, arr.size());
    for (const auto& val : arr)
        result.insert(end(result), value_to<typename
            container_traits<T>::value_type>(val));
    return result;
}
 
// Matches containers
template<class T, void_t<typename std::enable_if<
    !std::is_constructible<T, const value&>::value &&
        !std::is_arithmetic<T>::value>::type, decltype(
    value_to_generic<T>(std::declval<const value&>(), 
        priority_tag<2>()))>* = nullptr>
T
tag_invoke(
    value_to_tag<T>,
    value const& jv)
{
    return value_to_generic<T>(
        jv, priority_tag<2>());
}
 
//----------------------------------------------------------
 
// Calls to value_to 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_to_tag<T>&>(),
        std::declval<const value&>()))>* = nullptr>
T
value_to_impl(
    value_to_tag<T> tag,
    value const& jv)
{
    return tag_invoke(tag, jv);
}
 
} // detail
BOOST_JSON_NS_END
 
#endif