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

10  

11  
#ifndef BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
11  
#ifndef BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
12  
#define BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
12  
#define BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
13  

13  

14  
#include <boost/json/detail/string_impl.hpp>
14  
#include <boost/json/detail/string_impl.hpp>
15  
#include <boost/json/detail/except.hpp>
15  
#include <boost/json/detail/except.hpp>
16  
#include <cstring>
16  
#include <cstring>
17  
#include <functional>
17  
#include <functional>
18  

18  

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

22  

23  
inline
23  
inline
24  
bool
24  
bool
25  
ptr_in_range(
25  
ptr_in_range(
26  
    const char* first,
26  
    const char* first,
27  
    const char* last,
27  
    const char* last,
28  
    const char* ptr) noexcept
28  
    const char* ptr) noexcept
29  
{
29  
{
30  
    return std::less<const char*>()(ptr, last) &&
30  
    return std::less<const char*>()(ptr, last) &&
31  
        std::greater_equal<const char*>()(ptr, first);
31  
        std::greater_equal<const char*>()(ptr, first);
32  
}
32  
}
33  

33  

34  
string_impl::
34  
string_impl::
35  
string_impl() noexcept
35  
string_impl() noexcept
36  
{
36  
{
37  
    s_.k = short_string_;
37  
    s_.k = short_string_;
38  
    s_.buf[sbo_chars_] =
38  
    s_.buf[sbo_chars_] =
39  
        static_cast<char>(
39  
        static_cast<char>(
40  
            sbo_chars_);
40  
            sbo_chars_);
41  
    s_.buf[0] = 0;
41  
    s_.buf[0] = 0;
42  
}
42  
}
43  

43  

44  
string_impl::
44  
string_impl::
45  
string_impl(
45  
string_impl(
46  
    std::size_t size,
46  
    std::size_t size,
47  
    storage_ptr const& sp)
47  
    storage_ptr const& sp)
48  
{
48  
{
49  
    if(size <= sbo_chars_)
49  
    if(size <= sbo_chars_)
50  
    {
50  
    {
51  
        s_.k = short_string_;
51  
        s_.k = short_string_;
52  
        s_.buf[sbo_chars_] =
52  
        s_.buf[sbo_chars_] =
53  
            static_cast<char>(
53  
            static_cast<char>(
54  
                sbo_chars_ - size);
54  
                sbo_chars_ - size);
55  
        s_.buf[size] = 0;
55  
        s_.buf[size] = 0;
56  
    }
56  
    }
57  
    else
57  
    else
58  
    {
58  
    {
59  
        s_.k = kind::string;
59  
        s_.k = kind::string;
60  
        auto const n = growth(
60  
        auto const n = growth(
61  
            size, sbo_chars_ + 1);
61  
            size, sbo_chars_ + 1);
62  
        p_.t = ::new(sp->allocate(
62  
        p_.t = ::new(sp->allocate(
63  
            sizeof(table) +
63  
            sizeof(table) +
64  
                n + 1,
64  
                n + 1,
65  
            alignof(table))) table{
65  
            alignof(table))) table{
66  
                static_cast<
66  
                static_cast<
67  
                    std::uint32_t>(size),
67  
                    std::uint32_t>(size),
68  
                static_cast<
68  
                static_cast<
69  
                    std::uint32_t>(n)};
69  
                    std::uint32_t>(n)};
70  
        data()[n] = 0;
70  
        data()[n] = 0;
71  
    }
71  
    }
72  
}
72  
}
73  

73  

74  
// construct a key, unchecked
74  
// construct a key, unchecked
75  
string_impl::
75  
string_impl::
76  
string_impl(
76  
string_impl(
77  
    key_t,
77  
    key_t,
78  
    string_view s,
78  
    string_view s,
79  
    storage_ptr const& sp)
79  
    storage_ptr const& sp)
