Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:38:58

0001 //
0002 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
0003 // Copyright (c) 2020 Krystian Stasiowski (sdkrystian@gmail.com)
0004 //
0005 // Distributed under the Boost Software License, Version 1.0. (See accompanying
0006 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
0007 //
0008 // Official repository: https://github.com/boostorg/json
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 // construct a key, unchecked
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; // null term
0090     std::memcpy(&k_.s[0],
0091         s.data(), s.size());
0092 }
0093 
0094 // construct a key, unchecked
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; // null term
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     // growth factor 2
0129     if( capacity >
0130         max_size() - capacity)
0131         return static_cast<
0132             std::uint32_t>(max_size()); // overflow
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     // if we are shrinking in size or we have enough
0314     // capacity, dont reallocate
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         // there is nothing to replace; return
0319         if (inside && s == curr_data + pos && n1 == n2)
0320             return;
0321         if (!inside || (inside && ((s - curr_data) + n2 <= pos)))
0322         {
0323             // source outside
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             // source inside
0330             const std::size_t offset = s - curr_data;
0331             if (n2 >= n1)
0332             {
0333                 // grow/unchanged
0334                 const std::size_t diff = offset <= pos + n1 ? (std::min)((pos + n1) - offset, n2) : 0;
0335                 // shift all right of splice point by n2 - n1 to the right
0336                 std::memmove(&curr_data[pos + n2], &curr_data[pos + n1], curr_size - pos - n1 + 1);
0337                 // copy all before splice point
0338                 std::memmove(&curr_data[pos], &curr_data[offset], diff);
0339                 // copy all after splice point
0340                 std::memmove(&curr_data[pos + diff], &curr_data[(offset - n1) + n2 + diff], n2 - diff);
0341             }
0342             else
0343             {
0344                 // shrink
0345                 // copy all elements into place
0346                 std::memmove(&curr_data[pos], &curr_data[offset], n2);
0347                 // shift all elements after splice point left
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         // would exceed capacity, reallocate
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 // unlike the replace overload, this function does
0382 // not move any characters
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     // if the size doesn't change, we don't need to
0401     // do anything
0402     if (!delta)
0403       return curr_data + pos;
0404     // if we are shrinking in size or we have enough
0405     // capacity, dont reallocate
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     // would exceed capacity, reallocate
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         // eat the exception
0479     }
0480 #endif
0481 }
0482 
0483 } // detail
0484 } // namespace json
0485 } // namespace boost
0486 
0487 #endif