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 -
#include <boost/core/detail/static_assert.hpp>
 
14  

13  

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

20  

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

23  

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

26  

28  
namespace detail {
27  
namespace detail {
29  

28  

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

36  

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

44  

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

52  

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

60  

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

66  

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

72  

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

79  

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

86  

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

96  

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

109  

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

112  

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

117  

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

123  

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

130  

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

136  

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

153  

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

166  

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

173  

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

187  

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

196  

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

204  

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

216  

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

223  

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

236  

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

263  

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

269  

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

275  

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

283  

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

290  

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

299  

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

307  

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

312  

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

330  

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

339  

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

348  

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

354  

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

361  

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

368  

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

373  

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

380  

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

384  

386  
#endif
385  
#endif