80  
{
80  
{
81  
    BOOST_ASSERT(
81  
    BOOST_ASSERT(
82  
        s.size() <= max_size());
82  
        s.size() <= max_size());
83  
    k_.k = key_string_;
83  
    k_.k = key_string_;
84  
    k_.n = static_cast<
84  
    k_.n = static_cast<
85  
        std::uint32_t>(s.size());
85  
        std::uint32_t>(s.size());
86  
    k_.s = reinterpret_cast<char*>(
86  
    k_.s = reinterpret_cast<char*>(
87  
        sp->allocate(s.size() + 1,
87  
        sp->allocate(s.size() + 1,
88  
            alignof(char)));
88  
            alignof(char)));
89  
    k_.s[s.size()] = 0; // null term
89  
    k_.s[s.size()] = 0; // null term
90  
    std::memcpy(&k_.s[0],
90  
    std::memcpy(&k_.s[0],
91  
        s.data(), s.size());
91  
        s.data(), s.size());
92  
}
92  
}
93  

93  

94  
// construct a key, unchecked
94  
// construct a key, unchecked
95  
string_impl::
95  
string_impl::
96  
string_impl(
96  
string_impl(
97  
    key_t,
97  
    key_t,
98  
    string_view s1,
98  
    string_view s1,
99  
    string_view s2,
99  
    string_view s2,
100  
    storage_ptr const& sp)
100  
    storage_ptr const& sp)
101  
{
101  
{
102  
    auto len = s1.size() + s2.size();
102  
    auto len = s1.size() + s2.size();
103  
    BOOST_ASSERT(len <= max_size());
103  
    BOOST_ASSERT(len <= max_size());
104  
    k_.k = key_string_;
104  
    k_.k = key_string_;
105  
    k_.n = static_cast<
105  
    k_.n = static_cast<
106  
        std::uint32_t>(len);
106  
        std::uint32_t>(len);
107  
    k_.s = reinterpret_cast<char*>(
107  
    k_.s = reinterpret_cast<char*>(
108  
        sp->allocate(len + 1,
108  
        sp->allocate(len + 1,
109  
            alignof(char)));
109  
            alignof(char)));
110  
    k_.s[len] = 0; // null term
110  
    k_.s[len] = 0; // null term
111  
    std::memcpy(&k_.s[0],
111  
    std::memcpy(&k_.s[0],
112  
        s1.data(), s1.size());
112  
        s1.data(), s1.size());
113  
    std::memcpy(&k_.s[s1.size()],
113  
    std::memcpy(&k_.s[s1.size()],
114  
        s2.data(), s2.size());
114  
        s2.data(), s2.size());
115  
}
115  
}
116  

116  

117  
std::uint32_t
117  
std::uint32_t
118  
string_impl::
118  
string_impl::
119  
growth(
119  
growth(
120  
    std::size_t new_size,
120  
    std::size_t new_size,
121  
    std::size_t capacity)
121  
    std::size_t capacity)
122  
{
122  
{
123  
    if(new_size > max_size())
123  
    if(new_size > max_size())
124  
    {
124  
    {
125  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
125  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
126  
        detail::throw_system_error( error::string_too_large, &loc );
126  
        detail::throw_system_error( error::string_too_large, &loc );
127  
    }
127  
    }
128  
    // growth factor 2
128  
    // growth factor 2
129  
    if( capacity >
129  
    if( capacity >
130  
        max_size() - capacity)
130  
        max_size() - capacity)
131  
        return static_cast<
131  
        return static_cast<
132  
            std::uint32_t>(max_size()); // overflow
132  
            std::uint32_t>(max_size()); // overflow
133  
    return static_cast<std::uint32_t>(
133  
    return static_cast<std::uint32_t>(
134  
        (std::max)(capacity * 2, new_size));
134  
        (std::max)(capacity * 2, new_size));
135  
}
135  
}
136  

136  

137  
char*
137  
char*
138  
string_impl::
138  
string_impl::
139  
assign(
139  
assign(
140  
    std::size_t new_size,
140  
    std::size_t new_size,
141  
    storage_ptr const& sp)
141  
    storage_ptr const& sp)
142  
{
142  
{
143  
    if(new_size > capacity())
143  
    if(new_size > capacity())
144  
    {
144  
    {
145  
        string_impl tmp(growth(
145  
        string_impl tmp(growth(
146  
            new_size,
146  
            new_size,
147  
            capacity()), sp);
147  
            capacity()), sp);
148  
        destroy(sp);
148  
        destroy(sp);
149  
        *this = tmp;
149  
        *this = tmp;
150  
    }
150  
    }
151  
    term(new_size);
151  
    term(new_size);
152  
    return data();
152  
    return data();
153  
}
153  
}
154  

