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 : inline
31 : bool
32 HIT 84 : ptr_in_range(char const* first, char const* last, char const* ptr) noexcept
33 : {
34 119 : return std::less<char const*>()(ptr, last) &&
35 119 : 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 154205 : 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 154205 : 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 8 : string_impl(
149 : InputIt first,
150 : InputIt last,
151 : storage_ptr const& sp,
152 : std::random_access_iterator_tag)
153 8 : : string_impl(last - first, sp)
154 : {
155 7 : char* out = data();
156 : #if defined(_MSC_VER) && _MSC_VER <= 1900
157 : while( first != last )
158 : *out++ = *first++;
159 : #else
160 7 : std::copy(first, last, out);
161 : #endif
162 7 : }
163 :
164 : template<class InputIt>
165 44 : string_impl(
166 : InputIt first,
167 : InputIt last,
168 : storage_ptr const& sp,
169 : std::input_iterator_tag)
170 44 : : string_impl(0, sp)
171 : {
172 : struct undo
173 : {
174 : string_impl* s;
175 : storage_ptr const& sp;
176 :
177 44 : ~undo()
178 : {
179 44 : if(s)
180 3 : s->destroy(sp);
181 44 : }
182 : };
183 :
184 44 : undo u{this, sp};
185 44 : auto dest = data();
186 463 : while(first != last)
187 : {
188 422 : if(size() < capacity())
189 405 : size(size() + 1);
190 : else
191 17 : dest = append(1, sp);
192 419 : *dest++ = *first++;
193 : }
194 41 : term(size());
195 41 : u.s = nullptr;
196 44 : }
197 :
198 : std::size_t
199 100048 : size() const noexcept
200 : {
201 100048 : return s_.k == kind::string ?
202 65149 : p_.t->size :
203 : sbo_chars_ -
204 100048 : s_.buf[sbo_chars_];
205 : }
206 :
207 : std::size_t
208 92375 : capacity() const noexcept
209 : {
210 92375 : return s_.k == kind::string ?
211 12037 : p_.t->capacity :
212 92375 : sbo_chars_;
213 : }
214 :
215 : void
216 10156 : size(std::size_t n)
217 : {
218 10156 : if(s_.k == kind::string)
219 9789 : p_.t->size = static_cast<
220 : std::uint32_t>(n);
221 : else
222 367 : s_.buf[sbo_chars_] =
223 : static_cast<char>(
224 367 : sbo_chars_ - n);
225 10156 : }
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 38150 : release_key(
236 : std::size_t& n) noexcept
237 : {
238 38150 : BOOST_ASSERT(
239 : k_.k == key_string_);
240 38150 : n = k_.n;
241 38150 : auto const s = k_.s;
242 : // prevent deallocate
243 38150 : k_.k = short_string_;
244 38150 : return s;
245 : }
246 :
247 : void
248 57730 : destroy(
249 : storage_ptr const& sp) noexcept
250 : {
251 57730 : if(s_.k == kind::string)
252 : {
253 26706 : sp->deallocate(p_.t,
254 : sizeof(table) +
255 26706 : p_.t->capacity + 1,
256 : alignof(table));
257 : }
258 31024 : else if(s_.k != key_string_)
259 : {
260 : // do nothing
261 : }
262 : else
263 : {
264 146 : 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 146 : sp->deallocate(k_.s, k_.n + 1);
271 : }
272 57730 : }
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 33730 : term(std::size_t n) noexcept
325 : {
326 33730 : if(s_.k == short_string_)
327 : {
328 5145 : s_.buf[sbo_chars_] =
329 : static_cast<char>(
330 5145 : sbo_chars_ - n);
331 5145 : s_.buf[n] = 0;
332 : }
333 : else
334 : {
335 28585 : p_.t->size = static_cast<
336 : std::uint32_t>(n);
337 28585 : data()[n] = 0;
338 : }
339 33730 : }
340 :
341 : char*
342 117773 : data() noexcept
343 : {
344 117773 : if(s_.k == short_string_)
345 15444 : return s_.buf;
346 : return reinterpret_cast<
347 102329 : char*>(p_.t + 1);
348 : }
349 :
350 : char const*
351 44033 : data() const noexcept
352 : {
353 44033 : if(s_.k == short_string_)
354 4553 : return s_.buf;
355 : return reinterpret_cast<
356 39480 : char const*>(p_.t + 1);
357 : }
358 :
359 : char*
360 315 : end() noexcept
361 : {
362 315 : return data() + size();
363 : }
364 :
365 : char const*
366 10 : end() const noexcept
367 : {
368 10 : return data() + size();
369 : }
370 : };
371 :
372 : template<class T>
373 : string_view
374 2488 : to_string_view(T const& t) noexcept
375 : {
376 2488 : 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
|