Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:00

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_STRING_IMPL_HPP
0012 #define BOOST_JSON_DETAIL_STRING_IMPL_HPP
0013 
0014 #include <boost/json/detail/config.hpp>
0015 #include <boost/json/kind.hpp>
0016 #include <boost/json/storage_ptr.hpp>
0017 #include <boost/json/detail/value.hpp>
0018 #include <algorithm>
0019 #include <iterator>
0020 
0021 namespace boost {
0022 namespace json {
0023 
0024 class value;
0025 class string;
0026 
0027 namespace detail {
0028 
0029 class string_impl
0030 {
0031     struct table
0032     {
0033         std::uint32_t size;
0034         std::uint32_t capacity;
0035     };
0036 
0037 #if BOOST_JSON_ARCH == 64
0038     static constexpr std::size_t sbo_chars_ = 14;
0039 #elif BOOST_JSON_ARCH == 32
0040     static constexpr std::size_t sbo_chars_ = 10;
0041 #else
0042 # error Unknown architecture
0043 #endif
0044 
0045     static
0046     constexpr
0047     kind
0048     short_string_ =
0049         static_cast<kind>(
0050             ((unsigned char)
0051             kind::string) | 0x80);
0052 
0053     static
0054     constexpr
0055     kind
0056     key_string_ =
0057         static_cast<kind>(
0058             ((unsigned char)
0059             kind::string) | 0x40);
0060 
0061     struct sbo
0062     {
0063         kind k; // must come first
0064         char buf[sbo_chars_ + 1];
0065     };
0066 
0067     struct pointer
0068     {
0069         kind k; // must come first
0070         table* t;
0071     };
0072 
0073     struct key
0074     {
0075         kind k; // must come first
0076         std::uint32_t n;
0077         char* s;
0078     };
0079 
0080     union
0081     {
0082         sbo s_;
0083         pointer p_;
0084         key k_;
0085     };
0086 
0087 #if BOOST_JSON_ARCH == 64
0088     BOOST_STATIC_ASSERT(sizeof(sbo) <= 16);
0089     BOOST_STATIC_ASSERT(sizeof(pointer) <= 16);
0090     BOOST_STATIC_ASSERT(sizeof(key) <= 16);
0091 #elif BOOST_JSON_ARCH == 32
0092     BOOST_STATIC_ASSERT(sizeof(sbo) <= 24);
0093     BOOST_STATIC_ASSERT(sizeof(pointer) <= 24);
0094     BOOST_STATIC_ASSERT(sizeof(key) <= 24);
0095 #endif
0096 
0097 public:
0098     static
0099     constexpr
0100     std::size_t
0101     max_size() noexcept
0102     {
0103         // max_size depends on the address model
0104         using min = std::integral_constant<std::size_t,
0105             std::size_t(-1) - sizeof(table)>;
0106         return min::value < BOOST_JSON_MAX_STRING_SIZE ?
0107             min::value : BOOST_JSON_MAX_STRING_SIZE;
0108     }
0109 
0110     BOOST_JSON_DECL
0111     string_impl() noexcept;
0112 
0113     BOOST_JSON_DECL
0114     string_impl(
0115         std::size_t new_size,
0116         storage_ptr const& sp);
0117 
0118     BOOST_JSON_DECL
0119     string_impl(
0120         key_t,
0121         string_view s,
0122         storage_ptr const& sp);
0123 
0124     BOOST_JSON_DECL
0125     string_impl(
0126         key_t,
0127         string_view s1,
0128         string_view s2,
0129         storage_ptr const& sp);
0130 
0131     BOOST_JSON_DECL
0132     string_impl(
0133         char** dest,
0134         std::size_t len,
0135         storage_ptr const& sp);
0136 
0137     template<class InputIt>
0138     string_impl(
0139         InputIt first,
0140         InputIt last,
0141         storage_ptr const& sp,
0142         std::random_access_iterator_tag)
0143         : string_impl(last - first, sp)
0144     {
0145         char* out = data();
0146 #if defined(_MSC_VER) && _MSC_VER <= 1900
0147         while( first != last )
0148             *out++ = *first++;
0149 #else
0150         std::copy(first, last, out);
0151 #endif
0152     }
0153 
0154     template<class InputIt>
0155     string_impl(
0156         InputIt first,
0157         InputIt last,
0158         storage_ptr const& sp,
0159         std::input_iterator_tag)
0160         : string_impl(0, sp)
0161     {
0162         struct undo
0163         {
0164             string_impl* s;
0165             storage_ptr const& sp;
0166 
0167             ~undo()
0168             {
0169                 if(s)
0170                     s->destroy(sp);
0171             }
0172         };
0173 
0174         undo u{this, sp};
0175         auto dest = data();
0176         while(first != last)
0177         {
0178             if(size() < capacity())
0179                 size(size() + 1);
0180             else
0181                 dest = append(1, sp);
0182             *dest++ = *first++;
0183         }
0184         term(size());
0185         u.s = nullptr;
0186     }
0187 
0188     std::size_t
0189     size() const noexcept
0190     {
0191         return s_.k == kind::string ?
0192             p_.t->size :
0193             sbo_chars_ -
0194                 s_.buf[sbo_chars_];
0195     }
0196 
0197     std::size_t
0198     capacity() const noexcept
0199     {
0200         return s_.k == kind::string ?
0201             p_.t->capacity :
0202             sbo_chars_;
0203     }
0204 
0205     void
0206     size(std::size_t n)
0207     {
0208         if(s_.k == kind::string)
0209             p_.t->size = static_cast<
0210                 std::uint32_t>(n);
0211         else
0212             s_.buf[sbo_chars_] =
0213                 static_cast<char>(
0214                     sbo_chars_ - n);
0215     }
0216 
0217     BOOST_JSON_DECL
0218     static
0219     std::uint32_t
0220     growth(
0221         std::size_t new_size,
0222         std::size_t capacity);
0223 
0224     char const*
0225     release_key(
0226         std::size_t& n) noexcept
0227     {
0228         BOOST_ASSERT(
0229             k_.k == key_string_);
0230         n = k_.n;
0231         auto const s = k_.s;
0232         // prevent deallocate
0233         k_.k = short_string_;
0234         return s;
0235     }
0236 
0237     void
0238     destroy(
0239         storage_ptr const& sp) noexcept
0240     {
0241         if(s_.k == kind::string)
0242         {
0243             sp->deallocate(p_.t,
0244                 sizeof(table) +
0245                     p_.t->capacity + 1,
0246                 alignof(table));
0247         }
0248         else if(s_.k != key_string_)
0249         {
0250             // do nothing
0251         }
0252         else
0253         {
0254             BOOST_ASSERT(
0255                 s_.k == key_string_);
0256             // VFALCO unfortunately the key string
0257             // kind increases the cost of the destructor.
0258             // This function should be skipped when using
0259             // monotonic_resource.
0260             sp->deallocate(k_.s, k_.n + 1);
0261         }
0262     }
0263 
0264     BOOST_JSON_DECL
0265     char*
0266     assign(
0267         std::size_t new_size,
0268         storage_ptr const& sp);
0269 
0270     BOOST_JSON_DECL
0271     char*
0272     append(
0273         std::size_t n,
0274         storage_ptr const& sp);
0275 
0276     BOOST_JSON_DECL
0277     void
0278     insert(
0279         std::size_t pos,
0280         const char* s,
0281         std::size_t n,
0282         storage_ptr const& sp);
0283 
0284     BOOST_JSON_DECL
0285     char*
0286     insert_unchecked(
0287         std::size_t pos,
0288         std::size_t n,
0289         storage_ptr const& sp);
0290 
0291     BOOST_JSON_DECL
0292     void
0293     replace(
0294         std::size_t pos,
0295         std::size_t n1,
0296         const char* s,
0297         std::size_t n2,
0298         storage_ptr const& sp);
0299 
0300     BOOST_JSON_DECL
0301     char*
0302     replace_unchecked(
0303         std::size_t pos,
0304         std::size_t n1,
0305         std::size_t n2,
0306         storage_ptr const& sp);
0307 
0308     BOOST_JSON_DECL
0309     void
0310     shrink_to_fit(
0311         storage_ptr const& sp) noexcept;
0312 
0313     void
0314     term(std::size_t n) noexcept
0315     {
0316         if(s_.k == short_string_)
0317         {
0318             s_.buf[sbo_chars_] =
0319                 static_cast<char>(
0320                     sbo_chars_ - n);
0321             s_.buf[n] = 0;
0322         }
0323         else
0324         {
0325             p_.t->size = static_cast<
0326                 std::uint32_t>(n);
0327             data()[n] = 0;
0328         }
0329     }
0330 
0331     char*
0332     data() noexcept
0333     {
0334         if(s_.k == short_string_)
0335             return s_.buf;
0336         return reinterpret_cast<
0337             char*>(p_.t + 1);
0338     }
0339 
0340     char const*
0341     data() const noexcept
0342     {
0343         if(s_.k == short_string_)
0344             return s_.buf;
0345         return reinterpret_cast<
0346             char const*>(p_.t + 1);
0347     }
0348 
0349     char*
0350     end() noexcept
0351     {
0352         return data() + size();
0353     }
0354 
0355     char const*
0356     end() const noexcept
0357     {
0358         return data() + size();
0359     }
0360 };
0361 
0362 template<class T>
0363 string_view
0364 to_string_view(T const& t) noexcept
0365 {
0366     return string_view(t);
0367 }
0368 
0369 template<class T, class U>
0370 using string_and_stringlike = std::integral_constant<bool,
0371     std::is_same<T, string>::value &&
0372     std::is_convertible<U const&, string_view>::value>;
0373 
0374 template<class T, class U>
0375 using string_comp_op_requirement
0376     = typename std::enable_if<
0377         string_and_stringlike<T, U>::value ||
0378         string_and_stringlike<U, T>::value,
0379         bool>::type;
0380 
0381 } // detail
0382 } // namespace json
0383 } // namespace boost
0384 
0385 #endif