154  

155  
char*
155  
char*
156  
string_impl::
156  
string_impl::
157  
append(
157  
append(
158  
    std::size_t n,
158  
    std::size_t n,
159  
    storage_ptr const& sp)
159  
    storage_ptr const& sp)
160  
{
160  
{
161  
    if(n > max_size() - size())
161  
    if(n > max_size() - size())
162  
    {
162  
    {
163  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
163  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
164  
        detail::throw_system_error( error::string_too_large, &loc );
164  
        detail::throw_system_error( error::string_too_large, &loc );
165  
    }
165  
    }
166  
    if(n <= capacity() - size())
166  
    if(n <= capacity() - size())
167  
    {
167  
    {
168  
        term(size() + n);
168  
        term(size() + n);
169  
        return end() - n;
169  
        return end() - n;
170  
    }
170  
    }
171  
    string_impl tmp(growth(
171  
    string_impl tmp(growth(
172  
        size() + n, capacity()), sp);
172  
        size() + n, capacity()), sp);
173  
    std::memcpy(
173  
    std::memcpy(
174  
        tmp.data(), data(), size());
174  
        tmp.data(), data(), size());
175  
    tmp.term(size() + n);
175  
    tmp.term(size() + n);
176  
    destroy(sp);
176  
    destroy(sp);
177  
    *this = tmp;
177  
    *this = tmp;
178  
    return end() - n;
178  
    return end() - n;
179  
}
179  
}
180  

180  

181  
void
181  
void
182  
string_impl::
182  
string_impl::
183  
insert(
183  
insert(
184  
    std::size_t pos,
184  
    std::size_t pos,
185  
    const char* s,
185  
    const char* s,
186  
    std::size_t n,
186  
    std::size_t n,
187  
    storage_ptr const& sp)
187  
    storage_ptr const& sp)
188  
{
188  
{
189  
    const auto curr_size = size();
189  
    const auto curr_size = size();
190  
    if(pos > curr_size)
190  
    if(pos > curr_size)
191  
    {
191  
    {
192  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
192  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
193  
        detail::throw_system_error( error::out_of_range, &loc );
193  
        detail::throw_system_error( error::out_of_range, &loc );
194  
    }
194  
    }
195  
    const auto curr_data = data();
195  
    const auto curr_data = data();
196  
    if(n <= capacity() - curr_size)
196  
    if(n <= capacity() - curr_size)
197  
    {
197  
    {
198  
        const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
198  
        const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
199  
        if (!inside || (inside && ((s - curr_data) + n <= pos)))
199  
        if (!inside || (inside && ((s - curr_data) + n <= pos)))
200  
        {
200  
        {
201  
            std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
201  
            std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
202  
            std::memcpy(&curr_data[pos], s, n);
202  
            std::memcpy(&curr_data[pos], s, n);
203  
        }
203  
        }
204  
        else
204  
        else
205  
        {
205  
        {
206  
            const std::size_t offset = s - curr_data;
206  
            const std::size_t offset = s - curr_data;
207  
            std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
207  
            std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
208  
            if (offset < pos)
208  
            if (offset < pos)
209  
            {
209  
            {
210  
                const std::size_t diff = pos - offset;
210  
                const std::size_t diff = pos - offset;
211  
                std::memcpy(&curr_data[pos], &curr_data[offset], diff);
211  
                std::memcpy(&curr_data[pos], &curr_data[offset], diff);
212  
                std::memcpy(&curr_data[pos + diff], &curr_data[pos + n], n - diff);
212  
                std::memcpy(&curr_data[pos + diff], &curr_data[pos + n], n - diff);
213  
            }
213  
            }
214  
            else
214  
            else
215  
            {
215  
            {
216  
                std::memcpy(&curr_data[pos], &curr_data[offset + n], n);
216  
                std::memcpy(&curr_data[pos], &curr_data[offset + n], n);
217  
            }
217  
            }
218  
        }
218  
        }
219  
        size(curr_size + n);
219  
        size(curr_size + n);
220  
    }
220  
    }
221  
    else
221  
    else
222  
    {
222  
    {
223  
        if(n > max_size() - curr_size)
223  
        if(n > max_size() - curr_size)
224  
        {
224  
        {
225  
            BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
225  
            BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
226  
            detail::throw_system_error( error::string_too_large, &loc );
226  
            detail::throw_system_error( error::string_too_large, &loc );
227  
        }
227  
        }
228  
        string_impl tmp(growth(
228  
        string_impl tmp(growth(
229  
            curr_size + n, capacity()), sp);
229  
            curr_size + n, capacity()), sp);
230  
        tmp.size(curr_size + n);
230  
        tmp.size(curr_size + n);
231  
        std::memcpy(
231  
        std::memcpy(
232  
            tmp.data(),
232  
            tmp.data(),
233  
            curr_data,
233  
            curr_data,
234  
            pos);
234  
            pos);
235  
        std::memcpy(
235  
        std::memcpy(
236  
            tmp.data() + pos + n,
236  
            tmp.data() + pos + n,
237  
            curr_data + pos,
237  
            curr_data + pos,
238  
            curr_size + 1 - pos);
238  
            curr_size + 1 - pos);
239  
        std::memcpy(
239  
        std::memcpy(
240  
            tmp.data() + pos,
240  
            tmp.data() + pos,
241  
            s,
241  
            s,
242  
            n);
242  
            n);
243  
        destroy(sp);
243  
        destroy(sp);
244  
        *this = tmp;
244  
        *this = tmp;
245  
    }
245  
    }
246  
}
246  
}
247  

