File indexing completed on 2025-01-18 09:39:00
0001
0002
0003
0004
0005
0006
0007
0008
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;
0064 char buf[sbo_chars_ + 1];
0065 };
0066
0067 struct pointer
0068 {
0069 kind k;
0070 table* t;
0071 };
0072
0073 struct key
0074 {
0075 kind k;
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
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
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
0251 }
0252 else
0253 {
0254 BOOST_ASSERT(
0255 s_.k == key_string_);
0256
0257
0258
0259
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 }
0382 }
0383 }
0384
0385 #endif