detail/string_impl.hpp

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