247  

248  
char*
248  
char*
249  
string_impl::
249  
string_impl::
250  
insert_unchecked(
250  
insert_unchecked(
251  
    std::size_t pos,
251  
    std::size_t pos,
252  
    std::size_t n,
252  
    std::size_t n,
253  
    storage_ptr const& sp)
253  
    storage_ptr const& sp)
254  
{
254  
{
255  
    const auto curr_size = size();
255  
    const auto curr_size = size();
256  
    if(pos > curr_size)
256  
    if(pos > curr_size)
257  
    {
257  
    {
258  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
258  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
259  
        detail::throw_system_error( error::out_of_range, &loc );
259  
        detail::throw_system_error( error::out_of_range, &loc );
260  
    }
260  
    }
261  
    const auto curr_data = data();
261  
    const auto curr_data = data();
262  
    if(n <= capacity() - size())
262  
    if(n <= capacity() - size())
263  
    {
263  
    {
264  
        auto const dest =
264  
        auto const dest =
265  
            curr_data + pos;
265  
            curr_data + pos;
266  
        std::memmove(
266  
        std::memmove(
267  
            dest + n,
267  
            dest + n,
268  
            dest,
268  
            dest,
269  
            curr_size + 1 - pos);
269  
            curr_size + 1 - pos);
270  
        size(curr_size + n);
270  
        size(curr_size + n);
271  
        return dest;
271  
        return dest;
272  
    }
272  
    }
273  
    if(n > max_size() - curr_size)
273  
    if(n > max_size() - curr_size)
274  
    {
274  
    {
275  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
275  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
276  
        detail::throw_system_error( error::string_too_large, &loc );
276  
        detail::throw_system_error( error::string_too_large, &loc );
277  
    }
277  
    }
278  
    string_impl tmp(growth(
278  
    string_impl tmp(growth(
279  
        curr_size + n, capacity()), sp);
279  
        curr_size + n, capacity()), sp);
280  
    tmp.size(curr_size + n);
280  
    tmp.size(curr_size + n);
281  
    std::memcpy(
281  
    std::memcpy(
282  
        tmp.data(),
282  
        tmp.data(),
283  
        curr_data,
283  
        curr_data,
284  
        pos);
284  
        pos);
285  
    std::memcpy(
285  
    std::memcpy(
286  
        tmp.data() + pos + n,
286  
        tmp.data() + pos + n,
287  
        curr_data + pos,
287  
        curr_data + pos,
288  
        curr_size + 1 - pos);
288  
        curr_size + 1 - pos);
289  
    destroy(sp);
289  
    destroy(sp);
290  
    *this = tmp;
290  
    *this = tmp;
291  
    return data() + pos;
291  
    return data() + pos;
292  
}
292  
}
293  

293  

