TLA 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 : inline
31 : bool
32 HIT 78 : ptr_in_range(char const* first, char const* last, char const* ptr) noexcept
33 : {
34 113 : return std::less<char const*>()(ptr, last) &&
35 113 : std::greater_equal<char const*>()(ptr, first);
36 : }
37 :
38 :
39 : class string_impl
40 : {
41 : struct table
42 : {
43 : std::uint32_t size;
44 : std::uint32_t capacity;
45 : };
46 :
47 : #if BOOST_JSON_ARCH == 64
48 : static constexpr std::size_t sbo_chars_ = 14;
49 : #elif BOOST_JSON_ARCH == 32
50 : static constexpr std::size_t sbo_chars_ = 10;
51 : #else
52 : # error Unknown architecture
53 : #endif
54 :
55 : static constexpr
56 : unsigned char
57 : short_flag = 0x80;
58 :
59 : static constexpr
60 : unsigned char
61 : key_flag = 0x40;
62 :
63 : static constexpr
64 : unsigned char
65 : seamless_flag = 0x20;
66 :
67 : void
68 2 : set_storage_kind(unsigned char storage_kind)
69 : {
70 2 : unsigned char current = static_cast<unsigned char>(s_.k);
71 2 : current = current & 0x2F;
72 2 : s_.k = static_cast<kind>(current | storage_kind);
73 2 : }
74 :
75 : static
76 : constexpr
77 : kind
78 : short_string_ =
79 : static_cast<kind>(
80 : ((unsigned char)
81 : kind::string) | short_flag);
82 :
83 : static
84 : constexpr
85 : kind
86 : key_string_ =
87 : static_cast<kind>(
88 : ((unsigned char)
89 : kind::string) | key_flag);
90 :
91 : struct sbo
92 : {
93 : kind k; // must come first
94 : char buf[sbo_chars_ + 1];
95 : };
96 :
97 : struct pointer
98 : {
99 : kind k; // must come first
100 : table* t;
101 : };
102 :
103 : struct key
104 : {
105 : kind k; // must come first
106 : std::uint32_t n;
107 : char* s;
108 : };
109 :
110 : union
111 : {
112 : sbo s_;
113 : pointer p_;
114 : key k_;
115 : };
116 :
117 : #if BOOST_JSON_ARCH == 64
118 : BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
119 : BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
120 : BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
121 : #elif BOOST_JSON_ARCH == 32
122 : BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
123 : BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
124 : BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
125 : #endif
126 :
127 : public:
128 : static
129 : constexpr
130 : std::size_t
131 154259 : max_size() noexcept
132 : {
133 : // max_size depends on the address model
134 : using min = std::integral_constant<std::size_t,
135 : std::size_t(-1) - sizeof(table)>;
136 : return min::value < BOOST_JSON_MAX_STRING_SIZE ?
137 154259 : min::value : BOOST_JSON_MAX_STRING_SIZE;
138 : }
139 :
140 : BOOST_JSON_DECL
141 : string_impl() noexcept;
142 :
143 : BOOST_JSON_DECL
144 : string_impl(
145 : std::size_t new_size,
146 : storage_ptr const& sp);
147 :
148 : BOOST_JSON_DECL
149 : string_impl(
150 : key_t,
151 : string_view s,
152 : storage_ptr const& sp);
153 :
154 : BOOST_JSON_DECL
155 : string_impl(
156 : key_t,
157 : string_view s1,
158 : string_view s2,
159 : storage_ptr const& sp);
160 :
161 : BOOST_JSON_DECL
162 : string_impl(
163 : char** dest,
164 : std::size_t len,
165 : storage_ptr const& sp);
166 :
167 : template<class InputIt>
168 8 : string_impl(
169 : InputIt first,
170 : InputIt last,
171 : storage_ptr const& sp,
172 : std::random_access_iterator_tag)
173 8 : : string_impl(last - first, sp)
174 : {
175 7 : char* out = data();
176 : #if defined(_MSC_VER) && _MSC_VER <= 1900
177 : while( first != last )
178 : *out++ = *first++;
179 : #else
180 7 : std::copy(first, last, out);
181 : #endif
182 7 : }
183 :
184 : template<class InputIt>
185 38 : string_impl(
186 : InputIt first,
187 : InputIt last,
188 : storage_ptr const& sp,
189 : std::input_iterator_tag)
190 38 : : string_impl(0, sp)
191 : {
192 : struct undo
193 : {
194 : string_impl* s;
195 : storage_ptr const& sp;
196 :
197 38 : ~undo()
198 : {
199 38 : if(s)
200 3 : s->destroy(sp);
201 38 : }
202 : };
203 :
204 38 : undo u{this, sp};
205 38 : auto dest = data();
206 313 : while(first != last)
207 : {
208 278 : if(size() < capacity())
209 267 : size(size() + 1);
210 : else
211 11 : dest = append(1, sp);
212 275 : *dest++ = *first++;
213 : }
214 35 : term(size());
215 35 : u.s = nullptr;
216 38 : }
217 :
218 : std::size_t
219 99932 : size() const noexcept
220 : {
221 99932 : return s_.k == kind::string ?
222 65016 : p_.t->size :
223 : sbo_chars_ -
224 99932 : s_.buf[sbo_chars_];
225 : }
226 :
227 : std::size_t
228 92398 : capacity() const noexcept
229 : {
230 92398 : return s_.k == kind::string ?
231 11962 : p_.t->capacity :
232 92398 : sbo_chars_;
233 : }
234 :
235 : void
236 10059 : size(std::size_t n)
237 : {
238 10059 : if(s_.k == kind::string)
239 9776 : p_.t->size = static_cast<
240 : std::uint32_t>(n);
241 : else
242 283 : s_.buf[sbo_chars_] =
243 : static_cast<char>(
244 283 : sbo_chars_ - n);
245 10059 : }
246 :
247 : BOOST_JSON_DECL
248 : static
249 : std::uint32_t
250 : growth(
251 : std::size_t new_size,
252 : std::size_t capacity);
253 :
254 : char const*
255 38154 : release_key(
256 : std::size_t& n) noexcept
257 : {
258 38154 : BOOST_ASSERT( is_key() );
259 38154 : BOOST_ASSERT( ! is_seamless() );
260 38154 : n = k_.n;
261 38154 : auto const s = k_.s;
262 : // prevent deallocate
263 38154 : k_.k = short_string_;
264 38154 : return s;
265 : }
266 :
267 : void
268 57834 : destroy(storage_ptr const& sp) noexcept
269 : {
270 57834 : if( is_short() )
271 : {
272 : // do nothing
273 : }
274 26885 : else if( is_key() )
275 : {
276 : // VFALCO unfortunately the key string
277 : // kind increases the cost of the destructor.
278 : // This function should be skipped when using
279 : // monotonic_resource.
280 146 : sp->deallocate(k_.s, k_.n + 1);
281 : }
282 : else
283 : {
284 26739 : sp->deallocate(
285 26739 : p_.t, sizeof(table) + p_.t->capacity + 1, alignof(table));
286 : }
287 57834 : }
288 :
289 : BOOST_JSON_DECL
290 : char*
291 : assign(
292 : std::size_t new_size,
293 : storage_ptr const& sp);
294 :
295 : BOOST_JSON_DECL
296 : char*
297 : append(
298 : std::size_t n,
299 : storage_ptr const& sp);
300 :
301 : BOOST_JSON_DECL
302 : void
303 : insert(
304 : std::size_t pos,
305 : const char* s,
306 : std::size_t n,
307 : storage_ptr const& sp);
308 :
309 : BOOST_JSON_DECL
310 : char*
311 : insert_unchecked(
312 : std::size_t pos,
313 : std::size_t n,
314 : storage_ptr const& sp);
315 :
316 : BOOST_JSON_DECL
317 : void
318 : replace(
319 : std::size_t pos,
320 : std::size_t n1,
321 : const char* s,
322 : std::size_t n2,
323 : storage_ptr const& sp);
324 :
325 : BOOST_JSON_DECL
326 : char*
327 : replace_unchecked(
328 : std::size_t pos,
329 : std::size_t n1,
330 : std::size_t n2,
331 : storage_ptr const& sp);
332 :
333 : BOOST_JSON_DECL
334 : void
335 : shrink_to_fit(
336 : storage_ptr const& sp) noexcept;
337 :
338 : void
339 33801 : term(std::size_t n) noexcept
340 : {
341 33801 : if( is_short() )
342 : {
343 5177 : s_.buf[sbo_chars_] = static_cast<char>(sbo_chars_ - n);
344 5177 : s_.buf[n] = 0;
345 : }
346 : else
347 : {
348 28624 : p_.t->size = static_cast<std::uint32_t>(n);
349 28624 : data()[n] = 0;
350 : }
351 33801 : }
352 :
353 : char*
354 117954 : data() noexcept
355 : {
356 117954 : if( is_short() )
357 15495 : return s_.buf;
358 102459 : return reinterpret_cast<char*>(p_.t + 1);
359 : }
360 :
361 : char const*
362 44202 : data() const noexcept
363 : {
364 44202 : if( is_short() )
365 4684 : return s_.buf;
366 39518 : return reinterpret_cast<char const*>(p_.t + 1);
367 : }
368 :
369 : char*
370 241 : end() noexcept
371 : {
372 241 : return data() + size();
373 : }
374 :
375 : char const*
376 10 : end() const noexcept
377 : {
378 10 : return data() + size();
379 : }
380 :
381 : inline
382 : constexpr
383 : bool
384 253798 : is_short() const noexcept
385 : {
386 253798 : return static_cast<unsigned char>(s_.k) & short_flag;
387 : }
388 :
389 : inline
390 : constexpr
391 : bool
392 65039 : is_key() const noexcept
393 : {
394 65039 : return static_cast<unsigned char>(s_.k) & key_flag;
395 : }
396 :
397 : inline
398 : constexpr
399 : bool
400 52905 : is_seamless() const noexcept
401 : {
402 52905 : return static_cast<unsigned char>(s_.k) & seamless_flag;
403 : }
404 :
405 : void
406 4 : set_seamless(bool on) noexcept
407 : {
408 4 : unsigned char const seamless = on ? seamless_flag : 0;
409 4 : unsigned char current = static_cast<unsigned char>(s_.k);
410 4 : current = current & 0xCF;
411 4 : s_.k = static_cast<kind>(current | seamless);
412 4 : }
413 : };
414 :
415 : template<class T>
416 : string_view
417 2530 : to_string_view(T const& t) noexcept
418 : {
419 2530 : return string_view(t);
420 : }
421 :
422 : template<class T, class U>
423 : using string_and_stringlike = std::integral_constant<bool,
424 : std::is_same<T, string>::value &&
425 : std::is_convertible<U const&, string_view>::value>;
426 :
427 : template<class T, class U>
428 : using string_comp_op_requirement
429 : = typename std::enable_if<
430 : string_and_stringlike<T, U>::value ||
431 : string_and_stringlike<U, T>::value,
432 : bool>::type;
433 :
434 : } // detail
435 : } // namespace json
436 : } // namespace boost
437 :
438 : #endif
|