File indexing completed on 2025-01-18 09:38:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
0012 #define BOOST_JSON_DETAIL_IMPL_STRING_IMPL_IPP
0013
0014 #include <boost/json/detail/string_impl.hpp>
0015 #include <boost/json/detail/except.hpp>
0016 #include <cstring>
0017 #include <functional>
0018
0019 namespace boost {
0020 namespace json {
0021 namespace detail {
0022
0023 inline
0024 bool
0025 ptr_in_range(
0026 const char* first,
0027 const char* last,
0028 const char* ptr) noexcept
0029 {
0030 return std::less<const char*>()(ptr, last) &&
0031 std::greater_equal<const char*>()(ptr, first);
0032 }
0033
0034 string_impl::
0035 string_impl() noexcept
0036 {
0037 s_.k = short_string_;
0038 s_.buf[sbo_chars_] =
0039 static_cast<char>(
0040 sbo_chars_);
0041 s_.buf[0] = 0;
0042 }
0043
0044 string_impl::
0045 string_impl(
0046 std::size_t size,
0047 storage_ptr const& sp)
0048 {
0049 if(size <= sbo_chars_)
0050 {
0051 s_.k = short_string_;
0052 s_.buf[sbo_chars_] =
0053 static_cast<char>(
0054 sbo_chars_ - size);
0055 s_.buf[size] = 0;
0056 }
0057 else
0058 {
0059 s_.k = kind::string;
0060 auto const n = growth(
0061 size, sbo_chars_ + 1);
0062 p_.t = ::new(sp->allocate(
0063 sizeof(table) +
0064 n + 1,
0065 alignof(table))) table{
0066 static_cast<
0067 std::uint32_t>(size),
0068 static_cast<
0069 std::uint32_t>(n)};
0070 data()[n] = 0;
0071 }
0072 }
0073
0074
0075 string_impl::
0076 string_impl(
0077 key_t,
0078 string_view s,
0079 storage_ptr const& sp)
0080 {
0081 BOOST_ASSERT(
0082 s.size() <= max_size());
0083 k_.k = key_string_;
0084 k_.n = static_cast<
0085 std::uint32_t>(s.size());
0086 k_.s = reinterpret_cast<char*>(
0087 sp->allocate(s.size() + 1,
0088 alignof(char)));
0089 k_.s[s.size()] = 0;
0090 std::memcpy(&k_.s[0],
0091 s.data(), s.size());
0092 }
0093
0094
0095 string_impl::
0096 string_impl(
0097 key_t,
0098 string_view s1,
0099 string_view s2,
0100 storage_ptr const& sp)
0101 {
0102 auto len = s1.size() + s2.size();
0103 BOOST_ASSERT(len <= max_size());
0104 k_.k = key_string_;
0105 k_.n = static_cast<
0106 std::uint32_t>(len);
0107 k_.s = reinterpret_cast<char*>(
0108 sp->allocate(len + 1,
0109 alignof(char)));
0110 k_.s[len] = 0;
0111 std::memcpy(&k_.s[0],
0112 s1.data(), s1.size());
0113 std::memcpy(&k_.s[s1.size()],
0114 s2.data(), s2.size());
0115 }
0116
0117 std::uint32_t
0118 string_impl::
0119 growth(
0120 std::size_t new_size,
0121 std::size_t capacity)
0122 {
0123 if(new_size > max_size())
0124 {
0125 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0126 detail::throw_system_error( error::string_too_large, &loc );
0127 }
0128
0129 if( capacity >
0130 max_size() - capacity)
0131 return static_cast<
0132 std::uint32_t>(max_size());
0133 return static_cast<std::uint32_t>(
0134 (std::max)(capacity * 2, new_size));
0135 }
0136
0137 char*
0138 string_impl::
0139 assign(
0140 std::size_t new_size,
0141 storage_ptr const& sp)
0142 {
0143 if(new_size > capacity())
0144 {
0145 string_impl tmp(growth(
0146 new_size,
0147 capacity()), sp);
0148 destroy(sp);
0149 *this = tmp;
0150 }
0151 term(new_size);
0152 return data();
0153 }
0154
0155 char*
0156 string_impl::
0157 append(
0158 std::size_t n,
0159 storage_ptr const& sp)
0160 {
0161 if(n > max_size() - size())
0162 {
0163 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0164 detail::throw_system_error( error::string_too_large, &loc );
0165 }
0166 if(n <= capacity() - size())
0167 {
0168 term(size() + n);
0169 return end() - n;
0170 }
0171 string_impl tmp(growth(
0172 size() + n, capacity()), sp);
0173 std::memcpy(
0174 tmp.data(), data(), size());
0175 tmp.term(size() + n);
0176 destroy(sp);
0177 *this = tmp;
0178 return end() - n;
0179 }
0180
0181 void
0182 string_impl::
0183 insert(
0184 std::size_t pos,
0185 const char* s,
0186 std::size_t n,
0187 storage_ptr const& sp)
0188 {
0189 const auto curr_size = size();
0190 if(pos > curr_size)
0191 {
0192 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0193 detail::throw_system_error( error::out_of_range, &loc );
0194 }
0195 const auto curr_data = data();
0196 if(n <= capacity() - curr_size)
0197 {
0198 const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
0199 if (!inside || (inside && ((s - curr_data) + n <= pos)))
0200 {
0201 std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
0202 std::memcpy(&curr_data[pos], s, n);
0203 }
0204 else
0205 {
0206 const std::size_t offset = s - curr_data;
0207 std::memmove(&curr_data[pos + n], &curr_data[pos], curr_size - pos + 1);
0208 if (offset < pos)
0209 {
0210 const std::size_t diff = pos - offset;
0211 std::memcpy(&curr_data[pos], &curr_data[offset], diff);
0212 std::memcpy(&curr_data[pos + diff], &curr_data[pos + n], n - diff);
0213 }
0214 else
0215 {
0216 std::memcpy(&curr_data[pos], &curr_data[offset + n], n);
0217 }
0218 }
0219 size(curr_size + n);
0220 }
0221 else
0222 {
0223 if(n > max_size() - curr_size)
0224 {
0225 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0226 detail::throw_system_error( error::string_too_large, &loc );
0227 }
0228 string_impl tmp(growth(
0229 curr_size + n, capacity()), sp);
0230 tmp.size(curr_size + n);
0231 std::memcpy(
0232 tmp.data(),
0233 curr_data,
0234 pos);
0235 std::memcpy(
0236 tmp.data() + pos + n,
0237 curr_data + pos,
0238 curr_size + 1 - pos);
0239 std::memcpy(
0240 tmp.data() + pos,
0241 s,
0242 n);
0243 destroy(sp);
0244 *this = tmp;
0245 }
0246 }
0247
0248 char*
0249 string_impl::
0250 insert_unchecked(
0251 std::size_t pos,
0252 std::size_t n,
0253 storage_ptr const& sp)
0254 {
0255 const auto curr_size = size();
0256 if(pos > curr_size)
0257 {
0258 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0259 detail::throw_system_error( error::out_of_range, &loc );
0260 }
0261 const auto curr_data = data();
0262 if(n <= capacity() - size())
0263 {
0264 auto const dest =
0265 curr_data + pos;
0266 std::memmove(
0267 dest + n,
0268 dest,
0269 curr_size + 1 - pos);
0270 size(curr_size + n);
0271 return dest;
0272 }
0273 if(n > max_size() - curr_size)
0274 {
0275 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0276 detail::throw_system_error( error::string_too_large, &loc );
0277 }
0278 string_impl tmp(growth(
0279 curr_size + n, capacity()), sp);
0280 tmp.size(curr_size + n);
0281 std::memcpy(
0282 tmp.data(),
0283 curr_data,
0284 pos);
0285 std::memcpy(
0286 tmp.data() + pos + n,
0287 curr_data + pos,
0288 curr_size + 1 - pos);
0289 destroy(sp);
0290 *this = tmp;
0291 return data() + pos;
0292 }
0293
0294 void
0295 string_impl::
0296 replace(
0297 std::size_t pos,
0298 std::size_t n1,
0299 const char* s,
0300 std::size_t n2,
0301 storage_ptr const& sp)
0302 {
0303 const auto curr_size = size();
0304 if (pos > curr_size)
0305 {
0306 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0307 detail::throw_system_error( error::out_of_range, &loc );
0308 }
0309 const auto curr_data = data();
0310 n1 = (std::min)(n1, curr_size - pos);
0311 const auto delta = (std::max)(n1, n2) -
0312 (std::min)(n1, n2);
0313
0314
0315 if (n1 > n2 || delta <= capacity() - curr_size)
0316 {
0317 const bool inside = detail::ptr_in_range(curr_data, curr_data + curr_size, s);
0318
0319 if (inside && s == curr_data + pos && n1 == n2)
0320 return;
0321 if (!inside || (inside && ((s - curr_data) + n2 <= pos)))
0322 {
0323
0324 std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
0325 std::memcpy(&curr_data[pos], s, n2);
0326 }
0327 else
0328 {
0329
0330 const std::size_t offset = s - curr_data;
0331 if (n2 >= n1)
0332 {
0333
0334 const std::size_t diff = offset <= pos + n1 ? (std::min)((pos + n1) - offset, n2) : 0;
0335
0336 std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
0337
0338 std::memmove(&curr_data[pos], &curr_data[offset], diff);
0339
0340 std::memmove(&curr_data[pos + diff], &curr_data[(offset - n1) + n2 + diff], n2 - diff);
0341 }
0342 else
0343 {
0344
0345
0346 std::memmove(&curr_data[pos], &curr_data[offset], n2);
0347
0348 std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
0349 }
0350 }
0351 size((curr_size - n1) + n2);
0352 }
0353 else
0354 {
0355 if (delta > max_size() - curr_size)
0356 {
0357 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0358 detail::throw_system_error( error::string_too_large, &loc );
0359 }
0360
0361 string_impl tmp(growth(
0362 curr_size + delta, capacity()), sp);
0363 tmp.size(curr_size + delta);
0364 std::memcpy(
0365 tmp.data(),
0366 curr_data,
0367 pos);
0368 std::memcpy(
0369 tmp.data() + pos + n2,
0370 curr_data + pos + n1,
0371 curr_size - pos - n1 + 1);
0372 std::memcpy(
0373 tmp.data() + pos,
0374 s,
0375 n2);
0376 destroy(sp);
0377 *this = tmp;
0378 }
0379 }
0380
0381
0382
0383 char*
0384 string_impl::
0385 replace_unchecked(
0386 std::size_t pos,
0387 std::size_t n1,
0388 std::size_t n2,
0389 storage_ptr const& sp)
0390 {
0391 const auto curr_size = size();
0392 if(pos > curr_size)
0393 {
0394 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0395 detail::throw_system_error( error::out_of_range, &loc );
0396 }
0397 const auto curr_data = data();
0398 const auto delta = (std::max)(n1, n2) -
0399 (std::min)(n1, n2);
0400
0401
0402 if (!delta)
0403 return curr_data + pos;
0404
0405
0406 if(n1 > n2 || delta <= capacity() - curr_size)
0407 {
0408 auto const replace_pos = curr_data + pos;
0409 std::memmove(
0410 replace_pos + n2,
0411 replace_pos + n1,
0412 curr_size - pos - n1 + 1);
0413 size((curr_size - n1) + n2);
0414 return replace_pos;
0415 }
0416 if(delta > max_size() - curr_size)
0417 {
0418 BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
0419 detail::throw_system_error( error::string_too_large, &loc );
0420 }
0421
0422 string_impl tmp(growth(
0423 curr_size + delta, capacity()), sp);
0424 tmp.size(curr_size + delta);
0425 std::memcpy(
0426 tmp.data(),
0427 curr_data,
0428 pos);
0429 std::memcpy(
0430 tmp.data() + pos + n2,
0431 curr_data + pos + n1,
0432 curr_size - pos - n1 + 1);
0433 destroy(sp);
0434 *this = tmp;
0435 return data() + pos;
0436 }
0437
0438 void
0439 string_impl::
0440 shrink_to_fit(
0441 storage_ptr const& sp) noexcept
0442 {
0443 if(s_.k == short_string_)
0444 return;
0445 auto const t = p_.t;
0446 if(t->size <= sbo_chars_)
0447 {
0448 s_.k = short_string_;
0449 std::memcpy(
0450 s_.buf, data(), t->size);
0451 s_.buf[sbo_chars_] =
0452 static_cast<char>(
0453 sbo_chars_ - t->size);
0454 s_.buf[t->size] = 0;
0455 sp->deallocate(t,
0456 sizeof(table) +
0457 t->capacity + 1,
0458 alignof(table));
0459 return;
0460 }
0461 if(t->size >= t->capacity)
0462 return;
0463 #ifndef BOOST_NO_EXCEPTIONS
0464 try
0465 {
0466 #endif
0467 string_impl tmp(t->size, sp);
0468 std::memcpy(
0469 tmp.data(),
0470 data(),
0471 size());
0472 destroy(sp);
0473 *this = tmp;
0474 #ifndef BOOST_NO_EXCEPTIONS
0475 }
0476 catch(std::exception const&)
0477 {
0478
0479 }
0480 #endif
0481 }
0482
0483 }
0484 }
0485 }
0486
0487 #endif