Line data Source code
1 : //
2 : // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
3 : // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
4 : //
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)
7 : //
8 : // Official repository: https://github.com/boostorg/json
9 : //
10 :
11 : #ifndef BOOST_JSON_DETAIL_STRING_IMPL_HPP
12 : #define BOOST_JSON_DETAIL_STRING_IMPL_HPP
13 :
14 : #include <boost/core/detail/static_assert.hpp>
15 : #include <boost/json/detail/config.hpp>
16 : #include <boost/json/kind.hpp>
17 : #include <boost/json/storage_ptr.hpp>
18 : #include <boost/json/detail/value.hpp>
19 : #include <algorithm>
20 : #include <iterator>
21 :
22 : namespace boost {
23 : namespace json {
24 :
25 : class value;
26 : class string;
27 :
28 : namespace detail {
29 :
30 : class string_impl
31 : {
32 : struct table
33 : {
34 : std::uint32_t size;
35 : std::uint32_t capacity;
36 : };
37 :
38 : #if BOOST_JSON_ARCH == 64
39 : static constexpr std::size_t sbo_chars_ = 14;
40 : #elif BOOST_JSON_ARCH == 32
41 : static constexpr std::size_t sbo_chars_ = 10;
42 : #else
43 : # error Unknown architecture
44 : #endif
45 :
46 : static
47 : constexpr
48 : kind
49 : short_string_ =
50 : static_cast<kind>(
51 : ((unsigned char)
52 : kind::string) | 0x80);
53 :
54 : static
55 : constexpr
56 : kind
57 : key_string_ =
58 : static_cast<kind>(
59 : ((unsigned char)
60 : kind::string) | 0x40);
61 :
62 : struct sbo
63 : {
64 : kind k; // must come first
65 : char buf[sbo_chars_ + 1];
66 : };
67 :
68 : struct pointer
69 : {
70 : kind k; // must come first
71 : table* t;
72 : };
73 :
74 : struct key
75 : {
76 : kind k; // must come first
77 : std::uint32_t n;
78 : char* s;
79 : };
80 :
81 : union
82 : {
83 : sbo s_;
84 : pointer p_;
85 : key k_;
86 : };
87 :
88 : #if BOOST_JSON_ARCH == 64
89 : BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
90 : BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
91 : BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
92 : #elif BOOST_JSON_ARCH == 32
93 : BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
94 : BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
95 : BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
96 : #endif
97 :
98 : public:
99 : static
100 : constexpr
101 : std::size_t
102 153866 : max_size() noexcept
103 : {
104 : // max_size depends on the address model
105 : using min = std::integral_constant<std::size_t,
106 : std::size_t(-1) - sizeof(table)>;
107 : return min::value < BOOST_JSON_MAX_STRING_SIZE ?
108 153866 : min::value : BOOST_JSON_MAX_STRING_SIZE;
109 : }
110 :
111 : BOOST_JSON_DECL
112 : string_impl() noexcept;
113 :
114 : BOOST_JSON_DECL
115 : string_impl(
116 : std::size_t new_size,
117 : storage_ptr const& sp);
118 :
119 : BOOST_JSON_DECL
120 : string_impl(
121 : key_t,
122 : string_view s,
123 : storage_ptr const& sp);
124 :
125 : BOOST_JSON_DECL
126 : string_impl(
127 : key_t,
128 : string_view s1,
129 : string_view s2,
130 : storage_ptr const& sp);
131 :
132 : BOOST_JSON_DECL
133 : string_impl(
134 : char** dest,
135 : std::size_t len,
136 : storage_ptr const& sp);
137 :
138 : template<class InputIt>
139 8 : string_impl(
140 : InputIt first,
141 : InputIt last,
142 : storage_ptr const& sp,
143 : std::random_access_iterator_tag)
144 8 : : string_impl(last - first, sp)
145 : {
146 7 : char* out = data();
147 : #if defined(_MSC_VER) && _MSC_VER <= 1900
148 : while( first != last )
149 : *out++ = *first++;
150 : #else
151 7 : std::copy(first, last, out);
152 : #endif
153 7 : }
154 :
155 : template<class InputIt>
156 38 : string_impl(
157 : InputIt first,
158 : InputIt last,
159 : storage_ptr const& sp,
160 : std::input_iterator_tag)
161 38 : : string_impl(0, sp)
162 : {
163 : struct undo
164 : {
165 : string_impl* s;
166 : storage_ptr const& sp;
167 :
168 38 : ~undo()
169 : {
170 38 : if(s)
171 3 : s->destroy(sp);
172 38 : }
173 : };
174 :
175 38 : undo u{this, sp};
176 38 : auto dest = data();
177 313 : while(first != last)
178 : {
179 278 : if(size() < capacity())
180 267 : size(size() + 1);
181 : else
182 11 : dest = append(1, sp);
183 275 : *dest++ = *first++;
184 : }
185 35 : term(size());
186 35 : u.s = nullptr;
187 38 : }
188 :
189 : std::size_t
190 98892 : size() const noexcept
191 : {
192 98892 : return s_.k == kind::string ?
193 64299 : p_.t->size :
194 : sbo_chars_ -
195 98892 : s_.buf[sbo_chars_];
196 : }
197 :
198 : std::size_t
199 91875 : capacity() const noexcept
200 : {
201 91875 : return s_.k == kind::string ?
202 11708 : p_.t->capacity :
203 91875 : sbo_chars_;
204 : }
205 :
206 : void
207 10015 : size(std::size_t n)
208 : {
209 10015 : if(s_.k == kind::string)
210 9733 : p_.t->size = static_cast<
211 : std::uint32_t>(n);
212 : else
213 282 : s_.buf[sbo_chars_] =
214 : static_cast<char>(
215 282 : sbo_chars_ - n);
216 10015 : }
217 :
218 : BOOST_JSON_DECL
219 : static
220 : std::uint32_t
221 : growth(
222 : std::size_t new_size,
223 : std::size_t capacity);
224 :
225 : char const*
226 38150 : release_key(
227 : std::size_t& n) noexcept
228 : {
229 38150 : BOOST_ASSERT(
230 : k_.k == key_string_);
231 38150 : n = k_.n;
232 38150 : auto const s = k_.s;
233 : // prevent deallocate
234 38150 : k_.k = short_string_;
235 38150 : return s;
236 : }
237 :
238 : void
239 57650 : destroy(
240 : storage_ptr const& sp) noexcept
241 : {
242 57650 : if(s_.k == kind::string)
243 : {
244 26671 : sp->deallocate(p_.t,
245 : sizeof(table) +
246 26671 : p_.t->capacity + 1,
247 : alignof(table));
248 : }
249 30979 : else if(s_.k != key_string_)
250 : {
251 : // do nothing
252 : }
253 : else
254 : {
255 146 : BOOST_ASSERT(
256 : s_.k == key_string_);
257 : // VFALCO unfortunately the key string
258 : // kind increases the cost of the destructor.
259 : // This function should be skipped when using
260 : // monotonic_resource.
261 146 : sp->deallocate(k_.s, k_.n + 1);
262 : }
263 57650 : }
264 :
265 : BOOST_JSON_DECL
266 : char*
267 : assign(
268 : std::size_t new_size,
269 : storage_ptr const& sp);
270 :
271 : BOOST_JSON_DECL
272 : char*
273 : append(
274 : std::size_t n,
275 : storage_ptr const& sp);
276 :
277 : BOOST_JSON_DECL
278 : void
279 : insert(
280 : std::size_t pos,
281 : const char* s,
282 : std::size_t n,
283 : storage_ptr const& sp);
284 :
285 : BOOST_JSON_DECL
286 : char*
287 : insert_unchecked(
288 : std::size_t pos,
289 : std::size_t n,
290 : storage_ptr const& sp);
291 :
292 : BOOST_JSON_DECL
293 : void
294 : replace(
295 : std::size_t pos,
296 : std::size_t n1,
297 : const char* s,
298 : std::size_t n2,
299 : storage_ptr const& sp);
300 :
301 : BOOST_JSON_DECL
302 : char*
303 : replace_unchecked(
304 : std::size_t pos,
305 : std::size_t n1,
306 : std::size_t n2,
307 : storage_ptr const& sp);
308 :
309 : BOOST_JSON_DECL
310 : void
311 : shrink_to_fit(
312 : storage_ptr const& sp) noexcept;
313 :
314 : void
315 33565 : term(std::size_t n) noexcept
316 : {
317 33565 : if(s_.k == short_string_)
318 : {
319 5140 : s_.buf[sbo_chars_] =
320 : static_cast<char>(
321 5140 : sbo_chars_ - n);
322 5140 : s_.buf[n] = 0;
323 : }
324 : else
325 : {
326 28425 : p_.t->size = static_cast<
327 : std::uint32_t>(n);
328 28425 : data()[n] = 0;
329 : }
330 33565 : }
331 :
332 : char*
333 117283 : data() noexcept
334 : {
335 117283 : if(s_.k == short_string_)
336 15377 : return s_.buf;
337 : return reinterpret_cast<
338 101906 : char*>(p_.t + 1);
339 : }
340 :
341 : char const*
342 44003 : data() const noexcept
343 : {
344 44003 : if(s_.k == short_string_)
345 4548 : return s_.buf;
346 : return reinterpret_cast<
347 39455 : char const*>(p_.t + 1);
348 : }
349 :
350 : char*
351 175 : end() noexcept
352 : {
353 175 : return data() + size();
354 : }
355 :
356 : char const*
357 10 : end() const noexcept
358 : {
359 10 : return data() + size();
360 : }
361 : };
362 :
363 : template<class T>
364 : string_view
365 2481 : to_string_view(T const& t) noexcept
366 : {
367 2481 : return string_view(t);
368 : }
369 :
370 : template<class T, class U>
371 : using string_and_stringlike = std::integral_constant<bool,
372 : std::is_same<T, string>::value &&
373 : std::is_convertible<U const&, string_view>::value>;
374 :
375 : template<class T, class U>
376 : using string_comp_op_requirement
377 : = typename std::enable_if<
378 : string_and_stringlike<T, U>::value ||
379 : string_and_stringlike<U, T>::value,
380 : bool>::type;
381 :
382 : } // detail
383 : } // namespace json
384 : } // namespace boost
385 :
386 : #endif
|