value_stack.ipp 8.7 KB

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