value_stack.ipp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. //
  2. // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
  3. //
  4. // Distributed under the Boost Software License, Version 1.0. (See accompanying
  5. // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // Official repository: https://github.com/boostorg/json
  8. //
  9. #ifndef BOOST_JSON_IMPL_VALUE_STACK_IPP
  10. #define BOOST_JSON_IMPL_VALUE_STACK_IPP
  11. #include <boost/json/value_stack.hpp>
  12. #include <cstring>
  13. #include <stdexcept>
  14. #include <utility>
  15. BOOST_JSON_NS_BEGIN
  16. //--------------------------------------
  17. value_stack::
  18. stack::
  19. ~stack()
  20. {
  21. clear();
  22. if( begin_ != temp_ &&
  23. begin_ != nullptr)
  24. sp_->deallocate(
  25. begin_,
  26. (end_ - begin_) *
  27. sizeof(value));
  28. }
  29. value_stack::
  30. stack::
  31. stack(
  32. storage_ptr sp,
  33. void* temp,
  34. std::size_t size) noexcept
  35. : sp_(std::move(sp))
  36. , temp_(temp)
  37. {
  38. if(size >= min_size_ *
  39. sizeof(value))
  40. {
  41. begin_ = reinterpret_cast<
  42. value*>(temp);
  43. top_ = begin_;
  44. end_ = begin_ +
  45. size / sizeof(value);
  46. }
  47. else
  48. {
  49. begin_ = nullptr;
  50. top_ = nullptr;
  51. end_ = nullptr;
  52. }
  53. }
  54. void
  55. value_stack::
  56. stack::
  57. run_dtors(bool b) noexcept
  58. {
  59. run_dtors_ = b;
  60. }
  61. std::size_t
  62. value_stack::
  63. stack::
  64. size() const noexcept
  65. {
  66. return top_ - begin_;
  67. }
  68. bool
  69. value_stack::
  70. stack::
  71. has_chars()
  72. {
  73. return chars_ != 0;
  74. }
  75. //--------------------------------------
  76. // destroy the values but
  77. // not the stack allocation.
  78. void
  79. value_stack::
  80. stack::
  81. clear() noexcept
  82. {
  83. if(top_ != begin_)
  84. {
  85. if(run_dtors_)
  86. for(auto it = top_;
  87. it-- != begin_;)
  88. it->~value();
  89. top_ = begin_;
  90. }
  91. chars_ = 0;
  92. }
  93. void
  94. value_stack::
  95. stack::
  96. maybe_grow()
  97. {
  98. if(top_ >= end_)
  99. grow_one();
  100. }
  101. // make room for at least one more value
  102. void
  103. value_stack::
  104. stack::
  105. grow_one()
  106. {
  107. BOOST_ASSERT(chars_ == 0);
  108. std::size_t const capacity =
  109. end_ - begin_;
  110. std::size_t new_cap = min_size_;
  111. // VFALCO check overflow here
  112. while(new_cap < capacity + 1)
  113. new_cap <<= 1;
  114. auto const begin =
  115. reinterpret_cast<value*>(
  116. sp_->allocate(
  117. new_cap * sizeof(value)));
  118. if(begin_)
  119. {
  120. std::memcpy(
  121. reinterpret_cast<char*>(begin),
  122. reinterpret_cast<char*>(begin_),
  123. size() * sizeof(value));
  124. if(begin_ != temp_)
  125. sp_->deallocate(begin_,
  126. capacity * sizeof(value));
  127. }
  128. // book-keeping
  129. top_ = begin + (top_ - begin_);
  130. end_ = begin + new_cap;
  131. begin_ = begin;
  132. }
  133. // make room for nchars additional characters.
  134. void
  135. value_stack::
  136. stack::
  137. grow(std::size_t nchars)
  138. {
  139. // needed capacity in values
  140. std::size_t const needed =
  141. size() +
  142. 1 +
  143. ((chars_ + nchars +
  144. sizeof(value) - 1) /
  145. sizeof(value));
  146. std::size_t const capacity =
  147. end_ - begin_;
  148. BOOST_ASSERT(
  149. needed > capacity);
  150. std::size_t new_cap = min_size_;
  151. // VFALCO check overflow here
  152. while(new_cap < needed)
  153. new_cap <<= 1;
  154. auto const begin =
  155. reinterpret_cast<value*>(
  156. sp_->allocate(
  157. new_cap * sizeof(value)));
  158. if(begin_)
  159. {
  160. std::size_t amount =
  161. size() * sizeof(value);
  162. if(chars_ > 0)
  163. amount += sizeof(value) + chars_;
  164. std::memcpy(
  165. reinterpret_cast<char*>(begin),
  166. reinterpret_cast<char*>(begin_),
  167. amount);
  168. if(begin_ != temp_)
  169. sp_->deallocate(begin_,
  170. capacity * sizeof(value));
  171. }
  172. // book-keeping
  173. top_ = begin + (top_ - begin_);
  174. end_ = begin + new_cap;
  175. begin_ = begin;
  176. }
  177. //--------------------------------------
  178. void
  179. value_stack::
  180. stack::
  181. append(string_view s)
  182. {
  183. std::size_t const bytes_avail =
  184. reinterpret_cast<
  185. char const*>(end_) -
  186. reinterpret_cast<
  187. char const*>(top_);
  188. // make sure there is room for
  189. // pushing one more value without
  190. // clobbering the string.
  191. if(sizeof(value) + chars_ +
  192. s.size() > bytes_avail)
  193. grow(s.size());
  194. // copy the new piece
  195. std::memcpy(
  196. reinterpret_cast<char*>(
  197. top_ + 1) + chars_,
  198. s.data(), s.size());
  199. chars_ += s.size();
  200. // ensure a pushed value cannot
  201. // clobber the released string.
  202. BOOST_ASSERT(
  203. reinterpret_cast<char*>(
  204. top_ + 1) + chars_ <=
  205. reinterpret_cast<char*>(
  206. end_));
  207. }
  208. string_view
  209. value_stack::
  210. stack::
  211. release_string() noexcept
  212. {
  213. // ensure a pushed value cannot
  214. // clobber the released string.
  215. BOOST_ASSERT(
  216. reinterpret_cast<char*>(
  217. top_ + 1) + chars_ <=
  218. reinterpret_cast<char*>(
  219. end_));
  220. auto const n = chars_;
  221. chars_ = 0;
  222. return { reinterpret_cast<
  223. char const*>(top_ + 1), n };
  224. }
  225. // transfer ownership of the top n
  226. // elements of the stack to the caller
  227. value*
  228. value_stack::
  229. stack::
  230. release(std::size_t n) noexcept
  231. {
  232. BOOST_ASSERT(n <= size());
  233. BOOST_ASSERT(chars_ == 0);
  234. top_ -= n;
  235. return top_;
  236. }
  237. template<class... Args>
  238. value&
  239. value_stack::
  240. stack::
  241. push(Args&&... args)
  242. {
  243. BOOST_ASSERT(chars_ == 0);
  244. if(top_ >= end_)
  245. grow_one();
  246. value& jv = detail::access::
  247. construct_value(top_,
  248. std::forward<Args>(args)...);
  249. ++top_;
  250. return jv;
  251. }
  252. template<class Unchecked>
  253. void
  254. value_stack::
  255. stack::
  256. exchange(Unchecked&& u)
  257. {
  258. BOOST_ASSERT(chars_ == 0);
  259. union U
  260. {
  261. value v;
  262. U() {}
  263. ~U() {}
  264. } jv;
  265. // construct value on the stack
  266. // to avoid clobbering top_[0],
  267. // which belongs to `u`.
  268. detail::access::
  269. construct_value(
  270. &jv.v, std::move(u));
  271. std::memcpy(
  272. reinterpret_cast<
  273. char*>(top_),
  274. &jv.v, sizeof(value));
  275. ++top_;
  276. }
  277. //----------------------------------------------------------
  278. value_stack::
  279. ~value_stack()
  280. {
  281. // default dtor is here so the
  282. // definition goes in the library
  283. // instead of the caller's TU.
  284. }
  285. value_stack::
  286. value_stack(
  287. storage_ptr sp,
  288. unsigned char* temp_buffer,
  289. std::size_t temp_size) noexcept
  290. : st_(
  291. std::move(sp),
  292. temp_buffer,
  293. temp_size)
  294. {
  295. }
  296. void
  297. value_stack::
  298. reset(storage_ptr sp) noexcept
  299. {
  300. st_.clear();
  301. sp_.~storage_ptr();
  302. ::new(&sp_) storage_ptr(
  303. pilfer(sp));
  304. // `stack` needs this
  305. // to clean up correctly
  306. st_.run_dtors(
  307. ! sp_.is_not_shared_and_deallocate_is_trivial());
  308. }
  309. value
  310. value_stack::
  311. release() noexcept
  312. {
  313. // This means the caller did not
  314. // cause a single top level element
  315. // to be produced.
  316. BOOST_ASSERT(st_.size() == 1);
  317. // give up shared ownership
  318. sp_ = {};
  319. return pilfer(*st_.release(1));
  320. }
  321. //----------------------------------------------------------
  322. void
  323. value_stack::
  324. push_array(std::size_t n)
  325. {
  326. // we already have room if n > 0
  327. if(BOOST_JSON_UNLIKELY(n == 0))
  328. st_.maybe_grow();
  329. detail::unchecked_array ua(
  330. st_.release(n), n, sp_);
  331. st_.exchange(std::move(ua));
  332. }
  333. void
  334. value_stack::
  335. push_object(std::size_t n)
  336. {
  337. // we already have room if n > 0
  338. if(BOOST_JSON_UNLIKELY(n == 0))
  339. st_.maybe_grow();
  340. detail::unchecked_object uo(
  341. st_.release(n * 2), n, sp_);
  342. st_.exchange(std::move(uo));
  343. }
  344. void
  345. value_stack::
  346. push_chars(
  347. string_view s)
  348. {
  349. st_.append(s);
  350. }
  351. void
  352. value_stack::
  353. push_key(
  354. string_view s)
  355. {
  356. if(! st_.has_chars())
  357. {
  358. st_.push(detail::key_t{}, s, sp_);
  359. return;
  360. }
  361. auto part = st_.release_string();
  362. st_.push(detail::key_t{}, part, s, sp_);
  363. }
  364. void
  365. value_stack::
  366. push_string(
  367. string_view s)
  368. {
  369. if(! st_.has_chars())
  370. {
  371. // fast path
  372. st_.push(s, sp_);
  373. return;
  374. }
  375. // VFALCO We could add a special
  376. // private ctor to string that just
  377. // creates uninitialized space,
  378. // to reduce member function calls.
  379. auto part = st_.release_string();
  380. auto& str = st_.push(
  381. string_kind, sp_).get_string();
  382. str.reserve(
  383. part.size() + s.size());
  384. std::memcpy(
  385. str.data(),
  386. part.data(), part.size());
  387. std::memcpy(
  388. str.data() + part.size(),
  389. s.data(), s.size());
  390. str.grow(part.size() + s.size());
  391. }
  392. void
  393. value_stack::
  394. push_int64(
  395. int64_t i)
  396. {
  397. st_.push(i, sp_);
  398. }
  399. void
  400. value_stack::
  401. push_uint64(
  402. uint64_t u)
  403. {
  404. st_.push(u, sp_);
  405. }
  406. void
  407. value_stack::
  408. push_double(
  409. double d)
  410. {
  411. st_.push(d, sp_);
  412. }
  413. void
  414. value_stack::
  415. push_bool(
  416. bool b)
  417. {
  418. st_.push(b, sp_);
  419. }
  420. void
  421. value_stack::
  422. push_null()
  423. {
  424. st_.push(nullptr, sp_);
  425. }
  426. BOOST_JSON_NS_END
  427. #endif