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_OBJECT_HPP
10  
#ifndef BOOST_JSON_IMPL_OBJECT_HPP
11  
#define BOOST_JSON_IMPL_OBJECT_HPP
11  
#define BOOST_JSON_IMPL_OBJECT_HPP
12 -
#include <boost/core/detail/static_assert.hpp>
 
13  

12  

14  
#include <boost/json/value.hpp>
13  
#include <boost/json/value.hpp>
15  
#include <iterator>
14  
#include <iterator>
16  
#include <cmath>
15  
#include <cmath>
17  
#include <type_traits>
16  
#include <type_traits>
18  
#include <utility>
17  
#include <utility>
19  

18  

20  
namespace boost {
19  
namespace boost {
21  
namespace json {
20  
namespace json {
22  

21  

23  
namespace detail {
22  
namespace detail {
24  

23  

25  
// Objects with size less than or equal
24  
// Objects with size less than or equal
26  
// to this number will use a linear search
25  
// to this number will use a linear search
27  
// instead of the more expensive hash function.
26  
// instead of the more expensive hash function.
28  
static
27  
static
29  
constexpr
28  
constexpr
30  
std::size_t
29  
std::size_t
31  
small_object_size_ = 18;
30  
small_object_size_ = 18;
32  

31  

33 -
BOOST_CORE_STATIC_ASSERT(
32 +
BOOST_STATIC_ASSERT(
34 -
    small_object_size_ < BOOST_JSON_MAX_STRUCTURED_SIZE);
33 +
    small_object_size_ <
 
34 +
    BOOST_JSON_MAX_STRUCTURED_SIZE);
35  

35  

36  
} // detail
36  
} // detail
37  

37  

38  
//----------------------------------------------------------
38  
//----------------------------------------------------------
39  

39  

40  
struct alignas(key_value_pair)
40  
struct alignas(key_value_pair)
41  
    object::table
41  
    object::table
42  
{
42  
{
43  
    std::uint32_t size = 0;
43  
    std::uint32_t size = 0;
44  
    std::uint32_t capacity = 0;
44  
    std::uint32_t capacity = 0;
45  
    std::uintptr_t salt = 0;
45  
    std::uintptr_t salt = 0;
46  

46  

47  
#if defined(_MSC_VER) && BOOST_JSON_ARCH == 32
47  
#if defined(_MSC_VER) && BOOST_JSON_ARCH == 32
48  
    // VFALCO If we make key_value_pair smaller,
48  
    // VFALCO If we make key_value_pair smaller,
49  
    //        then we might want to revisit this
49  
    //        then we might want to revisit this
50  
    //        padding.
50  
    //        padding.
51 -
    BOOST_CORE_STATIC_ASSERT( sizeof(key_value_pair) == 32 );
51 +
    BOOST_STATIC_ASSERT(
 
52 +
        sizeof(key_value_pair) == 32);
52  
    char pad[4] = {}; // silence warnings
53  
    char pad[4] = {}; // silence warnings
53  
#endif
54  
#endif
54  

55  

55  
    constexpr table();
56  
    constexpr table();
56  

57  

57  
    // returns true if we use a linear
58  
    // returns true if we use a linear
58  
    // search instead of the hash table.
59  
    // search instead of the hash table.
59  
    bool is_small() const noexcept
60  
    bool is_small() const noexcept
60  
    {
61  
    {
61  
        return capacity <=
62  
        return capacity <=
62  
            detail::small_object_size_;
63  
            detail::small_object_size_;
63  
    }
64  
    }
64  

65  

65  
    key_value_pair&
66  
    key_value_pair&
66  
    operator[](
67  
    operator[](
67  
        std::size_t pos) noexcept
68  
        std::size_t pos) noexcept
68  
    {
69  
    {
69  
        return reinterpret_cast<
70  
        return reinterpret_cast<
70  
            key_value_pair*>(
71  
            key_value_pair*>(
71  
                this + 1)[pos];
72  
                this + 1)[pos];
72  
    }
73  
    }
73  

74  

74  
    // VFALCO This is exported for tests
75  
    // VFALCO This is exported for tests
75  
    BOOST_JSON_DECL
76  
    BOOST_JSON_DECL
76  
    std::size_t
77  
    std::size_t
77  
    digest(string_view key) const noexcept;
78  
    digest(string_view key) const noexcept;
78  

79  

79  
    inline
80  
    inline
80  
    index_t&
81  
    index_t&
81  
    bucket(std::size_t hash) noexcept;
82  
    bucket(std::size_t hash) noexcept;
82  

83  

83  
    inline
84  
    inline
84  
    index_t&
85  
    index_t&
85  
    bucket(string_view key) noexcept;
86  
    bucket(string_view key) noexcept;
86  

87  

87  
    inline
88  
    inline
88  
    void
89  
    void
89  
    clear() noexcept;
90  
    clear() noexcept;
90  

91  

91  
    static
92  
    static
92  
    inline
93  
    inline
93  
    table*
94  
    table*
94  
    allocate(
95  
    allocate(
95  
        std::size_t capacity,
96  
        std::size_t capacity,
96  
        std::uintptr_t salt,
97  
        std::uintptr_t salt,
97  
        storage_ptr const& sp);
98  
        storage_ptr const& sp);
98  

99  

99  
    static
100  
    static
100  
    void
101  
    void
101  
    deallocate(
102  
    deallocate(
102  
        table* p,
103  
        table* p,
103  
        storage_ptr const& sp) noexcept
104  
        storage_ptr const& sp) noexcept
104  
    {
105  
    {
105  
        if(p->capacity == 0)
106  
        if(p->capacity == 0)
106  
            return;
107  
            return;
107  
        if(! p->is_small())
108  
        if(! p->is_small())
108  
            sp->deallocate(p,
109  
            sp->deallocate(p,
109  
                sizeof(table) + p->capacity * (
110  
                sizeof(table) + p->capacity * (
110  
                    sizeof(key_value_pair) +
111  
                    sizeof(key_value_pair) +
111  
                    sizeof(index_t)));
112  
                    sizeof(index_t)));
112  
        else
113  
        else
113  
            sp->deallocate(p,
114  
            sp->deallocate(p,
114  
                sizeof(table) + p->capacity *
115  
                sizeof(table) + p->capacity *
115  
                    sizeof(key_value_pair));
116  
                    sizeof(key_value_pair));
116  
    }
117  
    }
117  
};
118  
};
118  

119  

119  
//----------------------------------------------------------
120  
//----------------------------------------------------------
120  

121  

121  
class object::revert_construct
122  
class object::revert_construct
122  
{
123  
{
123  
    object* obj_;
124  
    object* obj_;
124  

125  

125  
    BOOST_JSON_DECL
126  
    BOOST_JSON_DECL
126  
    void
127  
    void
127  
    destroy() noexcept;
128  
    destroy() noexcept;
128  

129  

129  
public:
130  
public:
130  
    explicit
131  
    explicit
131  
    revert_construct(
132  
    revert_construct(
132  
        object& obj) noexcept
133  
        object& obj) noexcept
133  
        : obj_(&obj)
134  
        : obj_(&obj)
134  
    {
135  
    {
135  
    }
136  
    }
136  

137  

137  
    ~revert_construct()
138  
    ~revert_construct()
138  
    {
139  
    {
139  
        if(! obj_)
140  
        if(! obj_)
140  
            return;
141  
            return;
141  
        destroy();
142  
        destroy();
142  
    }
143  
    }
143  

144  

144  
    void
145  
    void
145  
    commit() noexcept
146  
    commit() noexcept
146  
    {
147  
    {
147  
        obj_ = nullptr;
148  
        obj_ = nullptr;
148  
    }
149  
    }
149  
};
150  
};
150  

151  

151  
//----------------------------------------------------------
152  
//----------------------------------------------------------
152  

153  

153  
class object::revert_insert
154  
class object::revert_insert
154  
{
155  
{
155  
    object* obj_;
156  
    object* obj_;
156  
    table* t_ = nullptr;
157  
    table* t_ = nullptr;
157  
    std::size_t size_;
158  
    std::size_t size_;
158  

159  

159  
    BOOST_JSON_DECL
160  
    BOOST_JSON_DECL
160  
    void
161  
    void
161  
    destroy() noexcept;
162  
    destroy() noexcept;
162  

163  

163  
public:
164  
public:
164  
    explicit
165  
    explicit
165  
    revert_insert(
166  
    revert_insert(
166  
        object& obj,
167  
        object& obj,
167  
        std::size_t capacity)
168  
        std::size_t capacity)
168  
        : obj_(&obj)
169  
        : obj_(&obj)
169  
        , size_(obj_->size())
170  
        , size_(obj_->size())
170  
    {
171  
    {
171  
        if( capacity > obj_->capacity() )
172  
        if( capacity > obj_->capacity() )
172  
            t_ = obj_->reserve_impl(capacity);
173  
            t_ = obj_->reserve_impl(capacity);
173  
    }
174  
    }
174  

175  

175  
    ~revert_insert()
176  
    ~revert_insert()
176  
    {
177  
    {
177  
        if(! obj_)
178  
        if(! obj_)
178  
            return;
179  
            return;
179  

180  

180  
        destroy();
181  
        destroy();
181  
        if( t_ )
182  
        if( t_ )
182  
        {
183  
        {
183  
            table::deallocate( obj_->t_, obj_->sp_ );
184  
            table::deallocate( obj_->t_, obj_->sp_ );
184  
            obj_->t_ = t_;
185  
            obj_->t_ = t_;
185  
        }
186  
        }
186  
        else
187  
        else
187  
        {
188  
        {
188  
            obj_->t_->size = static_cast<index_t>(size_);
189  
            obj_->t_->size = static_cast<index_t>(size_);
189  
        }
190  
        }
190  
    }
191  
    }
191  

192  

192  
    void
193  
    void
193  
    commit() noexcept
194  
    commit() noexcept
194  
    {
195  
    {
195  
        BOOST_ASSERT(obj_);
196  
        BOOST_ASSERT(obj_);
196  
        if( t_ )
197  
        if( t_ )
197  
            table::deallocate( t_, obj_->sp_ );
198  
            table::deallocate( t_, obj_->sp_ );
198  
        obj_ = nullptr;
199  
        obj_ = nullptr;
199  
    }
200  
    }
200  
};
201  
};
201  

202  

202  
//----------------------------------------------------------
203  
//----------------------------------------------------------
203  
//
204  
//
204  
// Iterators
205  
// Iterators
205  
//
206  
//
206  
//----------------------------------------------------------
207  
//----------------------------------------------------------
207  

208  

208  
auto
209  
auto
209  
object::
210  
object::
210  
begin() noexcept ->
211  
begin() noexcept ->
211  
    iterator
212  
    iterator
212  
{
213  
{
213  
    return &(*t_)[0];
214  
    return &(*t_)[0];
214  
}
215  
}
215  

216  

216  
auto
217  
auto
217  
object::
218  
object::
218  
begin() const noexcept ->
219  
begin() const noexcept ->
219  
    const_iterator
220  
    const_iterator
220  
{
221  
{
221  
    return &(*t_)[0];
222  
    return &(*t_)[0];
222  
}
223  
}
223  

224  

224  
auto
225  
auto
225  
object::
226  
object::
226  
cbegin() const noexcept ->
227  
cbegin() const noexcept ->
227  
    const_iterator
228  
    const_iterator
228  
{
229  
{
229  
    return &(*t_)[0];
230  
    return &(*t_)[0];
230  
}
231  
}
231  

232  

232  
auto
233  
auto
233  
object::
234  
object::
234  
end() noexcept ->
235  
end() noexcept ->
235  
    iterator
236  
    iterator
236  
{
237  
{
237  
    return &(*t_)[t_->size];
238  
    return &(*t_)[t_->size];
238  
}
239  
}
239  

240  

240  
auto
241  
auto
241  
object::
242  
object::
242  
end() const noexcept ->
243  
end() const noexcept ->
243  
    const_iterator
244  
    const_iterator
244  
{
245  
{
245  
    return &(*t_)[t_->size];
246  
    return &(*t_)[t_->size];
246  
}
247  
}
247  

248  

248  
auto
249  
auto
249  
object::
250  
object::
250  
cend() const noexcept ->
251  
cend() const noexcept ->
251  
    const_iterator
252  
    const_iterator
252  
{
253  
{
253  
    return &(*t_)[t_->size];
254  
    return &(*t_)[t_->size];
254  
}
255  
}
255  

256  

256  
auto
257  
auto
257  
object::
258  
object::
258  
rbegin() noexcept ->
259  
rbegin() noexcept ->
259  
    reverse_iterator
260  
    reverse_iterator
260  
{
261  
{
261  
    return reverse_iterator(end());
262  
    return reverse_iterator(end());
262  
}
263  
}
263  

264  

264  
auto
265  
auto
265  
object::
266  
object::
266  
rbegin() const noexcept ->
267  
rbegin() const noexcept ->
267  
    const_reverse_iterator
268  
    const_reverse_iterator
268  
{
269  
{
269  
    return const_reverse_iterator(end());
270  
    return const_reverse_iterator(end());
270  
}
271  
}
271  

272  

272  
auto
273  
auto
273  
object::
274  
object::
274  
crbegin() const noexcept ->
275  
crbegin() const noexcept ->
275  
    const_reverse_iterator
276  
    const_reverse_iterator
276  
{
277  
{
277  
    return const_reverse_iterator(end());
278  
    return const_reverse_iterator(end());
278  
}
279  
}
279  

280  

280  
auto
281  
auto
281  
object::
282  
object::
282  
rend() noexcept ->
283  
rend() noexcept ->
283  
    reverse_iterator
284  
    reverse_iterator
284  
{
285  
{
285  
    return reverse_iterator(begin());
286  
    return reverse_iterator(begin());
286  
}
287  
}
287  

288  

288  
auto
289  
auto
289  
object::
290  
object::
290  
rend() const noexcept ->
291  
rend() const noexcept ->
291  
    const_reverse_iterator
292  
    const_reverse_iterator
292  
{
293  
{
293  
    return const_reverse_iterator(begin());
294  
    return const_reverse_iterator(begin());
294  
}
295  
}
295  

296  

296  
auto
297  
auto
297  
object::
298  
object::
298  
crend() const noexcept ->
299  
crend() const noexcept ->
299  
    const_reverse_iterator
300  
    const_reverse_iterator
300  
{
301  
{
301  
    return const_reverse_iterator(begin());
302  
    return const_reverse_iterator(begin());
302  
}
303  
}
303  

304  

304  
//----------------------------------------------------------
305  
//----------------------------------------------------------
305  
//
306  
//
306  
// Capacity
307  
// Capacity
307  
//
308  
//
308  
//----------------------------------------------------------
309  
//----------------------------------------------------------
309  

310  

310  
bool
311  
bool
311  
object::
312  
object::
312  
empty() const noexcept
313  
empty() const noexcept
313  
{
314  
{
314  
    return t_->size == 0;
315  
    return t_->size == 0;
315  
}
316  
}
316  

317  

317  
auto
318  
auto
318  
object::
319  
object::
319  
size() const noexcept ->
320  
size() const noexcept ->
320  
    std::size_t
321  
    std::size_t
321  
{
322  
{
322  
    return t_->size;
323  
    return t_->size;
323  
}
324  
}
324  

325  

325  
constexpr
326  
constexpr
326  
std::size_t
327  
std::size_t
327  
object::
328  
object::
328  
max_size() noexcept
329  
max_size() noexcept
329  
{
330  
{
330  
    // max_size depends on the address model
331  
    // max_size depends on the address model
331  
    using min = std::integral_constant<std::size_t,
332  
    using min = std::integral_constant<std::size_t,
332  
        (std::size_t(-1) - sizeof(table)) /
333  
        (std::size_t(-1) - sizeof(table)) /
333  
            (sizeof(key_value_pair) + sizeof(index_t))>;
334  
            (sizeof(key_value_pair) + sizeof(index_t))>;
334  
    return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
335  
    return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
335  
        min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
336  
        min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
336  
}
337  
}
337  

338  

338  
auto
339  
auto
339  
object::
340  
object::
340  
capacity() const noexcept ->
341  
capacity() const noexcept ->
341  
    std::size_t
342  
    std::size_t
342  
{
343  
{
343  
    return t_->capacity;
344  
    return t_->capacity;
344  
}
345  
}
345  

346  

346  
void
347  
void
347  
object::
348  
object::
348  
reserve(std::size_t new_capacity)
349  
reserve(std::size_t new_capacity)
349  
{
350  
{
350  
    if( new_capacity <= capacity() )
351  
    if( new_capacity <= capacity() )
351  
        return;
352  
        return;
352  
    table* const old_table = reserve_impl(new_capacity);
353  
    table* const old_table = reserve_impl(new_capacity);
353  
    table::deallocate( old_table, sp_ );
354  
    table::deallocate( old_table, sp_ );
354  
}
355  
}
355  

356  

356  
//----------------------------------------------------------
357  
//----------------------------------------------------------
357  
//
358  
//
358  
// Lookup
359  
// Lookup
359  
//
360  
//
360  
//----------------------------------------------------------
361  
//----------------------------------------------------------
361  

362  

362  
value&
363  
value&
363  
object::
364  
object::
364  
at(string_view key, source_location const& loc) &
365  
at(string_view key, source_location const& loc) &
365  
{
366  
{
366  
    auto const& self = *this;
367  
    auto const& self = *this;
367  
    return const_cast< value& >( self.at(key, loc) );
368  
    return const_cast< value& >( self.at(key, loc) );
368  
}
369  
}
369  

370  

370  
value&&
371  
value&&
371  
object::
372  
object::
372  
at(string_view key, source_location const& loc) &&
373  
at(string_view key, source_location const& loc) &&
373  
{
374  
{
374  
    return std::move( at(key, loc) );
375  
    return std::move( at(key, loc) );
375  
}
376  
}
376  

377  

377  
//----------------------------------------------------------
378  
//----------------------------------------------------------
378  

379  

379  
template<class P, class>
380  
template<class P, class>
380  
auto
381  
auto
381  
object::
382  
object::
382  
insert(P&& p) ->
383  
insert(P&& p) ->
383  
    std::pair<iterator, bool>
384  
    std::pair<iterator, bool>
384  
{
385  
{
385  
    key_value_pair v(
386  
    key_value_pair v(
386  
        std::forward<P>(p), sp_);
387  
        std::forward<P>(p), sp_);
387  
    return emplace_impl( v.key(), pilfer(v) );
388  
    return emplace_impl( v.key(), pilfer(v) );
388  
}
389  
}
389  

390  

390  
template<class M>
391  
template<class M>
391  
auto
392  
auto
392  
object::
393  
object::
393  
insert_or_assign(
394  
insert_or_assign(
394  
    string_view key, M&& m) ->
395  
    string_view key, M&& m) ->
395  
        std::pair<iterator, bool>
396  
        std::pair<iterator, bool>
396  
{
397  
{
397  
    std::pair<iterator, bool> result = emplace_impl(
398  
    std::pair<iterator, bool> result = emplace_impl(
398  
        key, key, static_cast<M&&>(m) );
399  
        key, key, static_cast<M&&>(m) );
399  
    if( !result.second )
400  
    if( !result.second )
400  
    {
401  
    {
401  
        value(static_cast<M>(m), sp_).swap(
402  
        value(static_cast<M>(m), sp_).swap(
402  
            result.first->value());
403  
            result.first->value());
403  
    }
404  
    }
404  
    return result;
405  
    return result;
405  
}
406  
}
406  

407  

407  
template<class Arg>
408  
template<class Arg>
408  
auto
409  
auto
409  
object::
410  
object::
410  
emplace(
411  
emplace(
411  
    string_view key,
412  
    string_view key,
412  
    Arg&& arg) ->
413  
    Arg&& arg) ->
413  
        std::pair<iterator, bool>
414  
        std::pair<iterator, bool>
414  
{
415  
{
415  
    return emplace_impl( key, key, static_cast<Arg&&>(arg) );
416  
    return emplace_impl( key, key, static_cast<Arg&&>(arg) );
416  
}
417  
}
417  

418  

418  
//----------------------------------------------------------
419  
//----------------------------------------------------------
419  
//
420  
//
420  
// (private)
421  
// (private)
421  
//
422  
//
422  
//----------------------------------------------------------
423  
//----------------------------------------------------------
423  

424  

424  
template<class InputIt>
425  
template<class InputIt>
425  
void
426  
void
426  
object::
427  
object::
427  
construct(
428  
construct(
428  
    InputIt first,
429  
    InputIt first,
429  
    InputIt last,
430  
    InputIt last,
430  
    std::size_t min_capacity,
431  
    std::size_t min_capacity,
431  
    std::input_iterator_tag)
432  
    std::input_iterator_tag)
432  
{
433  
{
433  
    reserve(min_capacity);
434  
    reserve(min_capacity);
434  
    revert_construct r(*this);
435  
    revert_construct r(*this);
435  
    while(first != last)
436  
    while(first != last)
436  
    {
437  
    {
437  
        insert(*first);
438  
        insert(*first);
438  
        ++first;
439  
        ++first;
439  
    }
440  
    }
440  
    r.commit();
441  
    r.commit();
441  
}
442  
}
442  

443  

443  
template<class InputIt>
444  
template<class InputIt>
444  
void
445  
void
445  
object::
446  
object::
446  
construct(
447  
construct(
447  
    InputIt first,
448  
    InputIt first,
448  
    InputIt last,
449  
    InputIt last,
449  
    std::size_t min_capacity,
450  
    std::size_t min_capacity,
450  
    std::forward_iterator_tag)
451  
    std::forward_iterator_tag)
451  
{
452  
{
452  
    auto n = static_cast<
453  
    auto n = static_cast<
453  
        std::size_t>(std::distance(
454  
        std::size_t>(std::distance(
454  
            first, last));
455  
            first, last));
455  
    if( n < min_capacity)
456  
    if( n < min_capacity)
456  
        n = min_capacity;
457  
        n = min_capacity;
457  
    reserve(n);
458  
    reserve(n);
458  
    revert_construct r(*this);
459  
    revert_construct r(*this);
459  
    while(first != last)
460  
    while(first != last)
460  
    {
461  
    {
461  
        insert(*first);
462  
        insert(*first);
462  
        ++first;
463  
        ++first;
463  
    }
464  
    }
464  
    r.commit();
465  
    r.commit();
465  
}
466  
}
466  

467  

467  
template<class InputIt>
468  
template<class InputIt>
468  
void
469  
void
469  
object::
470  
object::
470  
insert(
471  
insert(
471  
    InputIt first,
472  
    InputIt first,
472  
    InputIt last,
473  
    InputIt last,
473  
    std::input_iterator_tag)
474  
    std::input_iterator_tag)
474  
{
475  
{
475  
    // Since input iterators cannot be rewound,
476  
    // Since input iterators cannot be rewound,
476  
    // we keep inserted elements on an exception.
477  
    // we keep inserted elements on an exception.
477  
    //
478  
    //
478  
    while(first != last)
479  
    while(first != last)
479  
    {
480  
    {
480  
        insert(*first);
481  
        insert(*first);
481  
        ++first;
482  
        ++first;
482  
    }
483  
    }
483  
}
484  
}
484  

485  

485  
template<class InputIt>
486  
template<class InputIt>
486  
void
487  
void
487  
object::
488  
object::
488  
insert(
489  
insert(
489  
    InputIt first,
490  
    InputIt first,
490  
    InputIt last,
491  
    InputIt last,
491  
    std::forward_iterator_tag)
492  
    std::forward_iterator_tag)
492  
{
493  
{
493  
    auto const n =
494  
    auto const n =
494  
        static_cast<std::size_t>(
495  
        static_cast<std::size_t>(
495  
            std::distance(first, last));
496  
            std::distance(first, last));
496  
    auto const n0 = size();
497  
    auto const n0 = size();
497  
    if(n > max_size() - n0)
498  
    if(n > max_size() - n0)
498  
    {
499  
    {
499  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
500  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
500  
        detail::throw_system_error( error::object_too_large, &loc );
501  
        detail::throw_system_error( error::object_too_large, &loc );
501  
    }
502  
    }
502  
    revert_insert r( *this, n0 + n );
503  
    revert_insert r( *this, n0 + n );
503  
    while(first != last)
504  
    while(first != last)
504  
    {
505  
    {
505  
        insert(*first);
506  
        insert(*first);
506  
        ++first;
507  
        ++first;
507  
    }
508  
    }
508  
    r.commit();
509  
    r.commit();
509  
}
510  
}
510  

511  

511  
template< class... Args >
512  
template< class... Args >
512  
std::pair<object::iterator, bool>
513  
std::pair<object::iterator, bool>
513  
object::
514  
object::
514  
emplace_impl( string_view key, Args&& ... args )
515  
emplace_impl( string_view key, Args&& ... args )
515  
{
516  
{
516  
    std::pair<iterator, std::size_t> search_result(nullptr, 0);
517  
    std::pair<iterator, std::size_t> search_result(nullptr, 0);
517  
    if( !empty() )
518  
    if( !empty() )
518  
    {
519  
    {
519  
        search_result = detail::find_in_object(*this, key);
520  
        search_result = detail::find_in_object(*this, key);
520  
        if( search_result.first )
521  
        if( search_result.first )
521  
            return { search_result.first, false };
522  
            return { search_result.first, false };
522  
    }
523  
    }
523  

524  

524  
    // we create the new value before reserving, in case it is a reference to
525  
    // we create the new value before reserving, in case it is a reference to
525  
    // a subobject of the current object
526  
    // a subobject of the current object
526  
    key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
527  
    key_value_pair kv( static_cast<Args&&>(args)..., sp_ );
527  
    // the key might get deallocated too
528  
    // the key might get deallocated too
528  
    key = kv.key();
529  
    key = kv.key();
529  

530  

530  
    std::size_t const old_capacity = capacity();
531  
    std::size_t const old_capacity = capacity();
531  
    reserve(size() + 1);
532  
    reserve(size() + 1);
532  
    if( (empty() && capacity() > detail::small_object_size_)
533  
    if( (empty() && capacity() > detail::small_object_size_)
533  
            || (capacity() != old_capacity) )
534  
            || (capacity() != old_capacity) )
534  
        search_result.second = detail::digest(
535  
        search_result.second = detail::digest(
535  
            key.begin(), key.end(), t_->salt);
536  
            key.begin(), key.end(), t_->salt);
536  

537  

537  
    BOOST_ASSERT(
538  
    BOOST_ASSERT(
538  
        t_->is_small() ||
539  
        t_->is_small() ||
539  
        (search_result.second ==
540  
        (search_result.second ==
540  
            detail::digest(key.begin(), key.end(), t_->salt)) );
541  
            detail::digest(key.begin(), key.end(), t_->salt)) );
541  

542  

542  
    return { insert_impl(pilfer(kv), search_result.second), true };
543  
    return { insert_impl(pilfer(kv), search_result.second), true };
543  
}
544  
}
544  

545  

545  
//----------------------------------------------------------
546  
//----------------------------------------------------------
546  

547  

547  
namespace detail {
548  
namespace detail {
548  

549  

549  
unchecked_object::
550  
unchecked_object::
550  
~unchecked_object()
551  
~unchecked_object()
551  
{
552  
{
552  
    if(! data_)
553  
    if(! data_)
553  
        return;
554  
        return;
554  
    if(sp_.is_not_shared_and_deallocate_is_trivial())
555  
    if(sp_.is_not_shared_and_deallocate_is_trivial())
555  
        return;
556  
        return;
556  
    value* p = data_;
557  
    value* p = data_;
557  
    while(size_--)
558  
    while(size_--)
558  
    {
559  
    {
559  
        p[0].~value();
560  
        p[0].~value();
560  
        p[1].~value();
561  
        p[1].~value();
561  
        p += 2;
562  
        p += 2;
562  
    }
563  
    }
563  
}
564  
}
564  

565  

565  
} // detail
566  
} // detail
566  

567  

567  
} // namespace json
568  
} // namespace json
568  
} // namespace boost
569  
} // namespace boost
569  

570  

570  
#endif
571  
#endif