string_impl.hpp 7.8 KB

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