detail/string_impl.hpp

98.9% Lines (91/92) 100.0% List of functions (28/28)
string_impl.hpp
f(x) Functions (28)
Function Calls Lines Blocks
boost::json::detail::ptr_in_range(char const*, char const*, char const*) :32 78x 100.0% 100.0% boost::json::detail::string_impl::set_storage_kind(unsigned char) :68 2x 100.0% 100.0% boost::json::detail::string_impl::max_size() :131 154259x 100.0% 100.0% boost::json::detail::string_impl::string_impl<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >(__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, __gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >, boost::json::storage_ptr const&, std::random_access_iterator_tag) :168 3x 100.0% 100.0% boost::json::detail::string_impl::string_impl<char const*>(char const*, char const*, boost::json::storage_ptr const&, std::random_access_iterator_tag) :168 5x 100.0% 100.0% boost::json::detail::string_impl::string_impl<boost::json::detail::pointer_token::iterator>(boost::json::detail::pointer_token::iterator, boost::json::detail::pointer_token::iterator, boost::json::storage_ptr const&, std::input_iterator_tag) :185 21x 100.0% 82.0% boost::json::detail::string_impl::string_impl<boost::json::input_iterator<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > > >(boost::json::input_iterator<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::json::input_iterator<__gnu_cxx::__normal_iterator<char const*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > > >, boost::json::storage_ptr const&, std::input_iterator_tag) :185 12x 100.0% 100.0% boost::json::detail::string_impl::string_impl<boost::json::input_iterator<char const*> >(boost::json::input_iterator<char const*>, boost::json::input_iterator<char const*>, boost::json::storage_ptr const&, std::input_iterator_tag) :185 5x 100.0% 100.0% boost::json::detail::string_impl::string_impl<boost::json::detail::pointer_token::iterator>(boost::json::detail::pointer_token::iterator, boost::json::detail::pointer_token::iterator, boost::json::storage_ptr const&, std::input_iterator_tag)::undo::~undo() :197 21x 85.7% 67.0% boost::json::detail::string_impl::size() const :219 99932x 100.0% 100.0% boost::json::detail::string_impl::capacity() const :228 92398x 100.0% 100.0% boost::json::detail::string_impl::size(unsigned long) :236 10059x 100.0% 100.0% boost::json::detail::string_impl::release_key(unsigned long&) :255 38154x 100.0% 75.0% boost::json::detail::string_impl::destroy(boost::json::storage_ptr const&) :268 57834x 100.0% 100.0% boost::json::detail::string_impl::term(unsigned long) :339 33801x 100.0% 100.0% boost::json::detail::string_impl::data() :354 117954x 100.0% 100.0% boost::json::detail::string_impl::data() const :362 44202x 100.0% 100.0% boost::json::detail::string_impl::end() :370 241x 100.0% 100.0% boost::json::detail::string_impl::end() const :376 10x 100.0% 100.0% boost::json::detail::string_impl::is_short() const :384 253798x 100.0% 100.0% boost::json::detail::string_impl::is_key() const :392 65039x 100.0% 100.0% boost::json::detail::string_impl::is_seamless() const :400 52905x 100.0% 100.0% boost::json::detail::string_impl::set_seamless(bool) :406 4x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<boost::core::basic_string_view<char> >(boost::core::basic_string_view<char> const&) :417 8x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<char [14]>(char const (&) [14]) :417 1x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<char [3]>(char const (&) [3]) :417 109x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<char [6]>(char const (&) [6]) :417 15x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) :417 2141x 100.0% 100.0%
Line TLA Hits 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 78x ptr_in_range(char const* first, char const* last, char const* ptr) noexcept
33 {
34 113x return std::less<char const*>()(ptr, last) &&
35 113x 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 2x set_storage_kind(unsigned char storage_kind)
69 {
70 2x unsigned char current = static_cast<unsigned char>(s_.k);
71 2x current = current & 0x2F;
72 2x s_.k = static_cast<kind>(current | storage_kind);
73 2x }
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 154259x 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 154259x 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 8x string_impl(
169 InputIt first,
170 InputIt last,
171 storage_ptr const& sp,
172 std::random_access_iterator_tag)
173 8x : string_impl(last - first, sp)
174 {
175 7x char* out = data();
176 #if defined(_MSC_VER) && _MSC_VER <= 1900
177 while( first != last )
178 *out++ = *first++;
179 #else
180 7x std::copy(first, last, out);
181 #endif
182 7x }
183
184 template<class InputIt>
185 38x string_impl(
186 InputIt first,
187 InputIt last,
188 storage_ptr const& sp,
189 std::input_iterator_tag)
190 38x : string_impl(0, sp)
191 {
192 struct undo
193 {
194 string_impl* s;
195 storage_ptr const& sp;
196
197 21x ~undo()
198 {
199 21x if(s)
200 s->destroy(sp);
201 21x }
202 };
203
204 38x undo u{this, sp};
205 38x auto dest = data();
206 313x while(first != last)
207 {
208 278x if(size() < capacity())
209 267x size(size() + 1);
210 else
211 11x dest = append(1, sp);
212 275x *dest++ = *first++;
213 }
214 35x term(size());
215 35x u.s = nullptr;
216 38x }
217
218 std::size_t
219 99932x size() const noexcept
220 {
221 99932x return s_.k == kind::string ?
222 65016x p_.t->size :
223 sbo_chars_ -
224 99932x s_.buf[sbo_chars_];
225 }
226
227 std::size_t
228 92398x capacity() const noexcept
229 {
230 92398x return s_.k == kind::string ?
231 11962x p_.t->capacity :
232 92398x sbo_chars_;
233 }
234
235 void
236 10059x size(std::size_t n)
237 {
238 10059x if(s_.k == kind::string)
239 9776x p_.t->size = static_cast<
240 std::uint32_t>(n);
241 else
242 283x s_.buf[sbo_chars_] =
243 static_cast<char>(
244 283x sbo_chars_ - n);
245 10059x }
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 38154x release_key(
256 std::size_t& n) noexcept
257 {
258 38154x BOOST_ASSERT( is_key() );
259 38154x BOOST_ASSERT( ! is_seamless() );
260 38154x n = k_.n;
261 38154x auto const s = k_.s;
262 // prevent deallocate
263 38154x k_.k = short_string_;
264 38154x return s;
265 }
266
267 void
268 57834x destroy(storage_ptr const& sp) noexcept
269 {
270 57834x if( is_short() )
271 {
272 // do nothing
273 }
274 26885x 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 146x sp->deallocate(k_.s, k_.n + 1);
281 }
282 else
283 {
284 26739x sp->deallocate(
285 26739x p_.t, sizeof(table) + p_.t->capacity + 1, alignof(table));
286 }
287 57834x }
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 33801x term(std::size_t n) noexcept
340 {
341 33801x if( is_short() )
342 {
343 5177x s_.buf[sbo_chars_] = static_cast<char>(sbo_chars_ - n);
344 5177x s_.buf[n] = 0;
345 }
346 else
347 {
348 28624x p_.t->size = static_cast<std::uint32_t>(n);
349 28624x data()[n] = 0;
350 }
351 33801x }
352
353 char*
354 117954x data() noexcept
355 {
356 117954x if( is_short() )
357 15495x return s_.buf;
358 102459x return reinterpret_cast<char*>(p_.t + 1);
359 }
360
361 char const*
362 44202x data() const noexcept
363 {
364 44202x if( is_short() )
365 4684x return s_.buf;
366 39518x return reinterpret_cast<char const*>(p_.t + 1);
367 }
368
369 char*
370 241x end() noexcept
371 {
372 241x return data() + size();
373 }
374
375 char const*
376 10x end() const noexcept
377 {
378 10x return data() + size();
379 }
380
381 inline
382 constexpr
383 bool
384 253798x is_short() const noexcept
385 {
386 253798x return static_cast<unsigned char>(s_.k) & short_flag;
387 }
388
389 inline
390 constexpr
391 bool
392 65039x is_key() const noexcept
393 {
394 65039x return static_cast<unsigned char>(s_.k) & key_flag;
395 }
396
397 inline
398 constexpr
399 bool
400 52905x is_seamless() const noexcept
401 {
402 52905x return static_cast<unsigned char>(s_.k) & seamless_flag;
403 }
404
405 void
406 4x set_seamless(bool on) noexcept
407 {
408 4x unsigned char const seamless = on ? seamless_flag : 0;
409 4x unsigned char current = static_cast<unsigned char>(s_.k);
410 4x current = current & 0xCF;
411 4x s_.k = static_cast<kind>(current | seamless);
412 4x }
413 };
414
415 template<class T>
416 string_view
417 2530x to_string_view(T const& t) noexcept
418 {
419 2530x 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
439