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