detail/impl/string_impl.ipp

100.0% Lines (230 / 230) 100.0% Functions (12 / 12)
string_impl.ipp
f(x) Functions (12)
Function Calls Lines Blocks
boost::json::detail::string_impl::string_impl() :23 31070x 100.0% 100.0% boost::json::detail::string_impl::string_impl(unsigned long, boost::json::storage_ptr const&) :34 26968x 100.0% 100.0% boost::json::detail::string_impl::string_impl(boost::json::detail::key_t, boost::core::basic_string_view<char>, boost::json::storage_ptr const&) :66 30297x 100.0% 92.0% boost::json::detail::string_impl::string_impl(boost::json::detail::key_t, boost::core::basic_string_view<char>, boost::core::basic_string_view<char>, boost::json::storage_ptr const&) :86 8061x 100.0% 92.0% boost::json::detail::string_impl::growth(unsigned long, unsigned long) :109 53847x 100.0% 100.0% boost::json::detail::string_impl::assign(unsigned long, boost::json::storage_ptr const&) :129 18500x 100.0% 100.0% boost::json::detail::string_impl::append(unsigned long, boost::json::storage_ptr const&) :147 259x 100.0% 96.0% boost::json::detail::string_impl::insert(unsigned long, char const*, unsigned long, boost::json::storage_ptr const&) :173 27x 100.0% 97.0% boost::json::detail::string_impl::insert_unchecked(unsigned long, unsigned long, boost::json::storage_ptr const&) :240 18x 100.0% 100.0% boost::json::detail::string_impl::replace(unsigned long, unsigned long, char const*, unsigned long, boost::json::storage_ptr const&) :286 19x 100.0% 95.0% boost::json::detail::string_impl::replace_unchecked(unsigned long, unsigned long, unsigned long, boost::json::storage_ptr const&) :375 11x 100.0% 97.0% boost::json::detail::string_impl::shrink_to_fit(boost::json::storage_ptr const&) :431 11x 100.0% 95.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_IMPL_STRING_IMPL_IPP
12 #define BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
13
14 #include <boost/json/detail/string_impl.hpp>
15 #include <boost/json/detail/except.hpp>
16 #include <cstring>
17 #include <functional>
18
19 namespace boost {
20 namespace json {
21 namespace detail {
22
23 31070x string_impl::
24 31070x string_impl() noexcept
25 31070x : s_{}
26 {
27 31070x s_.k = short_string_;
28 31070x s_.buf[sbo_chars_] =
29 static_cast<char>(
30 sbo_chars_);
31 31070x s_.buf[0] = 0;
32 31070x }
33
34 26968x string_impl::
35 string_impl(
36 std::size_t size,
37 26968x storage_ptr const& sp)
38 26968x : s_{}
39 {
40 26968x if(size <= sbo_chars_)
41 {
42 41x s_.k = short_string_;
43 41x s_.buf[sbo_chars_] =
44 static_cast<char>(
45 41x sbo_chars_ - size);
46 41x s_.buf[size] = 0;
47 }
48 else
49 {
50 26927x s_.k = kind::string;
51 26927x auto const n = growth(
52 size, sbo_chars_ + 1);
53 26927x p_.t = ::new(sp->allocate(
54 sizeof(table) +
55 26927x n + 1,
56 alignof(table))) table{
57 static_cast<
58 std::uint32_t>(size),
59 static_cast<
60 26725x std::uint32_t>(n)};
61 26725x data()[n] = 0;
62 }
63 26766x }
64
65 // construct a key, unchecked
66 30297x string_impl::
67 string_impl(
68 key_t,
69 string_view s,
70 30297x storage_ptr const& sp)
71 {
72 30297x BOOST_ASSERT(
73 s.size() <= max_size());
74 30297x k_.k = key_string_;
75 30297x k_.n = static_cast<
76 30297x std::uint32_t>(s.size());
77 30237x k_.s = reinterpret_cast<char*>(
78 30297x sp->allocate(s.size() + 1,
79 alignof(char)));
80 30237x k_.s[s.size()] = 0; // null term
81 30237x std::memcpy(&k_.s[0],
82 30237x s.data(), s.size());
83 30237x }
84
85 // construct a key, unchecked
86 8061x string_impl::
87 string_impl(
88 key_t,
89 string_view s1,
90 string_view s2,
91 8061x storage_ptr const& sp)
92 {
93 8061x auto len = s1.size() + s2.size();
94 8061x BOOST_ASSERT(len <= max_size());
95 8061x k_.k = key_string_;
96 8061x k_.n = static_cast<
97 std::uint32_t>(len);
98 8061x k_.s = reinterpret_cast<char*>(
99 8061x sp->allocate(len + 1,
100 alignof(char)));
101 8061x k_.s[len] = 0; // null term
102 8061x std::memcpy(&k_.s[0],
103 8061x s1.data(), s1.size());
104 16122x std::memcpy(&k_.s[s1.size()],
105 8061x s2.data(), s2.size());
106 8061x }
107
108 std::uint32_t
109 53847x string_impl::
110 growth(
111 std::size_t new_size,
112 std::size_t capacity)
113 {
114 53847x if(new_size > max_size())
115 {
116 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
117 1x detail::throw_system_error( error::string_too_large, &loc );
118 }
119 // growth factor 2
120 53846x if( capacity >
121 53846x max_size() - capacity)
122 return static_cast<
123 1x std::uint32_t>(max_size()); // overflow
124 return static_cast<std::uint32_t>(
125 53845x (std::max)(capacity * 2, new_size));
126 }
127
128 char*
129 18500x string_impl::
130 assign(
131 std::size_t new_size,
132 storage_ptr const& sp)
133 {
134 18500x if(new_size > capacity())
135 {
136 17135x string_impl tmp(growth(
137 new_size,
138 17135x capacity()), sp);
139 16986x destroy(sp);
140 16986x *this = tmp;
141 }
142 18351x term(new_size);
143 18351x return data();
144 }
145
146 char*
147 259x string_impl::
148 append(
149 std::size_t n,
150 storage_ptr const& sp)
151 {
152 259x if(n > max_size() - size())
153 {
154 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
155 1x detail::throw_system_error( error::string_too_large, &loc );
156 }
157 258x if(n <= capacity() - size())
158 {
159 199x term(size() + n);
160 199x return end() - n;
161 }
162 118x string_impl tmp(growth(
163 118x size() + n, capacity()), sp);
164 36x std::memcpy(
165 36x tmp.data(), data(), size());
166 36x tmp.term(size() + n);
167 36x destroy(sp);
168 36x *this = tmp;
169 36x return end() - n;
170 }
171
172 void
173 27x string_impl::
174 insert(
175 std::size_t pos,
176 const char* s,
177 std::size_t n,
178 storage_ptr const& sp)
179 {
180 27x const auto curr_size = size();
181 27x if(pos > curr_size)
182 {
183 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
184 2x detail::throw_system_error( error::out_of_range, &loc );
185 }
186 25x const auto curr_data = data();
187 25x if(n <= capacity() - curr_size)
188 {
189 10x const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
190 10x if (!inside || (inside && ((s - curr_data) + n <= pos)))
191 {
192 8x std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
193 8x std::memcpy(&curr_data[pos], s, n);
194 }
195 else
196 {
197 2x const std::size_t offset = s - curr_data;
198 2x std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
199 2x if (offset < pos)
200 {
201 1x const std::size_t diff = pos - offset;
202 1x std::memcpy(&curr_data[pos], &curr_data[offset], diff);
203 1x std::memcpy(&curr_data[pos + diff], &curr_data[pos + n], n - diff);
204 }
205 else
206 {
207 1x std::memcpy(&curr_data[pos], &curr_data[offset + n], n);
208 }
209 }
210 10x size(curr_size + n);
211 }
212 else
213 {
214 15x if(n > max_size() - curr_size)
215 {
216 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
217 1x detail::throw_system_error( error::string_too_large, &loc );
218 }
219 14x string_impl tmp(growth(
220 14x curr_size + n, capacity()), sp);
221 7x tmp.size(curr_size + n);
222 7x std::memcpy(
223 7x tmp.data(),
224 curr_data,
225 pos);
226 14x std::memcpy(
227 14x tmp.data() + pos + n,
228 curr_data + pos,
229 7x curr_size + 1 - pos);
230 7x std::memcpy(
231 7x tmp.data() + pos,
232 s,
233 n);
234 7x destroy(sp);
235 7x *this = tmp;
236 }
237 17x }
238
239 char*
240 18x string_impl::
241 insert_unchecked(
242 std::size_t pos,
243 std::size_t n,
244 storage_ptr const& sp)
245 {
246 18x const auto curr_size = size();
247 18x if(pos > curr_size)
248 {
249 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
250 1x detail::throw_system_error( error::out_of_range, &loc );
251 }
252 17x const auto curr_data = data();
253 17x if(n <= capacity() - size())
254 {
255 5x auto const dest =
256 curr_data + pos;
257 5x std::memmove(
258 dest + n,
259 dest,
260 5x curr_size + 1 - pos);
261 5x size(curr_size + n);
262 5x return dest;
263 }
264 12x if(n > max_size() - curr_size)
265 {
266 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
267 1x detail::throw_system_error( error::string_too_large, &loc );
268 }
269 11x string_impl tmp(growth(
270 11x curr_size + n, capacity()), sp);
271 6x tmp.size(curr_size + n);
272 6x std::memcpy(
273 6x tmp.data(),
274 curr_data,
275 pos);
276 12x std::memcpy(
277 12x tmp.data() + pos + n,
278 curr_data + pos,
279 6x curr_size + 1 - pos);
280 6x destroy(sp);
281 6x *this = tmp;
282 6x return data() + pos;
283 }
284
285 void
286 19x string_impl::
287 replace(
288 std::size_t pos,
289 std::size_t n1,
290 const char* s,
291 std::size_t n2,
292 storage_ptr const& sp)
293 {
294 19x const auto curr_size = size();
295 19x if (pos > curr_size)
296 {
297 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
298 1x detail::throw_system_error( error::out_of_range, &loc );
299 }
300 18x const auto curr_data = data();
301 18x n1 = (std::min)(n1, curr_size - pos);
302 18x const auto delta = (std::max)(n1, n2) -
303 18x (std::min)(n1, n2);
304 // if we are shrinking in size or we have enough
305 // capacity, dont reallocate
306 18x if (n1 > n2 || delta <= capacity() - curr_size)
307 {
308 13x const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
309 // there is nothing to replace; return
310 13x if (inside && s == curr_data + pos && n1 == n2)
311 1x return;
312 12x if (!inside || (inside && ((s - curr_data) + n2 <= pos)))
313 {
314 // source outside
315 6x std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
316 6x std::memcpy(&curr_data[pos], s, n2);
317 }
318 else
319 {
320 // source inside
321 6x const std::size_t offset = s - curr_data;
322 6x if (n2 >= n1)
323 {
324 // grow/unchanged
325 4x const std::size_t diff = offset <= pos + n1 ? (std::min)((pos + n1) - offset, n2) : 0;
326 // shift all right of splice point by n2 - n1 to the right
327 4x std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
328 // copy all before splice point
329 4x std::memmove(&curr_data[pos], &curr_data[offset], diff);
330 // copy all after splice point
331 4x std::memmove(&curr_data[pos + diff], &curr_data[(offset - n1) + n2 + diff], n2 - diff);
332 }
333 else
334 {
335 // shrink
336 // copy all elements into place
337 2x std::memmove(&curr_data[pos], &curr_data[offset], n2);
338 // shift all elements after splice point left
339 2x std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
340 }
341 }
342 12x size((curr_size - n1) + n2);
343 }
344 else
345 {
346 5x if (delta > max_size() - curr_size)
347 {
348 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
349 1x detail::throw_system_error( error::string_too_large, &loc );
350 }
351 // would exceed capacity, reallocate
352 4x string_impl tmp(growth(
353 4x curr_size + delta, capacity()), sp);
354 2x tmp.size(curr_size + delta);
355 2x std::memcpy(
356 2x tmp.data(),
357 curr_data,
358 pos);
359 4x std::memcpy(
360 4x tmp.data() + pos + n2,
361 2x curr_data + pos + n1,
362 2x curr_size - pos - n1 + 1);
363 4x std::memcpy(
364 2x tmp.data() + pos,
365 s,
366 n2);
367 2x destroy(sp);
368 2x *this = tmp;
369 }
370 }
371
372 // unlike the replace overload, this function does
373 // not move any characters
374 char*
375 11x string_impl::
376 replace_unchecked(
377 std::size_t pos,
378 std::size_t n1,
379 std::size_t n2,
380 storage_ptr const& sp)
381 {
382 11x const auto curr_size = size();
383 11x if(pos > curr_size)
384 {
385 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
386 1x detail::throw_system_error( error::out_of_range, &loc );
387 }
388 10x const auto curr_data = data();
389 10x n1 = (std::min)(n1, curr_size - pos);
390 10x const auto delta = (std::max)(n1, n2) -
391 10x (std::min)(n1, n2);
392 // if the size doesn't change, we don't need to
393 // do anything
394 10x if (!delta)
395 1x return curr_data + pos;
396 // if we are shrinking in size or we have enough
397 // capacity, dont reallocate
398 9x if(n1 > n2 || delta <= capacity() - curr_size)
399 {
400 4x auto const replace_pos = curr_data + pos;
401 4x std::memmove(
402 4x replace_pos + n2,
403 4x replace_pos + n1,
404 4x curr_size - pos - n1 + 1);
405 4x size((curr_size - n1) + n2);
406 4x return replace_pos;
407 }
408 5x if(delta > max_size() - curr_size)
409 {
410 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
411 1x detail::throw_system_error( error::string_too_large, &loc );
412 }
413 // would exceed capacity, reallocate
414 4x string_impl tmp(growth(
415 4x curr_size + delta, capacity()), sp);
416 2x tmp.size(curr_size + delta);
417 2x std::memcpy(
418 2x tmp.data(),
419 curr_data,
420 pos);
421 4x std::memcpy(
422 4x tmp.data() + pos + n2,
423 2x curr_data + pos + n1,
424 2x curr_size - pos - n1 + 1);
425 2x destroy(sp);
426 2x *this = tmp;
427 2x return data() + pos;
428 }
429
430 void
431 11x string_impl::
432 shrink_to_fit(
433 storage_ptr const& sp) noexcept
434 {
435 11x if(s_.k == short_string_)
436 3x return;
437 8x auto const t = p_.t;
438 8x if(t->size <= sbo_chars_)
439 {
440 6x std::memcpy(
441 3x s_.buf, data(), t->size);
442 3x s_.k = short_string_;
443 3x s_.buf[sbo_chars_] =
444 static_cast<char>(
445 3x sbo_chars_ - t->size);
446 3x s_.buf[t->size] = 0;
447 3x sp->deallocate(t,
448 sizeof(table) +
449 3x t->capacity + 1,
450 alignof(table));
451 3x return;
452 }
453 5x if(t->size >= t->capacity)
454 2x return;
455 #ifndef BOOST_NO_EXCEPTIONS
456 try
457 {
458 #endif
459 3x string_impl tmp(t->size, sp);
460 4x std::memcpy(
461 2x tmp.data(),
462 2x data(),
463 2x size() + 1);
464 2x destroy(sp);
465 2x *this = tmp;
466 #ifndef BOOST_NO_EXCEPTIONS
467 }
468 1x catch(std::exception const&)
469 {
470 // eat the exception
471 1x }
472 #endif
473 }
474
475 } // detail
476 } // namespace json
477 } // namespace boost
478
479 #endif
480