string_impl.hpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  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. #ifndef BOOST_JSON_DETAIL_STRING_IMPL_HPP
  11. #define BOOST_JSON_DETAIL_STRING_IMPL_HPP
  12. #include <boost/core/detail/static_assert.hpp>
  13. #include <boost/json/detail/config.hpp>
  14. #include <boost/json/kind.hpp>
  15. #include <boost/json/storage_ptr.hpp>
  16. #include <boost/json/detail/value.hpp>
  17. #include <algorithm>
  18. #include <iterator>
  19. namespace boost {
  20. namespace json {
  21. class value;
  22. class string;
  23. namespace detail {
  24. class string_impl
  25. {
  26. struct table
  27. {
  28. std::uint32_t size;
  29. std::uint32_t capacity;
  30. };
  31. #if BOOST_JSON_ARCH == 64
  32. static constexpr std::size_t sbo_chars_ = 14;
  33. #elif BOOST_JSON_ARCH == 32
  34. static constexpr std::size_t sbo_chars_ = 10;
  35. #else
  36. # error Unknown architecture
  37. #endif
  38. static
  39. constexpr
  40. kind
  41. short_string_ =
  42. static_cast<kind>(
  43. ((unsigned char)
  44. kind::string) | 0x80);
  45. static
  46. constexpr
  47. kind
  48. key_string_ =
  49. static_cast<kind>(
  50. ((unsigned char)
  51. kind::string) | 0x40);
  52. struct sbo
  53. {
  54. kind k; // must come first
  55. char buf[sbo_chars_ + 1];
  56. };
  57. struct pointer
  58. {
  59. kind k; // must come first
  60. table* t;
  61. };
  62. struct key
  63. {
  64. kind k; // must come first
  65. std::uint32_t n;
  66. char* s;
  67. };
  68. union
  69. {
  70. sbo s_;
  71. pointer p_;
  72. key k_;
  73. };
  74. #if BOOST_JSON_ARCH == 64
  75. BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 16 );
  76. BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 16 );
  77. BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 16 );
  78. #elif BOOST_JSON_ARCH == 32
  79. BOOST_CORE_STATIC_ASSERT( sizeof(sbo) <= 24 );
  80. BOOST_CORE_STATIC_ASSERT( sizeof(pointer) <= 24 );
  81. BOOST_CORE_STATIC_ASSERT( sizeof(key) <= 24 );
  82. #endif
  83. public:
  84. static
  85. constexpr
  86. std::size_t
  87. max_size() noexcept
  88. {
  89. // max_size depends on the address model
  90. using min = std::integral_constant<std::size_t,
  91. std::size_t(-1) - sizeof(table)>;
  92. return min::value < BOOST_JSON_MAX_STRING_SIZE ?
  93. min::value : BOOST_JSON_MAX_STRING_SIZE;
  94. }
  95. BOOST_JSON_DECL
  96. string_impl() noexcept;
  97. BOOST_JSON_DECL
  98. string_impl(
  99. std::size_t new_size,
  100. storage_ptr const& sp);
  101. BOOST_JSON_DECL
  102. string_impl(
  103. key_t,
  104. string_view s,
  105. storage_ptr const& sp);
  106. BOOST_JSON_DECL
  107. string_impl(
  108. key_t,
  109. string_view s1,
  110. string_view s2,
  111. storage_ptr const& sp);
  112. BOOST_JSON_DECL
  113. string_impl(
  114. char** dest,
  115. std::size_t len,
  116. storage_ptr const& sp);
  117. template<class InputIt>
  118. string_impl(
  119. InputIt first,
  120. InputIt last,
  121. storage_ptr const& sp,
  122. std::random_access_iterator_tag)
  123. : string_impl(last - first, sp)
  124. {
  125. char* out = data();
  126. #if defined(_MSC_VER) && _MSC_VER <= 1900
  127. while( first != last )
  128. *out++ = *first++;
  129. #else
  130. std::copy(first, last, out);
  131. #endif
  132. }
  133. template<class InputIt>
  134. string_impl(
  135. InputIt first,
  136. InputIt last,
  137. storage_ptr const& sp,
  138. std::input_iterator_tag)
  139. : string_impl(0, sp)
  140. {
  141. struct undo
  142. {
  143. string_impl* s;
  144. storage_ptr const& sp;
  145. ~undo()
  146. {
  147. if(s)
  148. s->destroy(sp);
  149. }
  150. };
  151. undo u{this, sp};
  152. auto dest = data();
  153. while(first != last)
  154. {
  155. if(size() < capacity())
  156. size(size() + 1);
  157. else
  158. dest = append(1, sp);
  159. *dest++ = *first++;
  160. }
  161. term(size());
  162. u.s = nullptr;
  163. }
  164. std::size_t
  165. size() const noexcept
  166. {
  167. return s_.k == kind::string ?
  168. p_.t->size :
  169. sbo_chars_ -
  170. s_.buf[sbo_chars_];
  171. }
  172. std::size_t
  173. capacity() const noexcept
  174. {
  175. return s_.k == kind::string ?
  176. p_.t->capacity :
  177. sbo_chars_;
  178. }
  179. void
  180. size(std::size_t n)
  181. {
  182. if(s_.k == kind::string)
  183. p_.t->size = static_cast<
  184. std::uint32_t>(n);
  185. else
  186. s_.buf[sbo_chars_] =
  187. static_cast<char>(
  188. sbo_chars_ - n);
  189. }
  190. BOOST_JSON_DECL
  191. static
  192. std::uint32_t
  193. growth(
  194. std::size_t new_size,
  195. std::size_t capacity);
  196. char const*
  197. release_key(
  198. std::size_t& n) noexcept
  199. {
  200. BOOST_ASSERT(
  201. k_.k == key_string_);
  202. n = k_.n;
  203. auto const s = k_.s;
  204. // prevent deallocate
  205. k_.k = short_string_;
  206. return s;
  207. }
  208. void
  209. destroy(
  210. storage_ptr const& sp) noexcept
  211. {
  212. if(s_.k == kind::string)
  213. {
  214. sp->deallocate(p_.t,
  215. sizeof(table) +
  216. p_.t->capacity + 1,
  217. alignof(table));
  218. }
  219. else if(s_.k != key_string_)
  220. {
  221. // do nothing
  222. }
  223. else
  224. {
  225. BOOST_ASSERT(
  226. s_.k == key_string_);
  227. // VFALCO unfortunately the key string
  228. // kind increases the cost of the destructor.
  229. // This function should be skipped when using
  230. // monotonic_resource.
  231. sp->deallocate(k_.s, k_.n + 1);
  232. }
  233. }
  234. BOOST_JSON_DECL
  235. char*
  236. assign(
  237. std::size_t new_size,
  238. storage_ptr const& sp);
  239. BOOST_JSON_DECL
  240. char*
  241. append(
  242. std::size_t n,
  243. storage_ptr const& sp);
  244. BOOST_JSON_DECL
  245. void
  246. insert(
  247. std::size_t pos,
  248. const char* s,
  249. std::size_t n,
  250. storage_ptr const& sp);
  251. BOOST_JSON_DECL
  252. char*
  253. insert_unchecked(
  254. std::size_t pos,
  255. std::size_t n,
  256. storage_ptr const& sp);
  257. BOOST_JSON_DECL
  258. void
  259. replace(
  260. std::size_t pos,
  261. std::size_t n1,
  262. const char* s,
  263. std::size_t n2,
  264. storage_ptr const& sp);
  265. BOOST_JSON_DECL
  266. char*
  267. replace_unchecked(
  268. std::size_t pos,
  269. std::size_t n1,
  270. std::size_t n2,
  271. storage_ptr const& sp);
  272. BOOST_JSON_DECL
  273. void
  274. shrink_to_fit(
  275. storage_ptr const& sp) noexcept;
  276. void
  277. term(std::size_t n) noexcept
  278. {
  279. if(s_.k == short_string_)
  280. {
  281. s_.buf[sbo_chars_] =
  282. static_cast<char>(
  283. sbo_chars_ - n);
  284. s_.buf[n] = 0;
  285. }
  286. else
  287. {
  288. p_.t->size = static_cast<
  289. std::uint32_t>(n);
  290. data()[n] = 0;
  291. }
  292. }
  293. char*
  294. data() noexcept
  295. {
  296. if(s_.k == short_string_)
  297. return s_.buf;
  298. return reinterpret_cast<
  299. char*>(p_.t + 1);
  300. }
  301. char const*
  302. data() const noexcept
  303. {
  304. if(s_.k == short_string_)
  305. return s_.buf;
  306. return reinterpret_cast<
  307. char const*>(p_.t + 1);
  308. }
  309. char*
  310. end() noexcept
  311. {
  312. return data() + size();
  313. }
  314. char const*
  315. end() const noexcept
  316. {
  317. return data() + size();
  318. }
  319. };
  320. template<class T>
  321. string_view
  322. to_string_view(T const& t) noexcept
  323. {
  324. return string_view(t);
  325. }
  326. template<class T, class U>
  327. using string_and_stringlike = std::integral_constant<bool,
  328. std::is_same<T, string>::value &&
  329. std::is_convertible<U const&, string_view>::value>;
  330. template<class T, class U>
  331. using string_comp_op_requirement
  332. = typename std::enable_if<
  333. string_and_stringlike<T, U>::value ||
  334. string_and_stringlike<U, T>::value,
  335. bool>::type;
  336. } // detail
  337. } // namespace json
  338. } // namespace boost
  339. #endif