detail/string_impl.hpp

98.7% Lines (75/76) 100.0% List of functions (23/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 18871x 100.0% 100.0% boost::json::detail::string_impl::max_size() :111 154151x 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 118309x 100.0% 100.0% boost::json::detail::string_impl::capacity() const :208 92559x 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 57728x 100.0% 89.0% boost::json::detail::string_impl::term(unsigned long) :325 34093x 100.0% 100.0% boost::json::detail::string_impl::data() :343 136862x 100.0% 100.0% boost::json::detail::string_impl::data() const :352 44039x 100.0% 100.0% boost::json::detail::string_impl::end() :361 272x 100.0% 100.0% boost::json::detail::string_impl::end() const :367 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&) :375 8x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<char [14]>(char const (&) [14]) :375 1x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<char [3]>(char const (&) [3]) :375 109x 100.0% 100.0% boost::core::basic_string_view<char> boost::json::detail::to_string_view<char [6]>(char const (&) [6]) :375 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&) :375 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 18871x ptr_in_range(char const* first, char const* last, char const* ptr) noexcept
33 {
34 20427x return std::less<char const*>()(ptr, last) &&
35 20427x 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 154151x 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 154151x 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 118309x size() const noexcept
200 {
201 118309x return s_.k == kind::string ?
202 64866x p_.t->size :
203 sbo_chars_ -
204 118309x s_.buf[sbo_chars_];
205 }
206
207 std::size_t
208 92559x capacity() const noexcept
209 {
210 92559x return s_.k == kind::string ?
211 11913x p_.t->capacity :
212 92559x 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 57728x destroy(
249 storage_ptr const& sp) noexcept
250 {
251 57728x if(s_.k == kind::string)
252 {
253 26702x sp->deallocate(p_.t,
254 sizeof(table) +
255 26702x p_.t->capacity + 1,
256 alignof(table));
257 }
258 31026x else if(s_.k != key_string_)
259 {
260 // do nothing
261 }
262 else
263 {
264 148x 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 148x sp->deallocate(k_.s, k_.n + 1,
271 alignof(char));
272 }
273 57728x }
274
275 BOOST_JSON_DECL
276 char*
277 assign(
278 std::size_t new_size,
279 storage_ptr const& sp);
280
281 BOOST_JSON_DECL
282 char*
283 append(
284 std::size_t n,
285 storage_ptr const& sp);
286
287 BOOST_JSON_DECL
288 void
289 insert(
290 std::size_t pos,
291 const char* s,
292 std::size_t n,
293 storage_ptr const& sp);
294
295 BOOST_JSON_DECL
296 char*
297 insert_unchecked(
298 std::size_t pos,
299 std::size_t n,
300 storage_ptr const& sp);
301
302 BOOST_JSON_DECL
303 void
304 replace(
305 std::size_t pos,
306 std::size_t n1,
307 const char* s,
308 std::size_t n2,
309 storage_ptr const& sp);
310
311 BOOST_JSON_DECL
312 char*
313 replace_unchecked(
314 std::size_t pos,
315 std::size_t n1,
316 std::size_t n2,
317 storage_ptr const& sp);
318
319 BOOST_JSON_DECL
320 void
321 shrink_to_fit(
322 storage_ptr const& sp) noexcept;
323
324 void
325 34093x term(std::size_t n) noexcept
326 {
327 34093x if(s_.k == short_string_)
328 {
329 5545x s_.buf[sbo_chars_] =
330 static_cast<char>(
331 5545x sbo_chars_ - n);
332 5545x s_.buf[n] = 0;
333 }
334 else
335 {
336 28548x p_.t->size = static_cast<
337 std::uint32_t>(n);
338 28548x data()[n] = 0;
339 }
340 34093x }
341
342 char*
343 136862x data() noexcept
344 {
345 136862x if(s_.k == short_string_)
346 34598x return s_.buf;
347 return reinterpret_cast<
348 102264x char*>(p_.t + 1);
349 }
350
351 char const*
352 44039x data() const noexcept
353 {
354 44039x if(s_.k == short_string_)
355 4554x return s_.buf;
356 return reinterpret_cast<
357 39485x char const*>(p_.t + 1);
358 }
359
360 char*
361 272x end() noexcept
362 {
363 272x return data() + size();
364 }
365
366 char const*
367 10x end() const noexcept
368 {
369 10x return data() + size();
370 }
371 };
372
373 template<class T>
374 string_view
375 2490x to_string_view(T const& t) noexcept
376 {
377 2490x return string_view(t);
378 }
379
380 template<class T, class U>
381 using string_and_stringlike = std::integral_constant<bool,
382 std::is_same<T, string>::value &&
383 std::is_convertible<U const&, string_view>::value>;
384
385 template<class T, class U>
386 using string_comp_op_requirement
387 = typename std::enable_if<
388 string_and_stringlike<T, U>::value ||
389 string_and_stringlike<U, T>::value,
390 bool>::type;
391
392 } // detail
393 } // namespace json
394 } // namespace boost
395
396 #endif
397