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  

12  

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

19  

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

22  

23  
namespace detail {
23  
namespace detail {
24  

24  

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

32  

33  
BOOST_CORE_STATIC_ASSERT(
33  
BOOST_CORE_STATIC_ASSERT(
34  
    small_object_size_ < BOOST_JSON_MAX_STRUCTURED_SIZE);
34  
    small_object_size_ < 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_CORE_STATIC_ASSERT( sizeof(key_value_pair) == 32 );
52  
    char pad[4] = {}; // silence warnings
52  
    char pad[4] = {}; // silence warnings
53  
#endif
53  
#endif
54  

54  

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

56  

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

64  

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

73  

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

78  

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

82  

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

86  

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

90  

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

98  

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

118  

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

120  

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

124  

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

128  

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

136  

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

143  

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

150  

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

152  

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

158  

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

162  

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

174  

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

179  

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

191  

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

201  

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

207  

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

215  

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

223  

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

231  

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

239  

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

247  

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

255  

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

263  

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

271  

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

279  

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

287  

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

295  

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

303  

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

309  

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

316  

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

324  

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

337  

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

345  

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

355  

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

361  

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

369  

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

376  

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

378  

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

389  

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

406  

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

417  

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

423  

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

442  

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

466  

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

484  

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

510  

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

523  

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

529  

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

536  

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

541  

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

544  

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

546  

547  
namespace detail {
547  
namespace detail {
548  

548  

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

564  

565  
} // detail
565  
} // detail
566  

566  

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

569  

570  
#endif
570  
#endif