294  
void
294  
void
295  
string_impl::
295  
string_impl::
296  
replace(
296  
replace(
297  
    std::size_t pos,
297  
    std::size_t pos,
298  
    std::size_t n1,
298  
    std::size_t n1,
299  
    const char* s,
299  
    const char* s,
300  
    std::size_t n2,
300  
    std::size_t n2,
301  
    storage_ptr const& sp)
301  
    storage_ptr const& sp)
302  
{
302  
{
303  
    const auto curr_size = size();
303  
    const auto curr_size = size();
304  
    if (pos > curr_size)
304  
    if (pos > curr_size)
305  
    {
305  
    {
306  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
306  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
307  
        detail::throw_system_error( error::out_of_range, &loc );
307  
        detail::throw_system_error( error::out_of_range, &loc );
308  
    }
308  
    }
309  
    const auto curr_data = data();
309  
    const auto curr_data = data();
310  
    n1 = (std::min)(n1, curr_size - pos);
310  
    n1 = (std::min)(n1, curr_size - pos);
311  
    const auto delta = (std::max)(n1, n2) -
311  
    const auto delta = (std::max)(n1, n2) -
312  
        (std::min)(n1, n2);
312  
        (std::min)(n1, n2);
313  
    // if we are shrinking in size or we have enough
313  
    // if we are shrinking in size or we have enough
314  
    // capacity, dont reallocate
314  
    // capacity, dont reallocate
315  
    if (n1 > n2 || delta <= capacity() - curr_size)
315  
    if (n1 > n2 || delta <= capacity() - curr_size)
316  
    {
316  
    {
317  
        const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
317  
        const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
318  
        // there is nothing to replace; return
318  
        // there is nothing to replace; return
319  
        if (inside && s == curr_data + pos && n1 == n2)
319  
        if (inside && s == curr_data + pos && n1 == n2)
320  
            return;
320  
            return;
321  
        if (!inside || (inside && ((s - curr_data) + n2 <= pos)))
321  
        if (!inside || (inside && ((s - curr_data) + n2 <= pos)))
322  
        {
322  
        {
323  
            // source outside
323  
            // source outside
324  
            std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
324  
            std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
325  
            std::memcpy(&curr_data[pos], s, n2);
325  
            std::memcpy(&curr_data[pos], s, n2);
326  
        }
326  
        }
327  
        else
327  
        else
328  
        {
328  
        {
329  
            // source inside
329  
            // source inside
330  
            const std::size_t offset = s - curr_data;
330  
            const std::size_t offset = s - curr_data;
331  
            if (n2 >= n1)
331  
            if (n2 >= n1)
332  
            {
332  
            {
333  
                // grow/unchanged
333  
                // grow/unchanged
334  
                const std::size_t diff = offset <= pos + n1 ? (std::min)((pos + n1) - offset, n2) : 0;
334  
                const std::size_t diff = offset <= pos + n1 ? (std::min)((pos + n1) - offset, n2) : 0;
335  
                // shift all right of splice point by n2 - n1 to the right
335  
                // shift all right of splice point by n2 - n1 to the right
336  
                std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
336  
                std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
337  
                // copy all before splice point
337  
                // copy all before splice point
338  
                std::memmove(&curr_data[pos], &curr_data[offset], diff);
338  
                std::memmove(&curr_data[pos], &curr_data[offset], diff);
339  
                // copy all after splice point
339  
                // copy all after splice point
340  
                std::memmove(&curr_data[pos + diff], &curr_data[(offset - n1) + n2 + diff], n2 - diff);
340  
                std::memmove(&curr_data[pos + diff], &curr_data[(offset - n1) + n2 + diff], n2 - diff);
341  
            }
341  
            }
342  
            else
342  
            else
343  
            {
343  
            {
344  
                // shrink
344  
                // shrink
345  
                // copy all elements into place
345  
                // copy all elements into place
346  
                std::memmove(&curr_data[pos], &curr_data[offset], n2);
346  
                std::memmove(&curr_data[pos], &curr_data[offset], n2);
347  
                // shift all elements after splice point left
347  
                // shift all elements after splice point left
348  
                std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
348  
                std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
349  
            }
349  
            }
350  
        }
350  
        }
351  
        size((curr_size - n1) + n2);
351  
        size((curr_size - n1) + n2);
352  
    }
352  
    }
353  
    else
353  
    else
354  
    {
354  
    {
355  
        if (delta > max_size() - curr_size)
355  
        if (delta > max_size() - curr_size)
356  
        {
356  
        {
357  
            BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
357  
            BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
358  
            detail::throw_system_error( error::string_too_large, &loc );
358  
            detail::throw_system_error( error::string_too_large, &loc );
359  
        }
359  
        }
360  
        // would exceed capacity, reallocate
360  
        // would exceed capacity, reallocate
361  
        string_impl tmp(growth(
361  
        string_impl tmp(growth(
362  
            curr_size + delta, capacity()), sp);
362  
            curr_size + delta, capacity()), sp);
363  
        tmp.size(curr_size + delta);
363  
        tmp.size(curr_size + delta);
364  
        std::memcpy(
364  
        std::memcpy(
365  
            tmp.data(),
365  
            tmp.data(),
366  
            curr_data,
366  
            curr_data,
367  
            pos);
367  
            pos);
368  
        std::memcpy(
368  
        std::memcpy(
369  
            tmp.data() + pos + n2,
369  
            tmp.data() + pos + n2,
370  
            curr_data + pos + n1,
370  
            curr_data + pos + n1,
371  
            curr_size - pos - n1 + 1);
371  
            curr_size - pos - n1 + 1);
372  
        std::memcpy(
372  
        std::memcpy(
373  
            tmp.data() + pos,
373  
            tmp.data() + pos,
374  
            s,
374  
            s,
375  
            n2);
375  
            n2);
376  
        destroy(sp);
376  
        destroy(sp);
377  
        *this = tmp;
377  
        *this = tmp;
378  
    }
378  
    }
379  
}
379  
}
380  

