value_stack.ipp 8.7 KB

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