GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/string_impl.hpp
Date: 2025-12-23 17:20:53
Exec Total Coverage
Lines: 73 73 100.0%
Functions: 22 22 100.0%
Branches: 24 27 88.9%

Line Branch Exec Source
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/json/detail/config.hpp>
15 #include <boost/json/kind.hpp>
16 #include <boost/json/storage_ptr.hpp>
17 #include <boost/json/detail/value.hpp>
18 #include <algorithm>
19 #include <iterator>
20
21 namespace boost {
22 namespace json {
23
24 class value;
25 class string;
26
27 namespace detail {
28
29 class string_impl
30 {
31 struct table
32 {
33 std::uint32_t size;
34 std::uint32_t capacity;
35 };
36
37 #if BOOST_JSON_ARCH == 64
38 static constexpr std::size_t sbo_chars_ = 14;
39 #elif BOOST_JSON_ARCH == 32
40 static constexpr std::size_t sbo_chars_ = 10;
41 #else
42 # error Unknown architecture
43 #endif
44
45 static
46 constexpr
47 kind
48 short_string_ =
49 static_cast<kind>(
50 ((unsigned char)
51 kind::string) | 0x80);
52
53 static
54 constexpr
55 kind
56 key_string_ =
57 static_cast<kind>(
58 ((unsigned char)
59 kind::string) | 0x40);
60
61 struct sbo
62 {
63 kind k; // must come first
64 char buf[sbo_chars_ + 1];
65 };
66
67 struct pointer
68 {
69 kind k; // must come first
70 table* t;
71 };
72
73 struct key
74 {
75 kind k; // must come first
76 std::uint32_t n;
77 char* s;
78 };
79
80 union
81 {
82 sbo s_;
83 pointer p_;
84 key k_;
85 };
86
87 #if BOOST_JSON_ARCH == 64
88 BOOST_STATIC_ASSERT(sizeof(sbo) <= 16);
89 BOOST_STATIC_ASSERT(sizeof(pointer) <= 16);
90 BOOST_STATIC_ASSERT(sizeof(key) <= 16);
91 #elif BOOST_JSON_ARCH == 32
92 BOOST_STATIC_ASSERT(sizeof(sbo) <= 24);
93 BOOST_STATIC_ASSERT(sizeof(pointer) <= 24);
94 BOOST_STATIC_ASSERT(sizeof(key) <= 24);
95 #endif
96
97 public:
98 static
99 constexpr
100 std::size_t
101 153810 max_size() noexcept
102 {
103 // max_size depends on the address model
104 using min = std::integral_constant<std::size_t,
105 std::size_t(-1) - sizeof(table)>;
106 return min::value < BOOST_JSON_MAX_STRING_SIZE ?
107 153810 min::value : BOOST_JSON_MAX_STRING_SIZE;
108 }
109
110 BOOST_JSON_DECL
111 string_impl() noexcept;
112
113 BOOST_JSON_DECL
114 string_impl(
115 std::size_t new_size,
116 storage_ptr const& sp);
117
118 BOOST_JSON_DECL
119 string_impl(
120 key_t,
121 string_view s,
122 storage_ptr const& sp);
123
124 BOOST_JSON_DECL
125 string_impl(
126 key_t,
127 string_view s1,
128 string_view s2,
129 storage_ptr const& sp);
130
131 BOOST_JSON_DECL
132 string_impl(
133 char** dest,
134 std::size_t len,
135 storage_ptr const& sp);
136
137 template<class InputIt>
138 16 string_impl(
139 InputIt first,
140 InputIt last,
141 storage_ptr const& sp,
142 std::random_access_iterator_tag)
143 16 : string_impl(last - first, sp)
144 {
145 14 char* out = data();
146 #if defined(_MSC_VER) && _MSC_VER <= 1900
147 while( first != last )
148 *out++ = *first++;
149 #else
150 14 std::copy(first, last, out);
151 #endif
152 14 }
153
154 template<class InputIt>
155 55 string_impl(
156 InputIt first,
157 InputIt last,
158 storage_ptr const& sp,
159 std::input_iterator_tag)
160 55 : string_impl(0, sp)
161 {
162 struct undo
163 {
164 string_impl* s;
165 storage_ptr const& sp;
166
167 38 ~undo()
168 {
169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
38 if(s)
170 3 s->destroy(sp);
171 38 }
172 };
173
174 55 undo u{this, sp};
175 55 auto dest = data();
176
2/2
✓ Branch 1 taken 278 times.
✓ Branch 2 taken 35 times.
576 while(first != last)
177 {
178
2/2
✓ Branch 2 taken 267 times.
✓ Branch 3 taken 11 times.
527 if(size() < capacity())
179 505 size(size() + 1);
180 else
181
1/1
✓ Branch 1 taken 8 times.
22 dest = append(1, sp);
182 521 *dest++ = *first++;
183 }
184 49 term(size());
185 49 u.s = nullptr;
186 55 }
187
188 std::size_t
189 99061 size() const noexcept
190 {
191
2/2
✓ Branch 0 taken 64288 times.
✓ Branch 1 taken 34773 times.
99061 return s_.k == kind::string ?
192 64288 p_.t->size :
193 sbo_chars_ -
194 99061 s_.buf[sbo_chars_];
195 }
196
197 std::size_t
198 92043 capacity() const noexcept
199 {
200
2/2
✓ Branch 0 taken 11708 times.
✓ Branch 1 taken 80335 times.
92043 return s_.k == kind::string ?
201 11708 p_.t->capacity :
202 92043 sbo_chars_;
203 }
204
205 void
206 10015 size(std::size_t n)
207 {
208
2/2
✓ Branch 0 taken 9733 times.
✓ Branch 1 taken 282 times.
10015 if(s_.k == kind::string)
209 9733 p_.t->size = static_cast<
210 std::uint32_t>(n);
211 else
212 282 s_.buf[sbo_chars_] =
213 static_cast<char>(
214 282 sbo_chars_ - n);
215 10015 }
216
217 BOOST_JSON_DECL
218 static
219 std::uint32_t
220 growth(
221 std::size_t new_size,
222 std::size_t capacity);
223
224 char const*
225 38150 release_key(
226 std::size_t& n) noexcept
227 {
228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 38150 times.
38150 BOOST_ASSERT(
229 k_.k == key_string_);
230 38150 n = k_.n;
231 38150 auto const s = k_.s;
232 // prevent deallocate
233 38150 k_.k = short_string_;
234 38150 return s;
235 }
236
237 void
238 58128 destroy(
239 storage_ptr const& sp) noexcept
240 {
241
2/2
✓ Branch 0 taken 26671 times.
✓ Branch 1 taken 31457 times.
58128 if(s_.k == kind::string)
242 {
243 26671 sp->deallocate(p_.t,
244 sizeof(table) +
245 26671 p_.t->capacity + 1,
246 alignof(table));
247 }
248
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 31311 times.
31457 else if(s_.k != key_string_)
249 {
250 // do nothing
251 }
252 else
253 {
254
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 146 times.
146 BOOST_ASSERT(
255 s_.k == key_string_);
256 // VFALCO unfortunately the key string
257 // kind increases the cost of the destructor.
258 // This function should be skipped when using
259 // monotonic_resource.
260 146 sp->deallocate(k_.s, k_.n + 1);
261 }
262 58128 }
263
264 BOOST_JSON_DECL
265 char*
266 assign(
267 std::size_t new_size,
268 storage_ptr const& sp);
269
270 BOOST_JSON_DECL
271 char*
272 append(
273 std::size_t n,
274 storage_ptr const& sp);
275
276 BOOST_JSON_DECL
277 void
278 insert(
279 std::size_t pos,
280 const char* s,
281 std::size_t n,
282 storage_ptr const& sp);
283
284 BOOST_JSON_DECL
285 char*
286 insert_unchecked(
287 std::size_t pos,
288 std::size_t n,
289 storage_ptr const& sp);
290
291 BOOST_JSON_DECL
292 void
293 replace(
294 std::size_t pos,
295 std::size_t n1,
296 const char* s,
297 std::size_t n2,
298 storage_ptr const& sp);
299
300 BOOST_JSON_DECL
301 char*
302 replace_unchecked(
303 std::size_t pos,
304 std::size_t n1,
305 std::size_t n2,
306 storage_ptr const& sp);
307
308 BOOST_JSON_DECL
309 void
310 shrink_to_fit(
311 storage_ptr const& sp) noexcept;
312
313 void
314 33733 term(std::size_t n) noexcept
315 {
316
2/2
✓ Branch 0 taken 5308 times.
✓ Branch 1 taken 28425 times.
33733 if(s_.k == short_string_)
317 {
318 5308 s_.buf[sbo_chars_] =
319 static_cast<char>(
320 5308 sbo_chars_ - n);
321 5308 s_.buf[n] = 0;
322 }
323 else
324 {
325 28425 p_.t->size = static_cast<
326 std::uint32_t>(n);
327 28425 data()[n] = 0;
328 }
329 33733 }
330
331 char*
332 117451 data() noexcept
333 {
334
2/2
✓ Branch 0 taken 15545 times.
✓ Branch 1 taken 101906 times.
117451 if(s_.k == short_string_)
335 15545 return s_.buf;
336 return reinterpret_cast<
337 101906 char*>(p_.t + 1);
338 }
339
340 char const*
341 44183 data() const noexcept
342 {
343
2/2
✓ Branch 0 taken 4728 times.
✓ Branch 1 taken 39455 times.
44183 if(s_.k == short_string_)
344 4728 return s_.buf;
345 return reinterpret_cast<
346 39455 char const*>(p_.t + 1);
347 }
348
349 char*
350 175 end() noexcept
351 {
352 175 return data() + size();
353 }
354
355 char const*
356 10 end() const noexcept
357 {
358 10 return data() + size();
359 }
360 };
361
362 template<class T>
363 string_view
364 2481 to_string_view(T const& t) noexcept
365 {
366 2481 return string_view(t);
367 }
368
369 template<class T, class U>
370 using string_and_stringlike = std::integral_constant<bool,
371 std::is_same<T, string>::value &&
372 std::is_convertible<U const&, string_view>::value>;
373
374 template<class T, class U>
375 using string_comp_op_requirement
376 = typename std::enable_if<
377 string_and_stringlike<T, U>::value ||
378 string_and_stringlike<U, T>::value,
379 bool>::type;
380
381 } // detail
382 } // namespace json
383 } // namespace boost
384
385 #endif
386