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_STRING_IMPL_HPP
11  
#ifndef BOOST_JSON_DETAIL_STRING_IMPL_HPP
12  
#define BOOST_JSON_DETAIL_STRING_IMPL_HPP
12  
#define BOOST_JSON_DETAIL_STRING_IMPL_HPP
13  

13  

14  
#include <boost/core/detail/static_assert.hpp>
14  
#include <boost/core/detail/static_assert.hpp>
15  
#include <boost/json/detail/config.hpp>
15  
#include <boost/json/detail/config.hpp>
16  
#include <boost/json/kind.hpp>
16  
#include <boost/json/kind.hpp>
17  
#include <boost/json/storage_ptr.hpp>
17  
#include <boost/json/storage_ptr.hpp>
18  
#include <boost/json/detail/value.hpp>
18  
#include <boost/json/detail/value.hpp>
19  
#include <algorithm>
19  
#include <algorithm>
20  
#include <iterator>
20  
#include <iterator>
21  

21  

22  
namespace boost {
22  
namespace boost {
23  
namespace json {
23  
namespace json {
24  

24  

25  
class value;
25  
class value;
26  
class string;
26  
class string;
27  

27  

28  
namespace detail {
28  
namespace detail {
29  

29  

30  
class string_impl
30  
class string_impl
31  
{
31  
{
32  
    struct table
32  
    struct table
33  
    {
33  
    {
34  
        std::uint32_t size;
34  
        std::uint32_t size;
35  
        std::uint32_t capacity;
35  
        std::uint32_t capacity;
36  
    };
36  
    };
37  

37  

38  
#if BOOST_JSON_ARCH == 64
38  
#if BOOST_JSON_ARCH == 64
39  
    static constexpr std::size_t sbo_chars_ = 14;
39  
    static constexpr std::size_t sbo_chars_ = 14;
40  
#elif BOOST_JSON_ARCH == 32
40  
#elif BOOST_JSON_ARCH == 32
41  
    static constexpr std::size_t sbo_chars_ = 10;
41  
    static constexpr std::size_t sbo_chars_ = 10;
42  
#else
42  
#else
43  
# error Unknown architecture
43  
# error Unknown architecture
44  
#endif
44  
#endif
45  

45  

46  
    static
46  
    static
47  
    constexpr
47  
    constexpr
48  
    kind
48  
    kind
49  
    short_string_ =
49  
    short_string_ =
50  
        static_cast<kind>(
50  
        static_cast<kind>(
51  
            ((unsigned char)
51  
            ((unsigned char)
52  
            kind::string) | 0x80);
52  
            kind::string) | 0x80);
53  

53  

54  
    static
54  
    static
55  
    constexpr
55  
    constexpr
56  
    kind
56  
    kind
57  
    key_string_ =
57  
    key_string_ =
58  
        static_cast<kind>(
58  
        static_cast<kind>(
59  
            ((unsigned char)
59  
            ((unsigned char)
60  
            kind::string) | 0x40);
60  
            kind::string) | 0x40);
61  

61  

62  
    struct sbo
62  
    struct sbo
63  
    {
63  
    {
64  
        kind k; // must come first
64  
        kind k; // must come first
65  
        char buf[sbo_chars_ + 1];
65  
        char buf[sbo_chars_ + 1];
66  
    };
66  
    };
67  

67  

68  
    struct pointer
68  
    struct pointer
69  
    {
69  
    {
70  
        kind k; // must come first
70  
        kind k; // must come first
71  
        table* t;
71  
        table* t;
72  
    };
72  
    };
73  

73  

74  
    struct key
74  
    struct key
75  
    {
75  
    {
76  
        kind k; // must come first
76  
        kind k; // must come first
77  
        std::uint32_t n;
77  
        std::uint32_t n;
78  
        char* s;
78  
        char* s;
79  
    };
79  
    };
80  

80  

81  
    union
81  
    union
82  
    {
82  
    {
83  
        sbo s_;
83  
        sbo s_;
84  
        pointer p_;
84  
        pointer p_;
85  
        key k_;
85  
        key k_;
86  
    };
86  
    };
87  

87  

88  
#if BOOST_JSON_ARCH == 64
88  
#if BOOST_JSON_ARCH == 64
89  
    BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
89  
    BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
90  
    BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
90  
    BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
91  
    BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
91  
    BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
92  
#elif BOOST_JSON_ARCH == 32
92  
#elif BOOST_JSON_ARCH == 32
93  
    BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
93  
    BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
94  
    BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
94  
    BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
95  
    BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
95  
    BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
96  
#endif
96  
#endif
97  

97  

98  
public:
98  
public:
99  
    static
99  
    static
100  
    constexpr
100  
    constexpr
101  
    std::size_t
101  
    std::size_t
102  
    max_size() noexcept
102  
    max_size() noexcept
103  
    {
103  
    {
104  
        // max_size depends on the address model
104  
        // max_size depends on the address model
105  
        using min = std::integral_constant<std::size_t,
105  
        using min = std::integral_constant<std::size_t,
106  
            std::size_t(-1) - sizeof(table)>;
106  
            std::size_t(-1) - sizeof(table)>;
107  
        return min::value < BOOST_JSON_MAX_STRING_SIZE ?
107  
        return min::value < BOOST_JSON_MAX_STRING_SIZE ?
108  
            min::value : BOOST_JSON_MAX_STRING_SIZE;
108  
            min::value : BOOST_JSON_MAX_STRING_SIZE;
109  
    }
109  
    }
110  

110  

111  
    BOOST_JSON_DECL
111  
    BOOST_JSON_DECL
112  
    string_impl() noexcept;
112  
    string_impl() noexcept;
113  

113  

114  
    BOOST_JSON_DECL
114  
    BOOST_JSON_DECL
115  
    string_impl(
115  
    string_impl(
116  
        std::size_t new_size,
116  
        std::size_t new_size,
117  
        storage_ptr const& sp);
117  
        storage_ptr const& sp);
118  

118  

119  
    BOOST_JSON_DECL
119  
    BOOST_JSON_DECL
120  
    string_impl(
120  
    string_impl(
121  
        key_t,
121  
        key_t,
122  
        string_view s,
122  
        string_view s,
123  
        storage_ptr const& sp);
123  
        storage_ptr const& sp);
124  

124  

125  
    BOOST_JSON_DECL
125  
    BOOST_JSON_DECL
126  
    string_impl(
126  
    string_impl(
127  
        key_t,
127  
        key_t,
128  
        string_view s1,
128  
        string_view s1,
129  
        string_view s2,
129  
        string_view s2,
130  
        storage_ptr const& sp);
130  
        storage_ptr const& sp);
131  

131  

132  
    BOOST_JSON_DECL
132  
    BOOST_JSON_DECL
133  
    string_impl(
133  
    string_impl(
134  
        char** dest,
134  
        char** dest,
135  
        std::size_t len,
135  
        std::size_t len,
136  
        storage_ptr const& sp);
136  
        storage_ptr const& sp);
137  

137  

138  
    template<class InputIt>
138  
    template<class InputIt>
139  
    string_impl(
139  
    string_impl(
140  
        InputIt first,
140  
        InputIt first,
141  
        InputIt last,
141  
        InputIt last,
142  
        storage_ptr const& sp,
142  
        storage_ptr const& sp,
143  
        std::random_access_iterator_tag)
143  
        std::random_access_iterator_tag)
144  
        : string_impl(last - first, sp)
144  
        : string_impl(last - first, sp)
145  
    {
145  
    {
146  
        char* out = data();
146  
        char* out = data();
147  
#if defined(_MSC_VER) && _MSC_VER <= 1900
147  
#if defined(_MSC_VER) && _MSC_VER <= 1900
148  
        while( first != last )
148  
        while( first != last )
149  
            *out++ = *first++;
149  
            *out++ = *first++;
150  
#else
150  
#else
151  
        std::copy(first, last, out);
151  
        std::copy(first, last, out);
152  
#endif
152  
#endif
153  
    }
153  
    }
154  

154  

155  
    template<class InputIt>
155  
    template<class InputIt>
156  
    string_impl(
156  
    string_impl(
157  
        InputIt first,
157  
        InputIt first,
158  
        InputIt last,
158  
        InputIt last,
159  
        storage_ptr const& sp,
159  
        storage_ptr const& sp,
160  
        std::input_iterator_tag)
160  
        std::input_iterator_tag)
161  
        : string_impl(0, sp)
161  
        : string_impl(0, sp)
162  
    {
162  
    {
163  
        struct undo
163  
        struct undo
164  
        {
164  
        {
165  
            string_impl* s;
165  
            string_impl* s;
166  
            storage_ptr const& sp;
166  
            storage_ptr const& sp;
167  

167  

168  
            ~undo()
168  
            ~undo()
169  
            {
169  
            {
170  
                if(s)
170  
                if(s)
171  
                    s->destroy(sp);
171  
                    s->destroy(sp);
172  
            }
172  
            }
173  
        };
173  
        };
174  

174  

175  
        undo u{this, sp};
175  
        undo u{this, sp};
176  
        auto dest = data();
176  
        auto dest = data();
177  
        while(first != last)
177  
        while(first != last)
178  
        {
178  
        {
179  
            if(size() < capacity())
179  
            if(size() < capacity())
180  
                size(size() + 1);
180  
                size(size() + 1);
181  
            else
181  
            else
182  
                dest = append(1, sp);
182  
                dest = append(1, sp);
183  
            *dest++ = *first++;
183  
            *dest++ = *first++;
184  
        }
184  
        }
185  
        term(size());
185  
        term(size());
186  
        u.s = nullptr;
186  
        u.s = nullptr;
187  
    }
187  
    }
188  

188  

189  
    std::size_t
189  
    std::size_t
190  
    size() const noexcept
190  
    size() const noexcept
191  
    {
191  
    {
192  
        return s_.k == kind::string ?
192  
        return s_.k == kind::string ?
193  
            p_.t->size :
193  
            p_.t->size :
194  
            sbo_chars_ -
194  
            sbo_chars_ -
195  
                s_.buf[sbo_chars_];
195  
                s_.buf[sbo_chars_];
196  
    }
196  
    }
197  

197  

198  
    std::size_t
198  
    std::size_t
199  
    capacity() const noexcept
199  
    capacity() const noexcept
200  
    {
200  
    {
201  
        return s_.k == kind::string ?
201  
        return s_.k == kind::string ?
202  
            p_.t->capacity :
202  
            p_.t->capacity :
203  
            sbo_chars_;
203  
            sbo_chars_;
204  
    }
204  
    }
205  

205  

206  
    void
206  
    void
207  
    size(std::size_t n)
207  
    size(std::size_t n)
208  
    {
208  
    {
209  
        if(s_.k == kind::string)
209  
        if(s_.k == kind::string)
210  
            p_.t->size = static_cast<
210  
            p_.t->size = static_cast<
211  
                std::uint32_t>(n);
211  
                std::uint32_t>(n);
212  
        else
212  
        else
213  
            s_.buf[sbo_chars_] =
213  
            s_.buf[sbo_chars_] =
214  
                static_cast<char>(
214  
                static_cast<char>(
215  
                    sbo_chars_ - n);
215  
                    sbo_chars_ - n);
216  
    }
216  
    }
217  

217  

218  
    BOOST_JSON_DECL
218  
    BOOST_JSON_DECL
219  
    static
219  
    static
220  
    std::uint32_t
220  
    std::uint32_t
221  
    growth(
221  
    growth(
222  
        std::size_t new_size,
222  
        std::size_t new_size,
223  
        std::size_t capacity);
223  
        std::size_t capacity);
224  

224  

225  
    char const*
225  
    char const*
226  
    release_key(
226  
    release_key(
227  
        std::size_t& n) noexcept
227  
        std::size_t& n) noexcept
228  
    {
228  
    {
229  
        BOOST_ASSERT(
229  
        BOOST_ASSERT(
230  
            k_.k == key_string_);
230  
            k_.k == key_string_);
231  
        n = k_.n;
231  
        n = k_.n;
232  
        auto const s = k_.s;
232  
        auto const s = k_.s;
233  
        // prevent deallocate
233  
        // prevent deallocate
234  
        k_.k = short_string_;
234  
        k_.k = short_string_;
235  
        return s;
235  
        return s;
236  
    }
236  
    }
237  

237  

238  
    void
238  
    void
239  
    destroy(
239  
    destroy(
240  
        storage_ptr const& sp) noexcept
240  
        storage_ptr const& sp) noexcept
241  
    {
241  
    {
242  
        if(s_.k == kind::string)
242  
        if(s_.k == kind::string)
243  
        {
243  
        {
244  
            sp->deallocate(p_.t,
244  
            sp->deallocate(p_.t,
245  
                sizeof(table) +
245  
                sizeof(table) +
246  
                    p_.t->capacity + 1,
246  
                    p_.t->capacity + 1,
247  
                alignof(table));
247  
                alignof(table));
248  
        }
248  
        }
249  
        else if(s_.k != key_string_)
249  
        else if(s_.k != key_string_)
250  
        {
250  
        {
251  
            // do nothing
251  
            // do nothing
252  
        }
252  
        }
253  
        else
253  
        else
254  
        {
254  
        {
255  
            BOOST_ASSERT(
255  
            BOOST_ASSERT(
256  
                s_.k == key_string_);
256  
                s_.k == key_string_);
257  
            // VFALCO unfortunately the key string
257  
            // VFALCO unfortunately the key string
258  
            // kind increases the cost of the destructor.
258  
            // kind increases the cost of the destructor.
259  
            // This function should be skipped when using
259  
            // This function should be skipped when using
260  
            // monotonic_resource.
260  
            // monotonic_resource.
261  
            sp->deallocate(k_.s, k_.n + 1);
261  
            sp->deallocate(k_.s, k_.n + 1);
262  
        }
262  
        }
263  
    }
263  
    }
264  

264  

265  
    BOOST_JSON_DECL
265  
    BOOST_JSON_DECL
266  
    char*
266  
    char*
267  
    assign(
267  
    assign(
268  
        std::size_t new_size,
268  
        std::size_t new_size,
269  
        storage_ptr const& sp);
269  
        storage_ptr const& sp);
270  

270  

271  
    BOOST_JSON_DECL
271  
    BOOST_JSON_DECL
272  
    char*
272  
    char*
273  
    append(
273  
    append(
274  
        std::size_t n,
274  
        std::size_t n,
275  
        storage_ptr const& sp);
275  
        storage_ptr const& sp);
276  

276  

277  
    BOOST_JSON_DECL
277  
    BOOST_JSON_DECL
278  
    void
278  
    void
279  
    insert(
279  
    insert(
280  
        std::size_t pos,
280  
        std::size_t pos,
281  
        const char* s,
281  
        const char* s,
282  
        std::size_t n,
282  
        std::size_t n,
283  
        storage_ptr const& sp);
283  
        storage_ptr const& sp);
284  

284  

285  
    BOOST_JSON_DECL
285  
    BOOST_JSON_DECL
286  
    char*
286  
    char*
287  
    insert_unchecked(
287  
    insert_unchecked(
288  
        std::size_t pos,
288  
        std::size_t pos,
289  
        std::size_t n,
289  
        std::size_t n,
290  
        storage_ptr const& sp);
290  
        storage_ptr const& sp);
291  

291  

292  
    BOOST_JSON_DECL
292  
    BOOST_JSON_DECL
293  
    void
293  
    void
294  
    replace(
294  
    replace(
295  
        std::size_t pos,
295  
        std::size_t pos,
296  
        std::size_t n1,
296  
        std::size_t n1,
297  
        const char* s,
297  
        const char* s,
298  
        std::size_t n2,
298  
        std::size_t n2,
299  
        storage_ptr const& sp);
299  
        storage_ptr const& sp);
300  

300  

301  
    BOOST_JSON_DECL
301  
    BOOST_JSON_DECL
302  
    char*
302  
    char*
303  
    replace_unchecked(
303  
    replace_unchecked(
304  
        std::size_t pos,
304  
        std::size_t pos,
305  
        std::size_t n1,
305  
        std::size_t n1,
306  
        std::size_t n2,
306  
        std::size_t n2,
307  
        storage_ptr const& sp);
307  
        storage_ptr const& sp);
308  

308  

309  
    BOOST_JSON_DECL
309  
    BOOST_JSON_DECL
310  
    void
310  
    void
311  
    shrink_to_fit(
311  
    shrink_to_fit(
312  
        storage_ptr const& sp) noexcept;
312  
        storage_ptr const& sp) noexcept;
313  

313  

314  
    void
314  
    void
315  
    term(std::size_t n) noexcept
315  
    term(std::size_t n) noexcept
316  
    {
316  
    {
317  
        if(s_.k == short_string_)
317  
        if(s_.k == short_string_)
318  
        {
318  
        {
319  
            s_.buf[sbo_chars_] =
319  
            s_.buf[sbo_chars_] =
320  
                static_cast<char>(
320  
                static_cast<char>(
321  
                    sbo_chars_ - n);
321  
                    sbo_chars_ - n);
322  
            s_.buf[n] = 0;
322  
            s_.buf[n] = 0;
323  
        }
323  
        }
324  
        else
324  
        else
325  
        {
325  
        {
326  
            p_.t->size = static_cast<
326  
            p_.t->size = static_cast<
327  
                std::uint32_t>(n);
327  
                std::uint32_t>(n);
328  
            data()[n] = 0;
328  
            data()[n] = 0;
329  
        }
329  
        }
330  
    }
330  
    }
331  

331  

332  
    char*
332  
    char*
333  
    data() noexcept
333  
    data() noexcept
334  
    {
334  
    {
335  
        if(s_.k == short_string_)
335  
        if(s_.k == short_string_)
336  
            return s_.buf;
336  
            return s_.buf;
337  
        return reinterpret_cast<
337  
        return reinterpret_cast<
338  
            char*>(p_.t + 1);
338  
            char*>(p_.t + 1);
339  
    }
339  
    }
340  

340  

341  
    char const*
341  
    char const*
342  
    data() const noexcept
342  
    data() const noexcept
343  
    {
343  
    {
344  
        if(s_.k == short_string_)
344  
        if(s_.k == short_string_)
345  
            return s_.buf;
345  
            return s_.buf;
346  
        return reinterpret_cast<
346  
        return reinterpret_cast<
347  
            char const*>(p_.t + 1);
347  
            char const*>(p_.t + 1);
348  
    }
348  
    }
349  

349  

350  
    char*
350  
    char*
351  
    end() noexcept
351  
    end() noexcept
352  
    {
352  
    {
353  
        return data() + size();
353  
        return data() + size();
354  
    }
354  
    }
355  

355  

356  
    char const*
356  
    char const*
357  
    end() const noexcept
357  
    end() const noexcept
358  
    {
358  
    {
359  
        return data() + size();
359  
        return data() + size();
360  
    }
360  
    }
361  
};
361  
};
362  

362  

363  
template<class T>
363  
template<class T>
364  
string_view
364  
string_view
365  
to_string_view(T const& t) noexcept
365  
to_string_view(T const& t) noexcept
366  
{
366  
{
367  
    return string_view(t);
367  
    return string_view(t);
368  
}
368  
}
369  

369  

370  
template<class T, class U>
370  
template<class T, class U>
371  
using string_and_stringlike = std::integral_constant<bool,
371  
using string_and_stringlike = std::integral_constant<bool,
372  
    std::is_same<T, string>::value &&
372  
    std::is_same<T, string>::value &&
373  
    std::is_convertible<U const&, string_view>::value>;
373  
    std::is_convertible<U const&, string_view>::value>;
374  

374  

375  
template<class T, class U>
375  
template<class T, class U>
376  
using string_comp_op_requirement
376  
using string_comp_op_requirement
377  
    = typename std::enable_if<
377  
    = typename std::enable_if<
378  
        string_and_stringlike<T, U>::value ||
378  
        string_and_stringlike<T, U>::value ||
379  
        string_and_stringlike<U, T>::value,
379  
        string_and_stringlike<U, T>::value,
380  
        bool>::type;
380  
        bool>::type;
381  

381  

382  
} // detail
382  
} // detail
383  
} // namespace json
383  
} // namespace json
384  
} // namespace boost
384  
} // namespace boost
385  

385  

386  
#endif
386  
#endif