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 18871 : ptr_in_range(char const* first, char const* last, char const* ptr) noexcept
33 : {
34 20427 : return std::less<char const*>()(ptr, last) &&
35 20427 : 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 154151 : 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 154151 : 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 38 : string_impl(
166 : InputIt first,
167 : InputIt last,
168 : storage_ptr const& sp,
169 : std::input_iterator_tag)
170 38 : : string_impl(0, sp)
171 : {
172 : struct undo
173 : {
174 : string_impl* s;
175 : storage_ptr const& sp;
176 :
177 38 : ~undo()
178 : {
179 38 : if(s)
180 3 : s->destroy(sp);
181 38 : }
182 : };
183 :
184 38 : undo u{this, sp};
185 38 : auto dest = data();
186 313 : while(first != last)
187 : {
188 278 : if(size() < capacity())
189 267 : size(size() + 1);
190 : else
191 11 : dest = append(1, sp);
192 275 : *dest++ = *first++;
193 : }
194 35 : term(size());
195 35 : u.s = nullptr;
196 38 : }
197 :
198 : std::size_t
199 118309 : size() const noexcept
200 : {
201 118309 : return s_.k == kind::string ?
202 64866 : p_.t->size :
203 : sbo_chars_ -
204 118309 : s_.buf[sbo_chars_];
205 : }
206 :
207 : std::size_t
208 92559 : capacity() const noexcept
209 : {
210 92559 : return s_.k == kind::string ?
211 11913 : p_.t->capacity :
212 92559 : sbo_chars_;
213 : }
214 :
215 : void
216 10018 : size(std::size_t n)
217 : {
218 10018 : if(s_.k == kind::string)
219 9735 : p_.t->size = static_cast<
220 : std::uint32_t>(n);
221 : else
222 283 : s_.buf[sbo_chars_] =
223 : static_cast<char>(
224 283 : sbo_chars_ - n);
225 10018 : }
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 57728 : destroy(
249 : storage_ptr const& sp) noexcept
250 : {
251 57728 : if(s_.k == kind::string)
252 : {
253 26702 : sp->deallocate(p_.t,
254 : sizeof(table) +
255 26702 : p_.t->capacity + 1,
256 : alignof(table));
257 : }
258 31026 : else if(s_.k != key_string_)
259 : {
260 : // do nothing
261 : }
262 : else
263 : {
264 148 : 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 148 : sp->deallocate(k_.s, k_.n + 1,
271 : alignof(char));
272 : }
273 57728 : }
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 34093 : term(std::size_t n) noexcept
326 : {
327 34093 : if(s_.k == short_string_)
328 : {
329 5545 : s_.buf[sbo_chars_] =
330 : static_cast<char>(
331 5545 : sbo_chars_ - n);
332 5545 : s_.buf[n] = 0;
333 : }
334 : else
335 : {
336 28548 : p_.t->size = static_cast<
337 : std::uint32_t>(n);
338 28548 : data()[n] = 0;
339 : }
340 34093 : }
341 :
342 : char*
343 136862 : data() noexcept
344 : {
345 136862 : if(s_.k == short_string_)
346 34598 : return s_.buf;
347 : return reinterpret_cast<
348 102264 : char*>(p_.t + 1);
349 : }
350 :
351 : char const*
352 44039 : data() const noexcept
353 : {
354 44039 : if(s_.k == short_string_)
355 4554 : return s_.buf;
356 : return reinterpret_cast<
357 39485 : char const*>(p_.t + 1);
358 : }
359 :
360 : char*
361 272 : end() noexcept
362 : {
363 272 : return data() + size();
364 : }
365 :
366 : char const*
367 10 : end() const noexcept
368 : {
369 10 : return data() + size();
370 : }
371 : };
372 :
373 : template<class T>
374 : string_view
375 2490 : to_string_view(T const& t) noexcept
376 : {
377 2490 : 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
|