380  

381  
// unlike the replace overload, this function does
381  
// unlike the replace overload, this function does
382  
// not move any characters
382  
// not move any characters
383  
char*
383  
char*
384  
string_impl::
384  
string_impl::
385  
replace_unchecked(
385  
replace_unchecked(
386  
    std::size_t pos,
386  
    std::size_t pos,
387  
    std::size_t n1,
387  
    std::size_t n1,
388  
    std::size_t n2,
388  
    std::size_t n2,
389  
    storage_ptr const& sp)
389  
    storage_ptr const& sp)
390  
{
390  
{
391  
    const auto curr_size = size();
391  
    const auto curr_size = size();
392  
    if(pos > curr_size)
392  
    if(pos > curr_size)
393  
    {
393  
    {
394  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
394  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
395  
        detail::throw_system_error( error::out_of_range, &loc );
395  
        detail::throw_system_error( error::out_of_range, &loc );
396  
    }
396  
    }
397  
    const auto curr_data = data();
397  
    const auto curr_data = data();
398  
    const auto delta = (std::max)(n1, n2) -
398  
    const auto delta = (std::max)(n1, n2) -
399  
        (std::min)(n1, n2);
399  
        (std::min)(n1, n2);
400  
    // if the size doesn't change, we don't need to
400  
    // if the size doesn't change, we don't need to
401  
    // do anything
401  
    // do anything
402  
    if (!delta)
402  
    if (!delta)
403  
      return curr_data + pos;
403  
      return curr_data + pos;
404  
    // if we are shrinking in size or we have enough
404  
    // if we are shrinking in size or we have enough
405  
    // capacity, dont reallocate
405  
    // capacity, dont reallocate
406  
    if(n1 > n2 || delta <= capacity() - curr_size)
406  
    if(n1 > n2 || delta <= capacity() - curr_size)
407  
    {
407  
    {
408  
        auto const replace_pos = curr_data + pos;
408  
        auto const replace_pos = curr_data + pos;
409  
        std::memmove(
409  
        std::memmove(
410  
            replace_pos + n2,
410  
            replace_pos + n2,
411  
            replace_pos + n1,
411  
            replace_pos + n1,
412  
            curr_size - pos - n1 + 1);
412  
            curr_size - pos - n1 + 1);
413  
        size((curr_size - n1) + n2);
413  
        size((curr_size - n1) + n2);
414  
        return replace_pos;
414  
        return replace_pos;
415  
    }
415  
    }
416  
    if(delta > max_size() - curr_size)
416  
    if(delta > max_size() - curr_size)
417  
    {
417  
    {
418  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
418  
        BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
419  
        detail::throw_system_error( error::string_too_large, &loc );
419  
        detail::throw_system_error( error::string_too_large, &loc );
420  
    }
420  
    }
421  
    // would exceed capacity, reallocate
421  
    // would exceed capacity, reallocate
422  
    string_impl tmp(growth(
422  
    string_impl tmp(growth(
423  
        curr_size + delta, capacity()), sp);
423  
        curr_size + delta, capacity()), sp);
424  
    tmp.size(curr_size + delta);
424  
    tmp.size(curr_size + delta);
425  
    std::memcpy(
425  
    std::memcpy(
426  
        tmp.data(),
426  
        tmp.data(),
427  
        curr_data,
427  
        curr_data,
428  
        pos);
428  
        pos);
429  
    std::memcpy(
429  
    std::memcpy(
430  
        tmp.data() + pos + n2,
430  
        tmp.data() + pos + n2,
431  
        curr_data + pos + n1,
431  
        curr_data + pos + n1,
432  
        curr_size - pos - n1 + 1);
432  
        curr_size - pos - n1 + 1);
433  
    destroy(sp);
433  
    destroy(sp);
434  
    *this = tmp;
434  
    *this = tmp;
435  
    return data() + pos;
435  
    return data() + pos;
436  
}
436  
}
437  

