GCC Code Coverage Report


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