array.ipp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776
  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_ARRAY_IPP
  10. #define BOOST_JSON_IMPL_ARRAY_IPP
  11. #include <boost/container_hash/hash.hpp>
  12. #include <boost/json/array.hpp>
  13. #include <boost/json/pilfer.hpp>
  14. #include <boost/json/detail/except.hpp>
  15. #include <cstdlib>
  16. #include <limits>
  17. #include <new>
  18. #include <utility>
  19. namespace boost {
  20. namespace json {
  21. //----------------------------------------------------------
  22. constexpr array::table::table() = default;
  23. // empty arrays point here
  24. BOOST_JSON_REQUIRE_CONST_INIT
  25. array::table array::empty_;
  26. auto
  27. array::
  28. table::
  29. allocate(
  30. std::size_t capacity,
  31. storage_ptr const& sp) ->
  32. table*
  33. {
  34. BOOST_ASSERT(capacity > 0);
  35. if(capacity > array::max_size())
  36. {
  37. BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
  38. detail::throw_system_error( error::array_too_large, &loc );
  39. }
  40. auto p = reinterpret_cast<
  41. table*>(sp->allocate(
  42. sizeof(table) +
  43. capacity * sizeof(value),
  44. alignof(value)));
  45. p->capacity = static_cast<
  46. std::uint32_t>(capacity);
  47. return p;
  48. }
  49. void
  50. array::
  51. table::
  52. deallocate(
  53. table* p,
  54. storage_ptr const& sp)
  55. {
  56. if(p->capacity == 0)
  57. return;
  58. sp->deallocate(p,
  59. sizeof(table) +
  60. p->capacity * sizeof(value),
  61. alignof(value));
  62. }
  63. //----------------------------------------------------------
  64. array::
  65. revert_insert::
  66. revert_insert(
  67. const_iterator pos,
  68. std::size_t n,
  69. array& arr)
  70. : arr_(&arr)
  71. , i_(pos - arr_->data())
  72. , n_(n)
  73. {
  74. BOOST_ASSERT(
  75. pos >= arr_->begin() &&
  76. pos <= arr_->end());
  77. if( n_ <= arr_->capacity() -
  78. arr_->size())
  79. {
  80. // fast path
  81. p = arr_->data() + i_;
  82. if(n_ == 0)
  83. return;
  84. relocate(
  85. p + n_,
  86. p,
  87. arr_->size() - i_);
  88. arr_->t_->size = static_cast<
  89. std::uint32_t>(
  90. arr_->t_->size + n_);
  91. return;
  92. }
  93. if(n_ > max_size() - arr_->size())
  94. {
  95. BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
  96. detail::throw_system_error( error::array_too_large, &loc );
  97. }
  98. auto t = table::allocate(
  99. arr_->growth(arr_->size() + n_),
  100. arr_->sp_);
  101. t->size = static_cast<std::uint32_t>(
  102. arr_->size() + n_);
  103. p = &(*t)[0] + i_;
  104. relocate(
  105. &(*t)[0],
  106. arr_->data(),
  107. i_);
  108. relocate(
  109. &(*t)[i_ + n_],
  110. arr_->data() + i_,
  111. arr_->size() - i_);
  112. t = detail::exchange(arr_->t_, t);
  113. table::deallocate(t, arr_->sp_);
  114. }
  115. array::
  116. revert_insert::
  117. ~revert_insert()
  118. {
  119. if(! arr_)
  120. return;
  121. BOOST_ASSERT(n_ != 0);
  122. auto const pos =
  123. arr_->data() + i_;
  124. arr_->destroy(pos, p);
  125. arr_->t_->size = static_cast<
  126. std::uint32_t>(
  127. arr_->t_->size - n_);
  128. relocate(
  129. pos,
  130. pos + n_,
  131. arr_->size() - i_);
  132. }
  133. //----------------------------------------------------------
  134. void
  135. array::
  136. destroy(
  137. value* first, value* last) noexcept
  138. {
  139. if(sp_.is_not_shared_and_deallocate_is_trivial())
  140. return;
  141. while(last-- != first)
  142. last->~value();
  143. }
  144. void
  145. array::
  146. destroy() noexcept
  147. {
  148. if(sp_.is_not_shared_and_deallocate_is_trivial())
  149. return;
  150. auto last = end();
  151. auto const first = begin();
  152. while(last-- != first)
  153. last->~value();
  154. table::deallocate(t_, sp_);
  155. }
  156. //----------------------------------------------------------
  157. //
  158. // Special Members
  159. //
  160. //----------------------------------------------------------
  161. array::
  162. array(detail::unchecked_array&& ua)
  163. : sp_(ua.storage())
  164. {
  165. BOOST_STATIC_ASSERT(
  166. alignof(table) == alignof(value));
  167. if(ua.size() == 0)
  168. {
  169. t_ = &empty_;
  170. return;
  171. }
  172. t_= table::allocate(
  173. ua.size(), sp_);
  174. t_->size = static_cast<
  175. std::uint32_t>(ua.size());
  176. ua.relocate(data());
  177. }
  178. array::
  179. ~array() noexcept
  180. {
  181. destroy();
  182. }
  183. array::
  184. array(
  185. std::size_t count,
  186. value const& v,
  187. storage_ptr sp)
  188. : sp_(std::move(sp))
  189. {
  190. if(count == 0)
  191. {
  192. t_ = &empty_;
  193. return;
  194. }
  195. t_= table::allocate(
  196. count, sp_);
  197. t_->size = 0;
  198. revert_construct r(*this);
  199. while(count--)
  200. {
  201. ::new(end()) value(v, sp_);
  202. ++t_->size;
  203. }
  204. r.commit();
  205. }
  206. array::
  207. array(
  208. std::size_t count,
  209. storage_ptr sp)
  210. : sp_(std::move(sp))
  211. {
  212. if(count == 0)
  213. {
  214. t_ = &empty_;
  215. return;
  216. }
  217. t_ = table::allocate(
  218. count, sp_);
  219. t_->size = static_cast<
  220. std::uint32_t>(count);
  221. auto p = data();
  222. do
  223. {
  224. ::new(p++) value(sp_);
  225. }
  226. while(--count);
  227. }
  228. array::
  229. array(array const& other)
  230. : array(other, other.sp_)
  231. {
  232. }
  233. array::
  234. array(
  235. array const& other,
  236. storage_ptr sp)
  237. : sp_(std::move(sp))
  238. {
  239. if(other.empty())
  240. {
  241. t_ = &empty_;
  242. return;
  243. }
  244. t_ = table::allocate(
  245. other.size(), sp_);
  246. t_->size = 0;
  247. revert_construct r(*this);
  248. auto src = other.data();
  249. auto dest = data();
  250. auto const n = other.size();
  251. do
  252. {
  253. ::new(dest++) value(
  254. *src++, sp_);
  255. ++t_->size;
  256. }
  257. while(t_->size < n);
  258. r.commit();
  259. }
  260. array::
  261. array(
  262. array&& other,
  263. storage_ptr sp)
  264. : sp_(std::move(sp))
  265. {
  266. if(*sp_ == *other.sp_)
  267. {
  268. // same resource
  269. t_ = detail::exchange(
  270. other.t_, &empty_);
  271. return;
  272. }
  273. else if(other.empty())
  274. {
  275. t_ = &empty_;
  276. return;
  277. }
  278. // copy
  279. t_ = table::allocate(
  280. other.size(), sp_);
  281. t_->size = 0;
  282. revert_construct r(*this);
  283. auto src = other.data();
  284. auto dest = data();
  285. auto const n = other.size();
  286. do
  287. {
  288. ::new(dest++) value(
  289. *src++, sp_);
  290. ++t_->size;
  291. }
  292. while(t_->size < n);
  293. r.commit();
  294. }
  295. array::
  296. array(
  297. std::initializer_list<
  298. value_ref> init,
  299. storage_ptr sp)
  300. : sp_(std::move(sp))
  301. {
  302. if(init.size() == 0)
  303. {
  304. t_ = &empty_;
  305. return;
  306. }
  307. t_ = table::allocate(
  308. init.size(), sp_);
  309. t_->size = 0;
  310. revert_construct r(*this);
  311. value_ref::write_array(
  312. data(), init, sp_);
  313. t_->size = static_cast<
  314. std::uint32_t>(init.size());
  315. r.commit();
  316. }
  317. //----------------------------------------------------------
  318. array&
  319. array::
  320. operator=(array const& other)
  321. {
  322. array(other,
  323. storage()).swap(*this);
  324. return *this;
  325. }
  326. array&
  327. array::
  328. operator=(array&& other)
  329. {
  330. array(std::move(other),
  331. storage()).swap(*this);
  332. return *this;
  333. }
  334. array&
  335. array::
  336. operator=(
  337. std::initializer_list<value_ref> init)
  338. {
  339. array(init,
  340. storage()).swap(*this);
  341. return *this;
  342. }
  343. //----------------------------------------------------------
  344. //
  345. // Capacity
  346. //
  347. //----------------------------------------------------------
  348. void
  349. array::
  350. shrink_to_fit() noexcept
  351. {
  352. if(capacity() <= size())
  353. return;
  354. if(size() == 0)
  355. {
  356. table::deallocate(t_, sp_);
  357. t_ = &empty_;
  358. return;
  359. }
  360. #ifndef BOOST_NO_EXCEPTIONS
  361. try
  362. {
  363. #endif
  364. auto t = table::allocate(
  365. size(), sp_);
  366. relocate(
  367. &(*t)[0],
  368. data(),
  369. size());
  370. t->size = static_cast<
  371. std::uint32_t>(size());
  372. t = detail::exchange(
  373. t_, t);
  374. table::deallocate(t, sp_);
  375. #ifndef BOOST_NO_EXCEPTIONS
  376. }
  377. catch(...)
  378. {
  379. // eat the exception
  380. return;
  381. }
  382. #endif
  383. }
  384. //----------------------------------------------------------
  385. //
  386. // Modifiers
  387. //
  388. //----------------------------------------------------------
  389. void
  390. array::
  391. clear() noexcept
  392. {
  393. if(size() == 0)
  394. return;
  395. destroy(
  396. begin(), end());
  397. t_->size = 0;
  398. }
  399. auto
  400. array::
  401. insert(
  402. const_iterator pos,
  403. value const& v) ->
  404. iterator
  405. {
  406. return emplace(pos, v);
  407. }
  408. auto
  409. array::
  410. insert(
  411. const_iterator pos,
  412. value&& v) ->
  413. iterator
  414. {
  415. return emplace(pos, std::move(v));
  416. }
  417. auto
  418. array::
  419. insert(
  420. const_iterator pos,
  421. std::size_t count,
  422. value const& v) ->
  423. iterator
  424. {
  425. revert_insert r(
  426. pos, count, *this);
  427. while(count--)
  428. {
  429. ::new(r.p) value(v, sp_);
  430. ++r.p;
  431. }
  432. return r.commit();
  433. }
  434. auto
  435. array::
  436. insert(
  437. const_iterator pos,
  438. std::initializer_list<
  439. value_ref> init) ->
  440. iterator
  441. {
  442. revert_insert r(
  443. pos, init.size(), *this);
  444. value_ref::write_array(
  445. r.p, init, sp_);
  446. return r.commit();
  447. }
  448. auto
  449. array::
  450. erase(
  451. const_iterator pos) noexcept ->
  452. iterator
  453. {
  454. BOOST_ASSERT(
  455. pos >= begin() &&
  456. pos <= end());
  457. return erase(pos, pos + 1);
  458. }
  459. auto
  460. array::
  461. erase(
  462. const_iterator first,
  463. const_iterator last) noexcept ->
  464. iterator
  465. {
  466. BOOST_ASSERT(
  467. first >= begin() &&
  468. last >= first &&
  469. last <= end());
  470. std::size_t const n =
  471. last - first;
  472. auto const p = &(*t_)[0] +
  473. (first - &(*t_)[0]);
  474. destroy(p, p + n);
  475. relocate(p, p + n,
  476. t_->size - (last -
  477. &(*t_)[0]));
  478. t_->size = static_cast<
  479. std::uint32_t>(t_->size - n);
  480. return p;
  481. }
  482. void
  483. array::
  484. push_back(value const& v)
  485. {
  486. emplace_back(v);
  487. }
  488. void
  489. array::
  490. push_back(value&& v)
  491. {
  492. emplace_back(std::move(v));
  493. }
  494. void
  495. array::
  496. pop_back() noexcept
  497. {
  498. auto const p = &back();
  499. destroy(p, p + 1);
  500. --t_->size;
  501. }
  502. void
  503. array::
  504. resize(std::size_t count)
  505. {
  506. if(count <= t_->size)
  507. {
  508. // shrink
  509. destroy(
  510. &(*t_)[0] + count,
  511. &(*t_)[0] + t_->size);
  512. t_->size = static_cast<
  513. std::uint32_t>(count);
  514. return;
  515. }
  516. reserve(count);
  517. auto p = &(*t_)[t_->size];
  518. auto const end = &(*t_)[count];
  519. while(p != end)
  520. ::new(p++) value(sp_);
  521. t_->size = static_cast<
  522. std::uint32_t>(count);
  523. }
  524. void
  525. array::
  526. resize(
  527. std::size_t count,
  528. value const& v)
  529. {
  530. if(count <= size())
  531. {
  532. // shrink
  533. destroy(
  534. data() + count,
  535. data() + size());
  536. t_->size = static_cast<
  537. std::uint32_t>(count);
  538. return;
  539. }
  540. count -= size();
  541. revert_insert r(
  542. end(), count, *this);
  543. while(count--)
  544. {
  545. ::new(r.p) value(v, sp_);
  546. ++r.p;
  547. }
  548. r.commit();
  549. }
  550. void
  551. array::
  552. swap(array& other)
  553. {
  554. if(*sp_ == *other.sp_)
  555. {
  556. t_ = detail::exchange(
  557. other.t_, t_);
  558. return;
  559. }
  560. array temp1(
  561. std::move(*this),
  562. other.storage());
  563. array temp2(
  564. std::move(other),
  565. this->storage());
  566. this->~array();
  567. ::new(this) array(
  568. pilfer(temp2));
  569. other.~array();
  570. ::new(&other) array(
  571. pilfer(temp1));
  572. }
  573. //----------------------------------------------------------
  574. //
  575. // Private
  576. //
  577. //----------------------------------------------------------
  578. std::size_t
  579. array::
  580. growth(
  581. std::size_t new_size) const
  582. {
  583. if(new_size > max_size())
  584. {
  585. BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
  586. detail::throw_system_error( error::array_too_large, &loc );
  587. }
  588. std::size_t const old = capacity();
  589. if(old > max_size() - old / 2)
  590. return new_size;
  591. std::size_t const g =
  592. old + old / 2; // 1.5x
  593. if(g < new_size)
  594. return new_size;
  595. return g;
  596. }
  597. // precondition: new_capacity > capacity()
  598. void
  599. array::
  600. reserve_impl(
  601. std::size_t new_capacity)
  602. {
  603. BOOST_ASSERT(
  604. new_capacity > t_->capacity);
  605. auto t = table::allocate(
  606. growth(new_capacity), sp_);
  607. relocate(
  608. &(*t)[0],
  609. &(*t_)[0],
  610. t_->size);
  611. t->size = t_->size;
  612. t = detail::exchange(t_, t);
  613. table::deallocate(t, sp_);
  614. }
  615. // precondition: pv is not aliased
  616. value&
  617. array::
  618. push_back(
  619. pilfered<value> pv)
  620. {
  621. auto const n = t_->size;
  622. if(n < t_->capacity)
  623. {
  624. // fast path
  625. auto& v = *::new(
  626. &(*t_)[n]) value(pv);
  627. ++t_->size;
  628. return v;
  629. }
  630. auto const t =
  631. detail::exchange(t_,
  632. table::allocate(
  633. growth(n + 1),
  634. sp_));
  635. auto& v = *::new(
  636. &(*t_)[n]) value(pv);
  637. relocate(
  638. &(*t_)[0],
  639. &(*t)[0],
  640. n);
  641. t_->size = n + 1;
  642. table::deallocate(t, sp_);
  643. return v;
  644. }
  645. // precondition: pv is not aliased
  646. auto
  647. array::
  648. insert(
  649. const_iterator pos,
  650. pilfered<value> pv) ->
  651. iterator
  652. {
  653. BOOST_ASSERT(
  654. pos >= begin() &&
  655. pos <= end());
  656. std::size_t const n =
  657. t_->size;
  658. std::size_t const i =
  659. pos - &(*t_)[0];
  660. if(n < t_->capacity)
  661. {
  662. // fast path
  663. auto const p =
  664. &(*t_)[i];
  665. relocate(
  666. p + 1,
  667. p,
  668. n - i);
  669. ::new(p) value(pv);
  670. ++t_->size;
  671. return p;
  672. }
  673. auto t =
  674. table::allocate(
  675. growth(n + 1), sp_);
  676. auto const p = &(*t)[i];
  677. ::new(p) value(pv);
  678. relocate(
  679. &(*t)[0],
  680. &(*t_)[0],
  681. i);
  682. relocate(
  683. p + 1,
  684. &(*t_)[i],
  685. n - i);
  686. t->size = static_cast<
  687. std::uint32_t>(size() + 1);
  688. t = detail::exchange(t_, t);
  689. table::deallocate(t, sp_);
  690. return p;
  691. }
  692. //----------------------------------------------------------
  693. bool
  694. array::
  695. equal(
  696. array const& other) const noexcept
  697. {
  698. if(size() != other.size())
  699. return false;
  700. for(std::size_t i = 0; i < size(); ++i)
  701. if((*this)[i] != other[i])
  702. return false;
  703. return true;
  704. }
  705. } // namespace json
  706. } // namespace boost
  707. //----------------------------------------------------------
  708. //
  709. // std::hash specialization
  710. //
  711. //----------------------------------------------------------
  712. std::size_t
  713. std::hash<::boost::json::array>::operator()(
  714. ::boost::json::array const& ja) const noexcept
  715. {
  716. return ::boost::hash< ::boost::json::array >()( ja );
  717. }
  718. //----------------------------------------------------------
  719. #endif