437  

438  
void
438  
void
439  
string_impl::
439  
string_impl::
440  
shrink_to_fit(
440  
shrink_to_fit(
441  
    storage_ptr const& sp) noexcept
441  
    storage_ptr const& sp) noexcept
442  
{
442  
{
443  
    if(s_.k == short_string_)
443  
    if(s_.k == short_string_)
444  
        return;
444  
        return;
445  
    auto const t = p_.t;
445  
    auto const t = p_.t;
446  
    if(t->size <= sbo_chars_)
446  
    if(t->size <= sbo_chars_)
447  
    {
447  
    {
448  
        s_.k = short_string_;
448  
        s_.k = short_string_;
449  
        std::memcpy(
449  
        std::memcpy(
450  
            s_.buf, data(), t->size);
450  
            s_.buf, data(), t->size);
451  
        s_.buf[sbo_chars_] =
451  
        s_.buf[sbo_chars_] =
452  
            static_cast<char>(
452  
            static_cast<char>(
453  
                sbo_chars_ - t->size);
453  
                sbo_chars_ - t->size);
454  
        s_.buf[t->size] = 0;
454  
        s_.buf[t->size] = 0;
455  
        sp->deallocate(t,
455  
        sp->deallocate(t,
456  
            sizeof(table) +
456  
            sizeof(table) +
457  
                t->capacity + 1,
457  
                t->capacity + 1,
458  
            alignof(table));
458  
            alignof(table));
459  
        return;
459  
        return;
460  
    }
460  
    }
461  
    if(t->size >= t->capacity)
461  
    if(t->size >= t->capacity)
462  
        return;
462  
        return;
463  
#ifndef BOOST_NO_EXCEPTIONS
463  
#ifndef BOOST_NO_EXCEPTIONS
464  
    try
464  
    try
465  
    {
465  
    {
466  
#endif
466  
#endif
467  
        string_impl tmp(t->size, sp);
467  
        string_impl tmp(t->size, sp);
468  
        std::memcpy(
468  
        std::memcpy(
469  
            tmp.data(),
469  
            tmp.data(),
470  
            data(),
470  
            data(),
471  
            size());
471  
            size());
472  
        destroy(sp);
472  
        destroy(sp);
473  
        *this = tmp;
473  
        *this = tmp;
474  
#ifndef BOOST_NO_EXCEPTIONS
474  
#ifndef BOOST_NO_EXCEPTIONS
475  
    }
475  
    }
476  
    catch(std::exception const&)
476  
    catch(std::exception const&)
477  
    {
477  
    {
478  
        // eat the exception
478  
        // eat the exception
479  
    }
479  
    }
480  
#endif
480  
#endif
481  
}
481  
}
482  

482  

483  
} // detail
483  
} // detail
484  
} // namespace json
484  
} // namespace json
485  
} // namespace boost
485  
} // namespace boost
486  

486  

487  
#endif
487  
#endif