detail/impl/string_impl.ipp

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