/src/boost/boost/json/detail/string_impl.hpp
Line | Count | Source (jump to first uncovered line) |
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 | | max_size() noexcept |
102 | 55.2k | { |
103 | | // max_size depends on the address model |
104 | 55.2k | using min = std::integral_constant<std::size_t, |
105 | 55.2k | std::size_t(-1) - sizeof(table)>; |
106 | 55.2k | return min::value < BOOST_JSON_MAX_STRING_SIZE ? |
107 | 55.2k | min::value : BOOST_JSON_MAX_STRING_SIZE; |
108 | 55.2k | } |
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 | | string_impl( |
139 | | InputIt first, |
140 | | InputIt last, |
141 | | storage_ptr const& sp, |
142 | | std::random_access_iterator_tag) |
143 | | : string_impl(last - first, sp) |
144 | | { |
145 | | char* out = data(); |
146 | | #if defined(_MSC_VER) && _MSC_VER <= 1900 |
147 | | while( first != last ) |
148 | | *out++ = *first++; |
149 | | #else |
150 | | std::copy(first, last, out); |
151 | | #endif |
152 | | } |
153 | | |
154 | | template<class InputIt> |
155 | | string_impl( |
156 | | InputIt first, |
157 | | InputIt last, |
158 | | storage_ptr const& sp, |
159 | | std::input_iterator_tag) |
160 | 0 | : string_impl(0, sp) |
161 | 0 | { |
162 | 0 | struct undo |
163 | 0 | { |
164 | 0 | string_impl* s; |
165 | 0 | storage_ptr const& sp; |
166 | |
|
167 | 0 | ~undo() |
168 | 0 | { |
169 | 0 | if(s) |
170 | 0 | s->destroy(sp); |
171 | 0 | } |
172 | 0 | }; |
173 | |
|
174 | 0 | undo u{this, sp}; |
175 | 0 | auto dest = data(); |
176 | 0 | while(first != last) |
177 | 0 | { |
178 | 0 | if(size() < capacity()) |
179 | 0 | size(size() + 1); |
180 | 0 | else |
181 | 0 | dest = append(1, sp); |
182 | 0 | *dest++ = *first++; |
183 | 0 | } |
184 | 0 | term(size()); |
185 | 0 | u.s = nullptr; |
186 | 0 | } |
187 | | |
188 | | std::size_t |
189 | | size() const noexcept |
190 | 70.0k | { |
191 | 70.0k | return s_.k == kind::string ? |
192 | 18.9k | p_.t->size : |
193 | 70.0k | sbo_chars_ - |
194 | 51.0k | s_.buf[sbo_chars_]; |
195 | 70.0k | } |
196 | | |
197 | | std::size_t |
198 | | capacity() const noexcept |
199 | 93.0k | { |
200 | 93.0k | return s_.k == kind::string ? |
201 | 0 | p_.t->capacity : |
202 | 93.0k | sbo_chars_; |
203 | 93.0k | } |
204 | | |
205 | | void |
206 | | size(std::size_t n) |
207 | 8.43k | { |
208 | 8.43k | if(s_.k == kind::string) |
209 | 8.43k | p_.t->size = static_cast< |
210 | 8.43k | std::uint32_t>(n); |
211 | 0 | else |
212 | 0 | s_.buf[sbo_chars_] = |
213 | 0 | static_cast<char>( |
214 | 0 | sbo_chars_ - n); |
215 | 8.43k | } |
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 | | release_key( |
226 | | std::size_t& n) noexcept |
227 | 1.19M | { |
228 | 1.19M | BOOST_ASSERT( |
229 | 1.19M | k_.k == key_string_); |
230 | 1.19M | n = k_.n; |
231 | 1.19M | auto const s = k_.s; |
232 | | // prevent deallocate |
233 | 1.19M | k_.k = short_string_; |
234 | 1.19M | return s; |
235 | 1.19M | } |
236 | | |
237 | | void |
238 | | destroy( |
239 | | storage_ptr const& sp) noexcept |
240 | 279k | { |
241 | 279k | if(s_.k == kind::string) |
242 | 12.0k | { |
243 | 12.0k | sp->deallocate(p_.t, |
244 | 12.0k | sizeof(table) + |
245 | 12.0k | p_.t->capacity + 1, |
246 | 12.0k | alignof(table)); |
247 | 12.0k | } |
248 | 267k | else if(s_.k != key_string_) |
249 | 55.5k | { |
250 | | // do nothing |
251 | 55.5k | } |
252 | 211k | else |
253 | 211k | { |
254 | 211k | BOOST_ASSERT( |
255 | 211k | 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 | 211k | sp->deallocate(k_.s, k_.n + 1); |
261 | 211k | } |
262 | 279k | } |
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 | | term(std::size_t n) noexcept |
315 | 70.7k | { |
316 | 70.7k | if(s_.k == short_string_) |
317 | 56.9k | { |
318 | 56.9k | s_.buf[sbo_chars_] = |
319 | 56.9k | static_cast<char>( |
320 | 56.9k | sbo_chars_ - n); |
321 | 56.9k | s_.buf[n] = 0; |
322 | 56.9k | } |
323 | 13.8k | else |
324 | 13.8k | { |
325 | 13.8k | p_.t->size = static_cast< |
326 | 13.8k | std::uint32_t>(n); |
327 | 13.8k | data()[n] = 0; |
328 | 13.8k | } |
329 | 70.7k | } |
330 | | |
331 | | char* |
332 | | data() noexcept |
333 | 139k | { |
334 | 139k | if(s_.k == short_string_) |
335 | 81.2k | return s_.buf; |
336 | 58.3k | return reinterpret_cast< |
337 | 58.3k | char*>(p_.t + 1); |
338 | 139k | } |
339 | | |
340 | | char const* |
341 | | data() const noexcept |
342 | 28.8k | { |
343 | 28.8k | if(s_.k == short_string_) |
344 | 18.3k | return s_.buf; |
345 | 10.5k | return reinterpret_cast< |
346 | 10.5k | char const*>(p_.t + 1); |
347 | 28.8k | } |
348 | | |
349 | | char* |
350 | | end() noexcept |
351 | 0 | { |
352 | 0 | return data() + size(); |
353 | 0 | } |
354 | | |
355 | | char const* |
356 | | end() const noexcept |
357 | 0 | { |
358 | 0 | return data() + size(); |
359 | 0 | } |
360 | | }; |
361 | | |
362 | | template<class T> |
363 | | string_view |
364 | | to_string_view(T const& t) noexcept |
365 | | { |
366 | | 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 |