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