1  
//
1  
//
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
2  
// Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3  
//
3  
//
4  
// Distributed under the Boost Software License, Version 1.0. (See accompanying
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)
5  
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  
//
6  
//
7  
// Official repository: https://github.com/boostorg/json
7  
// Official repository: https://github.com/boostorg/json
8  
//
8  
//
9  

9  

10  
#ifndef BOOST_JSON_IMPL_ARRAY_IPP
10  
#ifndef BOOST_JSON_IMPL_ARRAY_IPP
11  
#define BOOST_JSON_IMPL_ARRAY_IPP
11  
#define BOOST_JSON_IMPL_ARRAY_IPP
12  

12  

13  
#include <boost/core/detail/static_assert.hpp>
13  
#include <boost/core/detail/static_assert.hpp>
14  
#include <boost/container_hash/hash.hpp>
14  
#include <boost/container_hash/hash.hpp>
15  
#include <boost/json/array.hpp>
15  
#include <boost/json/array.hpp>
16  
#include <boost/json/pilfer.hpp>
16  
#include <boost/json/pilfer.hpp>
17  
#include <boost/json/detail/except.hpp>
17  
#include <boost/json/detail/except.hpp>
18  
#include <cstdlib>
18  
#include <cstdlib>
19  
#include <limits>
19  
#include <limits>
20  
#include <new>
20  
#include <new>
21  
#include <utility>
21  
#include <utility>
22  

22  

