string_impl.hpp 7.1 KB

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