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