array.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  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_ARRAY_HPP
  10. #define BOOST_JSON_IMPL_ARRAY_HPP
  11. #include <boost/json/value.hpp>
  12. #include <boost/json/detail/except.hpp>
  13. #include <algorithm>
  14. #include <stdexcept>
  15. #include <type_traits>
  16. namespace boost {
  17. namespace json {
  18. //----------------------------------------------------------
  19. struct alignas(value)
  20. array::table
  21. {
  22. std::uint32_t size = 0;
  23. std::uint32_t capacity = 0;
  24. constexpr table();
  25. value&
  26. operator[](std::size_t pos) noexcept
  27. {
  28. return (reinterpret_cast<
  29. value*>(this + 1))[pos];
  30. }
  31. BOOST_JSON_DECL
  32. static
  33. table*
  34. allocate(
  35. std::size_t capacity,
  36. storage_ptr const& sp);
  37. BOOST_JSON_DECL
  38. static
  39. void
  40. deallocate(
  41. table* p,
  42. storage_ptr const& sp);
  43. };
  44. //----------------------------------------------------------
  45. class array::revert_construct
  46. {
  47. array* arr_;
  48. public:
  49. explicit
  50. revert_construct(
  51. array& arr) noexcept
  52. : arr_(&arr)
  53. {
  54. }
  55. ~revert_construct()
  56. {
  57. if(! arr_)
  58. return;
  59. arr_->destroy();
  60. }
  61. void
  62. commit() noexcept
  63. {
  64. arr_ = nullptr;
  65. }
  66. };
  67. //----------------------------------------------------------
  68. class array::revert_insert
  69. {
  70. array* arr_;
  71. std::size_t const i_;
  72. std::size_t const n_;
  73. public:
  74. value* p;
  75. BOOST_JSON_DECL
  76. revert_insert(
  77. const_iterator pos,
  78. std::size_t n,
  79. array& arr);
  80. BOOST_JSON_DECL
  81. ~revert_insert();
  82. value*
  83. commit() noexcept
  84. {
  85. auto it =
  86. arr_->data() + i_;
  87. arr_ = nullptr;
  88. return it;
  89. }
  90. };
  91. //----------------------------------------------------------
  92. void
  93. array::
  94. relocate(
  95. value* dest,
  96. value* src,
  97. std::size_t n) noexcept
  98. {
  99. if(n == 0)
  100. return;
  101. std::memmove(
  102. static_cast<void*>(dest),
  103. static_cast<void const*>(src),
  104. n * sizeof(value));
  105. }
  106. //----------------------------------------------------------
  107. //
  108. // Construction
  109. //
  110. //----------------------------------------------------------
  111. template<class InputIt, class>
  112. array::
  113. array(
  114. InputIt first, InputIt last,
  115. storage_ptr sp)
  116. : array(
  117. first, last,
  118. std::move(sp),
  119. iter_cat<InputIt>{})
  120. {
  121. BOOST_STATIC_ASSERT(
  122. std::is_constructible<value,
  123. decltype(*first)>::value);
  124. }
  125. //----------------------------------------------------------
  126. //
  127. // Modifiers
  128. //
  129. //----------------------------------------------------------
  130. template<class InputIt, class>
  131. auto
  132. array::
  133. insert(
  134. const_iterator pos,
  135. InputIt first, InputIt last) ->
  136. iterator
  137. {
  138. BOOST_STATIC_ASSERT(
  139. std::is_constructible<value,
  140. decltype(*first)>::value);
  141. return insert(pos, first, last,
  142. iter_cat<InputIt>{});
  143. }
  144. template<class Arg>
  145. auto
  146. array::
  147. emplace(
  148. const_iterator pos,
  149. Arg&& arg) ->
  150. iterator
  151. {
  152. BOOST_ASSERT(
  153. pos >= begin() &&
  154. pos <= end());
  155. value jv(
  156. std::forward<Arg>(arg),
  157. storage());
  158. return insert(pos, pilfer(jv));
  159. }
  160. template<class Arg>
  161. value&
  162. array::
  163. emplace_back(Arg&& arg)
  164. {
  165. value jv(
  166. std::forward<Arg>(arg),
  167. storage());
  168. return push_back(pilfer(jv));
  169. }
  170. //----------------------------------------------------------
  171. //
  172. // Element access
  173. //
  174. //----------------------------------------------------------
  175. value&
  176. array::
  177. at(std::size_t pos) &
  178. {
  179. if(pos >= t_->size)
  180. detail::throw_out_of_range();
  181. return (*t_)[pos];
  182. }
  183. value&&
  184. array::
  185. at(std::size_t pos) &&
  186. {
  187. return std::move( at(pos) );
  188. }
  189. value const&
  190. array::
  191. at(std::size_t pos) const&
  192. {
  193. if(pos >= t_->size)
  194. detail::throw_out_of_range();
  195. return (*t_)[pos];
  196. }
  197. value&
  198. array::
  199. operator[](std::size_t pos) & noexcept
  200. {
  201. BOOST_ASSERT(pos < t_->size);
  202. return (*t_)[pos];
  203. }
  204. value&&
  205. array::
  206. operator[](std::size_t pos) && noexcept
  207. {
  208. return std::move( (*this)[pos] );
  209. }
  210. value const&
  211. array::
  212. operator[](std::size_t pos) const& noexcept
  213. {
  214. BOOST_ASSERT(pos < t_->size);
  215. return (*t_)[pos];
  216. }
  217. value&
  218. array::
  219. front() & noexcept
  220. {
  221. BOOST_ASSERT(t_->size > 0);
  222. return (*t_)[0];
  223. }
  224. value&&
  225. array::
  226. front() && noexcept
  227. {
  228. return std::move( front() );
  229. }
  230. value const&
  231. array::
  232. front() const& noexcept
  233. {
  234. BOOST_ASSERT(t_->size > 0);
  235. return (*t_)[0];
  236. }
  237. value&
  238. array::
  239. back() & noexcept
  240. {
  241. BOOST_ASSERT(
  242. t_->size > 0);
  243. return (*t_)[t_->size - 1];
  244. }
  245. value&&
  246. array::
  247. back() && noexcept
  248. {
  249. return std::move( back() );
  250. }
  251. value const&
  252. array::
  253. back() const& noexcept
  254. {
  255. BOOST_ASSERT(
  256. t_->size > 0);
  257. return (*t_)[t_->size - 1];
  258. }
  259. value*
  260. array::
  261. data() noexcept
  262. {
  263. return &(*t_)[0];
  264. }
  265. value const*
  266. array::
  267. data() const noexcept
  268. {
  269. return &(*t_)[0];
  270. }
  271. value const*
  272. array::
  273. if_contains(
  274. std::size_t pos) const noexcept
  275. {
  276. if( pos < t_->size )
  277. return &(*t_)[pos];
  278. return nullptr;
  279. }
  280. value*
  281. array::
  282. if_contains(
  283. std::size_t pos) noexcept
  284. {
  285. if( pos < t_->size )
  286. return &(*t_)[pos];
  287. return nullptr;
  288. }
  289. //----------------------------------------------------------
  290. //
  291. // Iterators
  292. //
  293. //----------------------------------------------------------
  294. auto
  295. array::
  296. begin() noexcept ->
  297. iterator
  298. {
  299. return &(*t_)[0];
  300. }
  301. auto
  302. array::
  303. begin() const noexcept ->
  304. const_iterator
  305. {
  306. return &(*t_)[0];
  307. }
  308. auto
  309. array::
  310. cbegin() const noexcept ->
  311. const_iterator
  312. {
  313. return &(*t_)[0];
  314. }
  315. auto
  316. array::
  317. end() noexcept ->
  318. iterator
  319. {
  320. return &(*t_)[t_->size];
  321. }
  322. auto
  323. array::
  324. end() const noexcept ->
  325. const_iterator
  326. {
  327. return &(*t_)[t_->size];
  328. }
  329. auto
  330. array::
  331. cend() const noexcept ->
  332. const_iterator
  333. {
  334. return &(*t_)[t_->size];
  335. }
  336. auto
  337. array::
  338. rbegin() noexcept ->
  339. reverse_iterator
  340. {
  341. return reverse_iterator(end());
  342. }
  343. auto
  344. array::
  345. rbegin() const noexcept ->
  346. const_reverse_iterator
  347. {
  348. return const_reverse_iterator(end());
  349. }
  350. auto
  351. array::
  352. crbegin() const noexcept ->
  353. const_reverse_iterator
  354. {
  355. return const_reverse_iterator(end());
  356. }
  357. auto
  358. array::
  359. rend() noexcept ->
  360. reverse_iterator
  361. {
  362. return reverse_iterator(begin());
  363. }
  364. auto
  365. array::
  366. rend() const noexcept ->
  367. const_reverse_iterator
  368. {
  369. return const_reverse_iterator(begin());
  370. }
  371. auto
  372. array::
  373. crend() const noexcept ->
  374. const_reverse_iterator
  375. {
  376. return const_reverse_iterator(begin());
  377. }
  378. //----------------------------------------------------------
  379. //
  380. // Capacity
  381. //
  382. //----------------------------------------------------------
  383. std::size_t
  384. array::
  385. size() const noexcept
  386. {
  387. return t_->size;
  388. }
  389. constexpr
  390. std::size_t
  391. array::
  392. max_size() noexcept
  393. {
  394. // max_size depends on the address model
  395. using min = std::integral_constant<std::size_t,
  396. (std::size_t(-1) - sizeof(table)) / sizeof(value)>;
  397. return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
  398. min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
  399. }
  400. std::size_t
  401. array::
  402. capacity() const noexcept
  403. {
  404. return t_->capacity;
  405. }
  406. bool
  407. array::
  408. empty() const noexcept
  409. {
  410. return t_->size == 0;
  411. }
  412. void
  413. array::
  414. reserve(
  415. std::size_t new_capacity)
  416. {
  417. // never shrink
  418. if(new_capacity <= t_->capacity)
  419. return;
  420. reserve_impl(new_capacity);
  421. }
  422. //----------------------------------------------------------
  423. //
  424. // private
  425. //
  426. //----------------------------------------------------------
  427. template<class InputIt>
  428. array::
  429. array(
  430. InputIt first, InputIt last,
  431. storage_ptr sp,
  432. std::input_iterator_tag)
  433. : sp_(std::move(sp))
  434. , t_(&empty_)
  435. {
  436. revert_construct r(*this);
  437. while(first != last)
  438. {
  439. reserve(size() + 1);
  440. ::new(end()) value(
  441. *first++, sp_);
  442. ++t_->size;
  443. }
  444. r.commit();
  445. }
  446. template<class InputIt>
  447. array::
  448. array(
  449. InputIt first, InputIt last,
  450. storage_ptr sp,
  451. std::forward_iterator_tag)
  452. : sp_(std::move(sp))
  453. {
  454. std::size_t n =
  455. std::distance(first, last);
  456. if( n == 0 )
  457. {
  458. t_ = &empty_;
  459. return;
  460. }
  461. t_ = table::allocate(n, sp_);
  462. t_->size = 0;
  463. revert_construct r(*this);
  464. while(n--)
  465. {
  466. ::new(end()) value(
  467. *first++, sp_);
  468. ++t_->size;
  469. }
  470. r.commit();
  471. }
  472. template<class InputIt>
  473. auto
  474. array::
  475. insert(
  476. const_iterator pos,
  477. InputIt first, InputIt last,
  478. std::input_iterator_tag) ->
  479. iterator
  480. {
  481. BOOST_ASSERT(
  482. pos >= begin() && pos <= end());
  483. if(first == last)
  484. return data() + (pos - data());
  485. array temp(first, last, sp_);
  486. revert_insert r(
  487. pos, temp.size(), *this);
  488. relocate(
  489. r.p,
  490. temp.data(),
  491. temp.size());
  492. temp.t_->size = 0;
  493. return r.commit();
  494. }
  495. template<class InputIt>
  496. auto
  497. array::
  498. insert(
  499. const_iterator pos,
  500. InputIt first, InputIt last,
  501. std::forward_iterator_tag) ->
  502. iterator
  503. {
  504. std::size_t n =
  505. std::distance(first, last);
  506. revert_insert r(pos, n, *this);
  507. while(n--)
  508. {
  509. ::new(r.p) value(*first++);
  510. ++r.p;
  511. }
  512. return r.commit();
  513. }
  514. } // namespace json
  515. } // namespace boost
  516. #endif