1//
2// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7// Official repository: https://github.com/boostorg/json
8//
9
10#ifndef BOOST_JSON_IMPL_VALUE_REF_IPP
11#define BOOST_JSON_IMPL_VALUE_REF_IPP
12
13#include <boost/json/value_ref.hpp>
14#include <boost/json/array.hpp>
15#include <boost/json/value.hpp>
16
17BOOST_JSON_NS_BEGIN
18
19value_ref::
20operator
21value() const
22{
23    return make_value({});
24}
25
26value
27value_ref::
28from_init_list(
29    void const* p,
30    storage_ptr sp)
31{
32    return make_value(
33        *reinterpret_cast<
34            init_list const*>(p),
35        std::move(sp));
36}
37
38bool
39value_ref::
40is_key_value_pair() const noexcept
41{
42    if(what_ != what::ini)
43        return false;
44    if(arg_.init_list_.size() != 2)
45        return false;
46    auto const& e =
47        *arg_.init_list_.begin();
48    if( e.what_ != what::str &&
49        e.what_ != what::strfunc)
50        return false;
51    return true;
52}
53
54bool
55value_ref::
56maybe_object(
57    std::initializer_list<
58        value_ref> init) noexcept
59{
60    for(auto const& e : init)
61        if(! e.is_key_value_pair())
62            return false;
63    return true;
64}
65
66string_view
67value_ref::
68get_string() const noexcept
69{
70    BOOST_ASSERT(
71        what_ == what::str ||
72        what_ == what::strfunc);
73    if (what_ == what::strfunc)
74        return *static_cast<const string*>(f_.p);
75    return arg_.str_;
76}
77
78value
79value_ref::
80make_value(
81    storage_ptr sp) const
82{
83    switch(what_)
84    {
85    default:
86    case what::str:
87        return string(
88            arg_.str_,
89            std::move(sp));
90
91    case what::ini:
92        return make_value(
93            arg_.init_list_,
94            std::move(sp));
95
96    case what::func:
97        return f_.f(f_.p,
98            std::move(sp));
99
100    case what::strfunc:
101        return f_.f(f_.p,
102            std::move(sp));
103
104    case what::cfunc:
105        return cf_.f(cf_.p,
106            std::move(sp));
107    }
108}
109
110value
111value_ref::
112make_value(
113    std::initializer_list<
114        value_ref> init,
115    storage_ptr sp)
116{
117    if(maybe_object(init))
118        return make_object(
119            init, std::move(sp));
120    return make_array(
121        init, std::move(sp));
122}
123
124object
125value_ref::
126make_object(
127    std::initializer_list<value_ref> init,
128    storage_ptr sp)
129{
130    object obj(std::move(sp));
131    obj.reserve(init.size());
132    for(auto const& e : init)
133        obj.emplace(
134            e.arg_.init_list_.begin()[0].get_string(),
135            e.arg_.init_list_.begin()[1].make_value(
136                obj.storage()));
137    return obj;
138}
139
140array
141value_ref::
142make_array(
143    std::initializer_list<
144        value_ref> init,
145    storage_ptr sp)
146{
147    array arr(std::move(sp));
148    arr.reserve(init.size());
149    for(auto const& e : init)
150        arr.emplace_back(
151            e.make_value(
152                arr.storage()));
153    return arr;
154}
155
156void
157value_ref::
158write_array(
159    value* dest,
160    std::initializer_list<
161        value_ref> init,
162    storage_ptr const& sp)
163{
164    struct undo
165    {
166        value* const base;
167        value* pos;
168        ~undo()
169        {
170            if(pos)
171                while(pos > base)
172                    (--pos)->~value();
173        }
174    };
175    undo u{dest, dest};
176    for(auto const& e : init)
177    {
178        ::new(u.pos) value(
179            e.make_value(sp));
180        ++u.pos;
181    }
182    u.pos = nullptr;
183}
184
185BOOST_JSON_NS_END
186
187#endif
188