detail/impl/string_impl.ipp

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