23  
namespace boost {
23  
namespace boost {
24  
namespace json {
24  
namespace json {
25  

25  

26  
//----------------------------------------------------------
26  
//----------------------------------------------------------
27  

27  

28  
constexpr array::table::table() = default;
28  
constexpr array::table::table() = default;
29  

29  

30  
// empty arrays point here
30  
// empty arrays point here
31  
BOOST_JSON_REQUIRE_CONST_INIT
31  
BOOST_JSON_REQUIRE_CONST_INIT
32  
array::table array::empty_;
32  
array::table array::empty_;
33  

33  

34  
auto
34  
auto
35  
array::
35  
array::
36  
table::
36  
table::
37  
allocate(
37  
allocate(
38  
    std::size_t capacity,
38  
    std::size_t capacity,
39  
    storage_ptr const& sp) ->
39  
    storage_ptr const& sp) ->
40  
        table*
40  
        table*
41  
{
41  
{
42  
    BOOST_ASSERT(capacity > 0);
42  
    BOOST_ASSERT(capacity > 0);
43  
    if(capacity > array::max_size())
43  
    if(capacity > array::max_size())
44  
    {
44  
    {
45  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
45  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
46  
        detail::throw_system_error( error::array_too_large, &loc );
46  
        detail::throw_system_error( error::array_too_large, &loc );
47  
    }
47  
    }
48  
    auto p = reinterpret_cast<
48  
    auto p = reinterpret_cast<
49  
        table*>(sp->allocate(
49  
        table*>(sp->allocate(
50  
            sizeof(table) +
50  
            sizeof(table) +
51  
                capacity * sizeof(value),
51  
                capacity * sizeof(value),
52  
            alignof(value)));
52  
            alignof(value)));
53  
    p->capacity = static_cast<
53  
    p->capacity = static_cast<
54  
        std::uint32_t>(capacity);
54  
        std::uint32_t>(capacity);
55  
    return p;
55  
    return p;
56  
}
56  
}
57  

57  

58  
void
58  
void
59  
array::
59  
array::
60  
table::
60  
table::
61  
deallocate(
61  
deallocate(
62  
    table* p,
62  
    table* p,
63  
    storage_ptr const& sp)
63  
    storage_ptr const& sp)
64  
{
64  
{
65  
    if(p->capacity == 0)
65  
    if(p->capacity == 0)
66  
        return;
66  
        return;
67  
    sp->deallocate(p,
67  
    sp->deallocate(p,
68  
        sizeof(table) +
68  
        sizeof(table) +
69  
            p->capacity * sizeof(value),
69  
            p->capacity * sizeof(value),
70  
        alignof(value));
70  
        alignof(value));
71  
}
71  
}
72  

72  

73  
//----------------------------------------------------------
73  
//----------------------------------------------------------
74  

74  

75  
array::
75  
array::
76  
revert_insert::
76  
revert_insert::
77  
revert_insert(
77  
revert_insert(
78  
    const_iterator pos,
78  
    const_iterator pos,
79  
    std::size_t n,
79  
    std::size_t n,
80  
    array& arr)
80  
    array& arr)
81  
    : arr_(&arr)
81  
    : arr_(&arr)
82  
    , i_(pos - arr_->data())
82  
    , i_(pos - arr_->data())
83  
    , n_(n)
83  
    , n_(n)
84  
{
84  
{
85  
    BOOST_ASSERT(
85  
    BOOST_ASSERT(
86  
        pos >= arr_->begin() &&
86  
        pos >= arr_->begin() &&
87  
        pos <= arr_->end());
87  
        pos <= arr_->end());
88  
    if( n_ <= arr_->capacity() -
88  
    if( n_ <= arr_->capacity() -
89  
        arr_->size())
89  
        arr_->size())
90  
    {
90  
    {
91  
        // fast path
91  
        // fast path
92  
        p = arr_->data() + i_;
92  
        p = arr_->data() + i_;
93  
        if(n_ == 0)
93  
        if(n_ == 0)
94  
            return;
94  
            return;
95  
        relocate(
95  
        relocate(
96  
            p + n_,
96  
            p + n_,
97  
            p,
97  
            p,
98  
            arr_->size() - i_);
98  
            arr_->size() - i_);
99  
        arr_->t_->size = static_cast<
99  
        arr_->t_->size = static_cast<
100  
            std::uint32_t>(
100  
            std::uint32_t>(
101  
                arr_->t_->size + n_);
101  
                arr_->t_->size + n_);
102  
        return;
102  
        return;
103  
    }
103  
    }
104  
    if(n_ > max_size() - arr_->size())
104  
    if(n_ > max_size() - arr_->size())
105  
    {
105  
    {
106  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
106  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
107  
        detail::throw_system_error( error::array_too_large, &loc );
107  
        detail::throw_system_error( error::array_too_large, &loc );
108  
    }
108  
    }
109  
    auto t = table::allocate(
109  
    auto t = table::allocate(
110  
        arr_->growth(arr_->size() + n_),
110  
        arr_->growth(arr_->size() + n_),
111  
            arr_->sp_);
111  
            arr_->sp_);
112  
    t->size = static_cast<std::uint32_t>(
112  
    t->size = static_cast<std::uint32_t>(
113  
        arr_->size() + n_);
113  
        arr_->size() + n_);
114  
    p = &(*t)[0] + i_;
114  
    p = &(*t)[0] + i_;
115  
    relocate(
115  
    relocate(
116  
        &(*t)[0],
116  
        &(*t)[0],
117  
        arr_->data(),
117  
        arr_->data(),
118  
        i_);
118  
        i_);
119  
    relocate(
119  
    relocate(
120  
        &(*t)[i_ + n_],
120  
        &(*t)[i_ + n_],
121  
        arr_->data() + i_,
121  
        arr_->data() + i_,
122  
        arr_->size() - i_);
122  
        arr_->size() - i_);
123  
    t = detail::exchange(arr_->t_, t);
123  
    t = detail::exchange(arr_->t_, t);
124  
    table::deallocate(t, arr_->sp_);
124  
    table::deallocate(t, arr_->sp_);
125  
}
125  
}
126  

126  

127  
array::
127  
array::
128  
revert_insert::
128  
revert_insert::
129  
~revert_insert()
129  
~revert_insert()
130  
{
130  
{
131  
    if(! arr_)
131  
    if(! arr_)
132  
        return;
132  
        return;
133  
    BOOST_ASSERT(n_ != 0);
133  
    BOOST_ASSERT(n_ != 0);
134  
    auto const pos =
134  
    auto const pos =
135  
        arr_->data() + i_;
135  
        arr_->data() + i_;
136  
    arr_->destroy(pos, p);
136  
    arr_->destroy(pos, p);
137  
    arr_->t_->size = static_cast<
137  
    arr_->t_->size = static_cast<
138  
        std::uint32_t>(
138  
        std::uint32_t>(
139  
            arr_->t_->size - n_);
139  
            arr_->t_->size - n_);
140  
    relocate(
140  
    relocate(
141  
        pos,
141  
        pos,
142  
        pos + n_,
142  
        pos + n_,
143  
        arr_->size() - i_);
143  
        arr_->size() - i_);
144  
}
144  
}
145  

145  

146  
//----------------------------------------------------------
146  
//----------------------------------------------------------
147  

147  

148  
void
148  
void
149  
array::
149  
array::
150  
destroy(
150  
destroy(
151  
    value* first, value* last) noexcept
151  
    value* first, value* last) noexcept
152  
{
152  
{
153  
    if(sp_.is_not_shared_and_deallocate_is_trivial())
153  
    if(sp_.is_not_shared_and_deallocate_is_trivial())
154  
        return;
154  
        return;
155  
    while(last-- != first)
155  
    while(last-- != first)
156  
        last->~value();
156  
        last->~value();
157  
}
157  
}
158  

158  

159  
void
159  
void
160  
array::
160  
array::
161  
destroy() noexcept
161  
destroy() noexcept
162  
{
162  
{
163  
    if(sp_.is_not_shared_and_deallocate_is_trivial())
163  
    if(sp_.is_not_shared_and_deallocate_is_trivial())
164  
        return;
164  
        return;
165  
    auto last = end();
165  
    auto last = end();
166  
    auto const first = begin();
166  
    auto const first = begin();
167  
    while(last-- != first)
167  
    while(last-- != first)
168  
        last->~value();
168  
        last->~value();
169  
    table::deallocate(t_, sp_);
169  
    table::deallocate(t_, sp_);
170  
}
170  
}
171  

171  

172  
//----------------------------------------------------------
172  
//----------------------------------------------------------
173  
//
173  
//
174  
// Special Members
174  
// Special Members
175  
//
175  
//
176  
//----------------------------------------------------------
176  
//----------------------------------------------------------
177  

177  

178  
array::
178  
array::
179  
array(detail::unchecked_array&& ua)
179  
array(detail::unchecked_array&& ua)
180  
    : sp_(ua.storage())
180  
    : sp_(ua.storage())
181  
{
181  
{
182  
    BOOST_CORE_STATIC_ASSERT( alignof(table) == alignof(value) );
182  
    BOOST_CORE_STATIC_ASSERT( alignof(table) == alignof(value) );
183  
    if(ua.size() == 0)
183  
    if(ua.size() == 0)
184  
    {
184  
    {
185  
        t_ = &empty_;
185  
        t_ = &empty_;
186  
        return;
186  
        return;
187  
    }
187  
    }
188  
    t_= table::allocate(
188  
    t_= table::allocate(
189  
        ua.size(), sp_);
189  
        ua.size(), sp_);
190  
    t_->size = static_cast<
190  
    t_->size = static_cast<
191  
        std::uint32_t>(ua.size());
191  
        std::uint32_t>(ua.size());
192  
    ua.relocate(data());
192  
    ua.relocate(data());
193  
}
193  
}
194  

194  

195  
array::
195  
array::
196  
~array() noexcept
196  
~array() noexcept
197  
{
197  
{
198  
    destroy();
198  
    destroy();
199  
}
199  
}
200  

200  

201  
array::
201  
array::
202  
array(
202  
array(
203  
    std::size_t count,
203  
    std::size_t count,
204  
    value const& v,
204  
    value const& v,
205  
    storage_ptr sp)
205  
    storage_ptr sp)
206  
    : sp_(std::move(sp))
206  
    : sp_(std::move(sp))
207  
{
207  
{
208  
    if(count == 0)
208  
    if(count == 0)
209  
    {
209  
    {
210  
        t_ = &empty_;
210  
        t_ = &empty_;
211  
        return;
211  
        return;
212  
    }
212  
    }
213  
    t_= table::allocate(
213  
    t_= table::allocate(
214  
        count, sp_);
214  
        count, sp_);
215  
    t_->size = 0;
215  
    t_->size = 0;
216  
    revert_construct r(*this);
216  
    revert_construct r(*this);
217  
    while(count--)
217  
    while(count--)
218  
    {
218  
    {
219  
        ::new(end()) value(v, sp_);
219  
        ::new(end()) value(v, sp_);
220  
        ++t_->size;
220  
        ++t_->size;
221  
    }
221  
    }
222  
    r.commit();
222  
    r.commit();
223  
}
223  
}
224  

224  

225  
array::
225  
array::
226  
array(
226  
array(
227  
    std::size_t count,
227  
    std::size_t count,
228  
    storage_ptr sp)
228  
    storage_ptr sp)
229  
    : sp_(std::move(sp))
229  
    : sp_(std::move(sp))
230  
{
230  
{
231  
    if(count == 0)
231  
    if(count == 0)
232  
    {
232  
    {
233  
        t_ = &empty_;
233  
        t_ = &empty_;
234  
        return;
234  
        return;
235  
    }
235  
    }
236  
    t_ = table::allocate(
236  
    t_ = table::allocate(
237  
        count, sp_);
237  
        count, sp_);
238  
    t_->size = static_cast<
238  
    t_->size = static_cast<
239  
        std::uint32_t>(count);
239  
        std::uint32_t>(count);
240  
    auto p = data();
240  
    auto p = data();
241  
    do
241  
    do
242  
    {
242  
    {
243  
        ::new(p++) value(sp_);
243  
        ::new(p++) value(sp_);
244  
    }
244  
    }
245  
    while(--count);
245  
    while(--count);
246  
}
246  
}
247  

247  

248  
array::
248  
array::
249  
array(array const& other)
249  
array(array const& other)
250  
    : array(other, other.sp_)
250  
    : array(other, other.sp_)
251  
{
251  
{
252  
}
252  
}
253  

253  

254  
array::
254  
array::
255  
array(
255  
array(
256  
    array const& other,
256  
    array const& other,
257  
    storage_ptr sp)
257  
    storage_ptr sp)
258  
    : sp_(std::move(sp))
258  
    : sp_(std::move(sp))
259  
{
259  
{
260  
    if(other.empty())
260  
    if(other.empty())
261  
    {
261  
    {
262  
        t_ = &empty_;
262  
        t_ = &empty_;
263  
        return;
263  
        return;
264  
    }
264  
    }
265  
    t_ = table::allocate(
265  
    t_ = table::allocate(
266  
        other.size(), sp_);
266  
        other.size(), sp_);
267  
    t_->size = 0;
267  
    t_->size = 0;
268  
    revert_construct r(*this);
268  
    revert_construct r(*this);
269  
    auto src = other.data();
269  
    auto src = other.data();
270  
    auto dest = data();
270  
    auto dest = data();
271  
    auto const n = other.size();
271  
    auto const n = other.size();
272  
    do
272  
    do
273  
    {
273  
    {
274  
        ::new(dest++) value(
274  
        ::new(dest++) value(
275  
            *src++, sp_);
275  
            *src++, sp_);
276  
        ++t_->size;
276  
        ++t_->size;
277  
    }
277  
    }
278  
    while(t_->size < n);
278  
    while(t_->size < n);
279  
    r.commit();
279  
    r.commit();
280  
}
280  
}
281  

281  

282  
array::
282  
array::
283  
array(
283  
array(
284  
    array&& other,
284  
    array&& other,
285  
    storage_ptr sp)
285  
    storage_ptr sp)
286  
    : sp_(std::move(sp))
286  
    : sp_(std::move(sp))
287  
{
287  
{
288  
    if(*sp_ == *other.sp_)
288  
    if(*sp_ == *other.sp_)
289  
    {
289  
    {
290  
        // same resource
290  
        // same resource
291  
        t_ = detail::exchange(
291  
        t_ = detail::exchange(
292  
            other.t_, &empty_);
292  
            other.t_, &empty_);
293  
        return;
293  
        return;
294  
    }
294  
    }
295  
    else if(other.empty())
295  
    else if(other.empty())
296  
    {
296  
    {
297  
        t_ = &empty_;
297  
        t_ = &empty_;
298  
        return;
298  
        return;
299  
    }
299  
    }
300  
    // copy
300  
    // copy
301  
    t_ = table::allocate(
301  
    t_ = table::allocate(
302  
        other.size(), sp_);
302  
        other.size(), sp_);
303  
    t_->size = 0;
303  
    t_->size = 0;
304  
    revert_construct r(*this);
304  
    revert_construct r(*this);
305  
    auto src = other.data();
305  
    auto src = other.data();
306  
    auto dest = data();
306  
    auto dest = data();
307  
    auto const n = other.size();
307  
    auto const n = other.size();
308  
    do
308  
    do
309  
    {
309  
    {
310  
        ::new(dest++) value(
310  
        ::new(dest++) value(
311  
            *src++, sp_);
311  
            *src++, sp_);
312  
        ++t_->size;
312  
        ++t_->size;
313  
    }
313  
    }
314  
    while(t_->size < n);
314  
    while(t_->size < n);
315  
    r.commit();
315  
    r.commit();
316  
}
316  
}
317  

317  

318  
array::
318  
array::
319  
array(
319  
array(
320  
    std::initializer_list<
320  
    std::initializer_list<
321  
        value_ref> init,
321  
        value_ref> init,
322  
    storage_ptr sp)
322  
    storage_ptr sp)
323  
    : sp_(std::move(sp))
323  
    : sp_(std::move(sp))
324  
{
324  
{
325  
    if(init.size() == 0)
325  
    if(init.size() == 0)
326  
    {
326  
    {
327  
        t_ = &empty_;
327  
        t_ = &empty_;
328  
        return;
328  
        return;
329  
    }
329  
    }
330  
    t_ = table::allocate(
330  
    t_ = table::allocate(
331  
        init.size(), sp_);
331  
        init.size(), sp_);
332  
    t_->size = 0;
332  
    t_->size = 0;
333  
    revert_construct r(*this);
333  
    revert_construct r(*this);
334  
    value_ref::write_array(
334  
    value_ref::write_array(
335  
        data(), init, sp_);
335  
        data(), init, sp_);
336  
    t_->size = static_cast<
336  
    t_->size = static_cast<
337  
        std::uint32_t>(init.size());
337  
        std::uint32_t>(init.size());
338  
    r.commit();
338  
    r.commit();
339  
}
339  
}
340  

340  

341  
//----------------------------------------------------------
341  
//----------------------------------------------------------
342  

342  

343  
array&
343  
array&
344  
array::
344  
array::
345  
operator=(array const& other)
345  
operator=(array const& other)
346  
{
346  
{
347  
    array(other,
347  
    array(other,
348  
        storage()).swap(*this);
348  
        storage()).swap(*this);
349  
    return *this;
349  
    return *this;
350  
}
350  
}
351  

351  

352  
array&
352  
array&
353  
array::
353  
array::
354  
operator=(array&& other)
354  
operator=(array&& other)
355  
{
355  
{
356  
    array(std::move(other),
356  
    array(std::move(other),
357  
        storage()).swap(*this);
357  
        storage()).swap(*this);
358  
    return *this;
358  
    return *this;
359  
}
359  
}
360  

360  

361  
array&
361  
array&
362  
array::
362  
array::
363  
operator=(
363  
operator=(
364  
    std::initializer_list<value_ref> init)
364  
    std::initializer_list<value_ref> init)
365  
{
365  
{
366  
    array(init,
366  
    array(init,
367  
        storage()).swap(*this);
367  
        storage()).swap(*this);
368  
    return *this;
368  
    return *this;
369  
}
369  
}
370  

370  

371  
//----------------------------------------------------------
371  
//----------------------------------------------------------
372  
//
372  
//
373  
// Element access
373  
// Element access
374  
//
374  
//
375  
//----------------------------------------------------------
375  
//----------------------------------------------------------
376  

376  

377  
system::result<value&>
377  
system::result<value&>
378  
array::try_at(std::size_t pos) noexcept
378  
array::try_at(std::size_t pos) noexcept
379  
{
379  
{
380  
    if(pos >= t_->size)
380  
    if(pos >= t_->size)
381  
    {
381  
    {
382  
        system::error_code ec;
382  
        system::error_code ec;
383  
        BOOST_JSON_FAIL(ec, error::out_of_range);
383  
        BOOST_JSON_FAIL(ec, error::out_of_range);
384  
        return ec;
384  
        return ec;
385  
    }
385  
    }
386  
    return (*t_)[pos];
386  
    return (*t_)[pos];
387  
}
387  
}
388  

388  

389  
system::result<value const&>
389  
system::result<value const&>
390  
array::try_at(std::size_t pos) const noexcept
390  
array::try_at(std::size_t pos) const noexcept
391  
{
391  
{
392  
    if(pos >= t_->size)
392  
    if(pos >= t_->size)
393  
    {
393  
    {
394  
        system::error_code ec;
394  
        system::error_code ec;
395  
        BOOST_JSON_FAIL(ec, error::out_of_range);
395  
        BOOST_JSON_FAIL(ec, error::out_of_range);
396  
        return ec;
396  
        return ec;
397  
    }
397  
    }
398  
    return (*t_)[pos];
398  
    return (*t_)[pos];
399  
}
399  
}
400  

400  

401  
value const&
401  
value const&
402  
array::
402  
array::
403  
array::at(std::size_t pos, source_location const& loc) const&
403  
array::at(std::size_t pos, source_location const& loc) const&
404  
{
404  
{
405  
    return try_at(pos).value(loc);
405  
    return try_at(pos).value(loc);
406  
}
406  
}
407  

407  

408  
//----------------------------------------------------------
408  
//----------------------------------------------------------
409  
//
409  
//
410  
// Capacity
410  
// Capacity
411  
//
411  
//
412  
//----------------------------------------------------------
412  
//----------------------------------------------------------
413  

413  

414  
void
414  
void
415  
array::
415  
array::
416  
shrink_to_fit() noexcept
416  
shrink_to_fit() noexcept
417  
{
417  
{
418  
    if(capacity() <= size())
418  
    if(capacity() <= size())
419  
        return;
419  
        return;
420  
    if(size() == 0)
420  
    if(size() == 0)
421  
    {
421  
    {
422  
        table::deallocate(t_, sp_);
422  
        table::deallocate(t_, sp_);
423  
        t_ = &empty_;
423  
        t_ = &empty_;
424  
        return;
424  
        return;
425  
    }
425  
    }
426  

426  

427  
#ifndef BOOST_NO_EXCEPTIONS
427  
#ifndef BOOST_NO_EXCEPTIONS
428  
    try
428  
    try
429  
    {
429  
    {
430  
#endif
430  
#endif
431  
        auto t = table::allocate(
431  
        auto t = table::allocate(
432  
            size(), sp_);
432  
            size(), sp_);
433  
        relocate(
433  
        relocate(
434  
            &(*t)[0],
434  
            &(*t)[0],
435  
            data(),
435  
            data(),
436  
            size());
436  
            size());
437  
        t->size = static_cast<
437  
        t->size = static_cast<
438  
            std::uint32_t>(size());
438  
            std::uint32_t>(size());
439  
        t = detail::exchange(
439  
        t = detail::exchange(
440  
            t_, t);
440  
            t_, t);
441  
        table::deallocate(t, sp_);
441  
        table::deallocate(t, sp_);
442  
#ifndef BOOST_NO_EXCEPTIONS
442  
#ifndef BOOST_NO_EXCEPTIONS
443  
    }
443  
    }
444  
    catch(...)
444  
    catch(...)
445  
    {
445  
    {
446  
        // eat the exception
446  
        // eat the exception
447  
        return;
447  
        return;
448  
    }
448  
    }
449  
#endif
449  
#endif
450  
}
450  
}
451  

451  

452  
//----------------------------------------------------------
452  
//----------------------------------------------------------
453  
//
453  
//
454  
// Modifiers
454  
// Modifiers
455  
//
455  
//
456  
//----------------------------------------------------------
456  
//----------------------------------------------------------
457  

457  

458  
void
458  
void
459  
array::
459  
array::
460  
clear() noexcept
460  
clear() noexcept
461  
{
461  
{
462  
    if(size() == 0)
462  
    if(size() == 0)
463  
        return;
463  
        return;
464  
    destroy(
464  
    destroy(
465  
        begin(), end());
465  
        begin(), end());
466  
    t_->size = 0;
466  
    t_->size = 0;
467  
}
467  
}
468  

468  

469  
auto
469  
auto
470  
array::
470  
array::
471  
insert(
471  
insert(
472  
    const_iterator pos,
472  
    const_iterator pos,
473  
    value const& v) ->
473  
    value const& v) ->
474  
        iterator
474  
        iterator
475  
{
475  
{
476  
    return emplace(pos, v);
476  
    return emplace(pos, v);
477  
}
477  
}
478  

478  

479  
auto
479  
auto
480  
array::
480  
array::
481  
insert(
481  
insert(
482  
    const_iterator pos,
482  
    const_iterator pos,
483  
    value&& v) ->
483  
    value&& v) ->
484  
        iterator
484  
        iterator
485  
{
485  
{
486  
    return emplace(pos, std::move(v));
486  
    return emplace(pos, std::move(v));
487  
}
487  
}
488  

488  

489  
auto
489  
auto
490  
array::
490  
array::
491  
insert(
491  
insert(
492  
    const_iterator pos,
492  
    const_iterator pos,
493  
    std::size_t count,
493  
    std::size_t count,
494  
    value const& v) ->
494  
    value const& v) ->
495  
        iterator
495  
        iterator
496  
{
496  
{
497  
    revert_insert r(
497  
    revert_insert r(
498  
        pos, count, *this);
498  
        pos, count, *this);
499  
    while(count--)
499  
    while(count--)
500  
    {
500  
    {
501  
        ::new(r.p) value(v, sp_);
501  
        ::new(r.p) value(v, sp_);
502  
        ++r.p;
502  
        ++r.p;
503  
    }
503  
    }
504  
    return r.commit();
504  
    return r.commit();
505  
}
505  
}
506  

506  

507  
auto
507  
auto
508  
array::
508  
array::
509  
insert(
509  
insert(
510  
    const_iterator pos,
510  
    const_iterator pos,
511  
    std::initializer_list<
511  
    std::initializer_list<
512  
        value_ref> init) ->
512  
        value_ref> init) ->
513  
    iterator
513  
    iterator
514  
{
514  
{
515  
    revert_insert r(
515  
    revert_insert r(
516  
        pos, init.size(), *this);
516  
        pos, init.size(), *this);
517  
    value_ref::write_array(
517  
    value_ref::write_array(
518  
        r.p, init, sp_);
518  
        r.p, init, sp_);
519  
    return r.commit();
519  
    return r.commit();
520  
}
520  
}
521  

521  

522  
auto
522  
auto
523  
array::
523  
array::
524  
erase(
524  
erase(
525  
    const_iterator pos) noexcept ->
525  
    const_iterator pos) noexcept ->
526  
    iterator
526  
    iterator
527  
{
527  
{
528  
    BOOST_ASSERT(
528  
    BOOST_ASSERT(
529  
        pos >= begin() &&
529  
        pos >= begin() &&
530  
        pos <= end());
530  
        pos <= end());
531  
    return erase(pos, pos + 1);
531  
    return erase(pos, pos + 1);
532  
}
532  
}
533  

533  

534  
auto
534  
auto
535  
array::
535  
array::
536  
erase(
536  
erase(
537  
    const_iterator first,
537  
    const_iterator first,
538  
    const_iterator last) noexcept ->
538  
    const_iterator last) noexcept ->
539  
        iterator
539  
        iterator
540  
{
540  
{
541  
    BOOST_ASSERT(
541  
    BOOST_ASSERT(
542  
        first >= begin() &&
542  
        first >= begin() &&
543  
        last >= first &&
543  
        last >= first &&
544  
        last <= end());
544  
        last <= end());
545  
    std::size_t const n =
545  
    std::size_t const n =
546  
        last - first;
546  
        last - first;
547  
    auto const p = &(*t_)[0] +
547  
    auto const p = &(*t_)[0] +
548  
        (first - &(*t_)[0]);
548  
        (first - &(*t_)[0]);
549  
    destroy(p, p + n);
549  
    destroy(p, p + n);
550  
    relocate(p, p + n,
550  
    relocate(p, p + n,
551  
        t_->size - (last -
551  
        t_->size - (last -
552  
            &(*t_)[0]));
552  
            &(*t_)[0]));
553  
    t_->size = static_cast<
553  
    t_->size = static_cast<
554  
        std::uint32_t>(t_->size - n);
554  
        std::uint32_t>(t_->size - n);
555  
    return p;
555  
    return p;
556  
}
556  
}
557  

557  

558  
void
558  
void
559  
array::
559  
array::
560  
push_back(value const& v)
560  
push_back(value const& v)
561  
{
561  
{
562  
    emplace_back(v);
562  
    emplace_back(v);
563  
}
563  
}
564  

564  

565  
void
565  
void
566  
array::
566  
array::
567  
push_back(value&& v)
567  
push_back(value&& v)
568  
{
568  
{
569  
    emplace_back(std::move(v));
569  
    emplace_back(std::move(v));
570  
}
570  
}
571  

571  

572  
void
572  
void
573  
array::
573  
array::
574  
pop_back() noexcept
574  
pop_back() noexcept
575  
{
575  
{
576  
    auto const p = &back();
576  
    auto const p = &back();
577  
    destroy(p, p + 1);
577  
    destroy(p, p + 1);
578  
    --t_->size;
578  
    --t_->size;
579  
}
579  
}
580  

580  

581  
void
581  
void
582  
array::
582  
array::
583  
resize(std::size_t count)
583  
resize(std::size_t count)
584  
{
584  
{
585  
    if(count <= t_->size)
585  
    if(count <= t_->size)
586  
    {
586  
    {
587  
        // shrink
587  
        // shrink
588  
        destroy(
588  
        destroy(
589  
            &(*t_)[0] + count,
589  
            &(*t_)[0] + count,
590  
            &(*t_)[0] + t_->size);
590  
            &(*t_)[0] + t_->size);
591  
        t_->size = static_cast<
591  
        t_->size = static_cast<
592  
            std::uint32_t>(count);
592  
            std::uint32_t>(count);
593  
        return;
593  
        return;
594  
    }
594  
    }
595  

595  

596  
    reserve(count);
596  
    reserve(count);
597  
    auto p = &(*t_)[t_->size];
597  
    auto p = &(*t_)[t_->size];
598  
    auto const end = &(*t_)[count];
598  
    auto const end = &(*t_)[count];
599  
    while(p != end)
599  
    while(p != end)
600  
        ::new(p++) value(sp_);
600  
        ::new(p++) value(sp_);
601  
    t_->size = static_cast<
601  
    t_->size = static_cast<
602  
        std::uint32_t>(count);
602  
        std::uint32_t>(count);
603  
}
603  
}
604  

604  

605  
void
605  
void
606  
array::
606  
array::
607  
resize(
607  
resize(
608  
    std::size_t count,
608  
    std::size_t count,
609  
    value const& v)
609  
    value const& v)
610  
{
610  
{
611  
    if(count <= size())
611  
    if(count <= size())
612  
    {
612  
    {
613  
        // shrink
613  
        // shrink
614  
        destroy(
614  
        destroy(
615  
            data() + count,
615  
            data() + count,
616  
            data() + size());
616  
            data() + size());
617  
        t_->size = static_cast<
617  
        t_->size = static_cast<
618  
            std::uint32_t>(count);
618  
            std::uint32_t>(count);
619  
        return;
619  
        return;
620  
    }
620  
    }
621  
    count -= size();
621  
    count -= size();
622  
    revert_insert r(
622  
    revert_insert r(
623  
        end(), count, *this);
623  
        end(), count, *this);
624  
    while(count--)
624  
    while(count--)
625  
    {
625  
    {
626  
        ::new(r.p) value(v, sp_);
626  
        ::new(r.p) value(v, sp_);
627  
        ++r.p;
627  
        ++r.p;
628  
    }
628  
    }
629  
    r.commit();
629  
    r.commit();
630  
}
630  
}
631  

631  

632  
void
632  
void
633  
array::
633  
array::
634  
swap(array& other)
634  
swap(array& other)
635  
{
635  
{
636  
    if(*sp_ == *other.sp_)
636  
    if(*sp_ == *other.sp_)
637  
    {
637  
    {
638  
        t_ = detail::exchange(
638  
        t_ = detail::exchange(
639  
            other.t_, t_);
639  
            other.t_, t_);
640  
        return;
640  
        return;
641  
    }
641  
    }
642  
    array temp1(
642  
    array temp1(
643  
        std::move(*this),
643  
        std::move(*this),
644  
        other.storage());
644  
        other.storage());
645  
    array temp2(
645  
    array temp2(
646  
        std::move(other),
646  
        std::move(other),
647  
        this->storage());
647  
        this->storage());
648  
    this->~array();
648  
    this->~array();
649  
    ::new(this) array(
649  
    ::new(this) array(
650  
        pilfer(temp2));
650  
        pilfer(temp2));
651  
    other.~array();
651  
    other.~array();
652  
    ::new(&other) array(
652  
    ::new(&other) array(
653  
        pilfer(temp1));
653  
        pilfer(temp1));
654  
}
654  
}
655  

655  

656  
//----------------------------------------------------------
656  
//----------------------------------------------------------
657  
//
657  
//
658  
// Private
658  
// Private
659  
//
659  
//
660  
//----------------------------------------------------------
660  
//----------------------------------------------------------
661  

661  

662  
std::size_t
662  
std::size_t
663  
array::
663  
array::
664  
growth(
664  
growth(
665  
    std::size_t new_size) const
665  
    std::size_t new_size) const
666  
{
666  
{
667  
    if(new_size > max_size())
667  
    if(new_size > max_size())
668  
    {
668  
    {
669  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
669  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
670  
        detail::throw_system_error( error::array_too_large, &loc );
670  
        detail::throw_system_error( error::array_too_large, &loc );
671  
    }
671  
    }
672  
    std::size_t const old = capacity();
672  
    std::size_t const old = capacity();
673  
    if(old > max_size() - old / 2)
673  
    if(old > max_size() - old / 2)
674  
        return new_size;
674  
        return new_size;
675  
    std::size_t const g =
675  
    std::size_t const g =
676  
        old + old / 2; // 1.5x
676  
        old + old / 2; // 1.5x
677  
    if(g < new_size)
677  
    if(g < new_size)
678  
        return new_size;
678  
        return new_size;
679  
    return g;
679  
    return g;
680  
}
680  
}
681  

681  

682  
// precondition: new_capacity > capacity()
682  
// precondition: new_capacity > capacity()
683  
void
683  
void
684  
array::
684  
array::
685  
reserve_impl(
685  
reserve_impl(
686  
    std::size_t new_capacity)
686  
    std::size_t new_capacity)
687  
{
687  
{
688  
    BOOST_ASSERT(
688  
    BOOST_ASSERT(
689  
        new_capacity > t_->capacity);
689  
        new_capacity > t_->capacity);
690  
    auto t = table::allocate(
690  
    auto t = table::allocate(
691  
        growth(new_capacity), sp_);
691  
        growth(new_capacity), sp_);
692  
    relocate(
692  
    relocate(
693  
        &(*t)[0],
693  
        &(*t)[0],
694  
        &(*t_)[0],
694  
        &(*t_)[0],
695  
        t_->size);
695  
        t_->size);
696  
    t->size = t_->size;
696  
    t->size = t_->size;
697  
    t = detail::exchange(t_, t);
697  
    t = detail::exchange(t_, t);
698  
    table::deallocate(t, sp_);
698  
    table::deallocate(t, sp_);
699  
}
699  
}
700  

700  

701  
// precondition: pv is not aliased
701  
// precondition: pv is not aliased
702  
value&
702  
value&
703  
array::
703  
array::
704  
push_back(
704  
push_back(
705  
    pilfered<value> pv)
705  
    pilfered<value> pv)
706  
{
706  
{
707  
    auto const n = t_->size;
707  
    auto const n = t_->size;
708  
    if(n < t_->capacity)
708  
    if(n < t_->capacity)
709  
    {
709  
    {
710  
        // fast path
710  
        // fast path
711  
        auto& v = *::new(
711  
        auto& v = *::new(
712  
            &(*t_)[n]) value(pv);
712  
            &(*t_)[n]) value(pv);
713  
        ++t_->size;
713  
        ++t_->size;
714  
        return v;
714  
        return v;
715  
    }
715  
    }
716  
    auto const t =
716  
    auto const t =
717  
        detail::exchange(t_,
717  
        detail::exchange(t_,
718  
            table::allocate(
718  
            table::allocate(
719  
                growth(n + 1),
719  
                growth(n + 1),
720  
                    sp_));
720  
                    sp_));
721  
    auto& v = *::new(
721  
    auto& v = *::new(
722  
        &(*t_)[n]) value(pv);
722  
        &(*t_)[n]) value(pv);
723  
    relocate(
723  
    relocate(
724  
        &(*t_)[0],
724  
        &(*t_)[0],
725  
        &(*t)[0],
725  
        &(*t)[0],
726  
        n);
726  
        n);
727  
    t_->size = n + 1;
727  
    t_->size = n + 1;
728  
    table::deallocate(t, sp_);
728  
    table::deallocate(t, sp_);
729  
    return v;
729  
    return v;
730  
}
730  
}
731  

731  

732  
// precondition: pv is not aliased
732  
// precondition: pv is not aliased
733  
auto
733  
auto
734  
array::
734  
array::
735  
insert(
735  
insert(
736  
    const_iterator pos,
736  
    const_iterator pos,
737  
    pilfered<value> pv) ->
737  
    pilfered<value> pv) ->
738  
        iterator
738  
        iterator
739  
{
739  
{
740  
    BOOST_ASSERT(
740  
    BOOST_ASSERT(
741  
        pos >= begin() &&
741  
        pos >= begin() &&
742  
        pos <= end());
742  
        pos <= end());
743  
    std::size_t const n =
743  
    std::size_t const n =
744  
        t_->size;
744  
        t_->size;
745  
    std::size_t const i =
745  
    std::size_t const i =
746  
        pos - &(*t_)[0];
746  
        pos - &(*t_)[0];
747  
    if(n < t_->capacity)
747  
    if(n < t_->capacity)
748  
    {
748  
    {
749  
        // fast path
749  
        // fast path
750  
        auto const p =
750  
        auto const p =
751  
            &(*t_)[i];
751  
            &(*t_)[i];
752  
        relocate(
752  
        relocate(
753  
            p + 1,
753  
            p + 1,
754  
            p,
754  
            p,
755  
            n - i);
755  
            n - i);
756  
        ::new(p) value(pv);
756  
        ::new(p) value(pv);
757  
        ++t_->size;
757  
        ++t_->size;
758  
        return p;
758  
        return p;
759  
    }
759  
    }
760  
    auto t =
760  
    auto t =
761  
        table::allocate(
761  
        table::allocate(
762  
            growth(n + 1), sp_);
762  
            growth(n + 1), sp_);
763  
    auto const p = &(*t)[i];
763  
    auto const p = &(*t)[i];
764  
    ::new(p) value(pv);
764  
    ::new(p) value(pv);
765  
    relocate(
765  
    relocate(
766  
        &(*t)[0],
766  
        &(*t)[0],
767  
        &(*t_)[0],
767  
        &(*t_)[0],
768  
        i);
768  
        i);
769  
    relocate(
769  
    relocate(
770  
        p + 1,
770  
        p + 1,
771  
        &(*t_)[i],
771  
        &(*t_)[i],
772  
        n - i);
772  
        n - i);
773  
    t->size = static_cast<
773  
    t->size = static_cast<
774  
        std::uint32_t>(size() + 1);
774  
        std::uint32_t>(size() + 1);
775  
    t = detail::exchange(t_, t);
775  
    t = detail::exchange(t_, t);
776  
    table::deallocate(t, sp_);
776  
    table::deallocate(t, sp_);
777  
    return p;
777  
    return p;
778  
}
778  
}
779  

779  

780  
//----------------------------------------------------------
780  
//----------------------------------------------------------
781  

781  

782  
bool
782  
bool
783  
array::
783  
array::
784  
equal(
784  
equal(
785  
    array const& other) const noexcept
785  
    array const& other) const noexcept
786  
{
786  
{
787  
    if(size() != other.size())
787  
    if(size() != other.size())
788  
        return false;
788  
        return false;
789  
    for(std::size_t i = 0; i < size(); ++i)
789  
    for(std::size_t i = 0; i < size(); ++i)
790  
        if((*this)[i] != other[i])
790  
        if((*this)[i] != other[i])
791  
            return false;
791  
            return false;
792  
    return true;
792  
    return true;
793  
}
793  
}
794  

794  

795  
} // namespace json
795  
} // namespace json
796  
} // namespace boost
796  
} // namespace boost
797  

797  

798  
//----------------------------------------------------------
798  
//----------------------------------------------------------
799  
//
799  
//
800  
// std::hash specialization
800  
// std::hash specialization
801  
//
801  
//
802  
//----------------------------------------------------------
802  
//----------------------------------------------------------
803  

803  

804  
std::size_t
804  
std::size_t
805  
std::hash<::boost::json::array>::operator()(
805  
std::hash<::boost::json::array>::operator()(
806  
    ::boost::json::array const& ja) const noexcept
806  
    ::boost::json::array const& ja) const noexcept
807  
{
807  
{
808  
    return ::boost::hash< ::boost::json::array >()( ja );
808  
    return ::boost::hash< ::boost::json::array >()( ja );
809  
}
809  
}
810  

810  

811  
//----------------------------------------------------------
811  
//----------------------------------------------------------
812  

812  

813  
#endif
813  
#endif