array.hpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590
  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. auto const& self = *this;
  180. return const_cast< value& >( self.at(pos) );
  181. }
  182. value&&
  183. array::
  184. at(std::size_t pos) &&
  185. {
  186. return std::move( at(pos) );
  187. }
  188. value const&
  189. array::
  190. at(std::size_t pos) const&
  191. {
  192. if(pos >= t_->size)
  193. {
  194. BOOST_STATIC_CONSTEXPR source_location loc = BOOST_CURRENT_LOCATION;
  195. detail::throw_system_error( error::out_of_range, &loc );
  196. }
  197. return (*t_)[pos];
  198. }
  199. value&
  200. array::
  201. operator[](std::size_t pos) & noexcept
  202. {
  203. BOOST_ASSERT(pos < t_->size);
  204. return (*t_)[pos];
  205. }
  206. value&&
  207. array::
  208. operator[](std::size_t pos) && noexcept
  209. {
  210. return std::move( (*this)[pos] );
  211. }
  212. value const&
  213. array::
  214. operator[](std::size_t pos) const& noexcept
  215. {
  216. BOOST_ASSERT(pos < t_->size);
  217. return (*t_)[pos];
  218. }
  219. value&
  220. array::
  221. front() & noexcept
  222. {
  223. BOOST_ASSERT(t_->size > 0);
  224. return (*t_)[0];
  225. }
  226. value&&
  227. array::
  228. front() && noexcept
  229. {
  230. return std::move( front() );
  231. }
  232. value const&
  233. array::
  234. front() const& noexcept
  235. {
  236. BOOST_ASSERT(t_->size > 0);
  237. return (*t_)[0];
  238. }
  239. value&
  240. array::
  241. back() & noexcept
  242. {
  243. BOOST_ASSERT(
  244. t_->size > 0);
  245. return (*t_)[t_->size - 1];
  246. }
  247. value&&
  248. array::
  249. back() && noexcept
  250. {
  251. return std::move( back() );
  252. }
  253. value const&
  254. array::
  255. back() const& noexcept
  256. {
  257. BOOST_ASSERT(
  258. t_->size > 0);
  259. return (*t_)[t_->size - 1];
  260. }
  261. value*
  262. array::
  263. data() noexcept
  264. {
  265. return &(*t_)[0];
  266. }
  267. value const*
  268. array::
  269. data() const noexcept
  270. {
  271. return &(*t_)[0];
  272. }
  273. value const*
  274. array::
  275. if_contains(
  276. std::size_t pos) const noexcept
  277. {
  278. if( pos < t_->size )
  279. return &(*t_)[pos];
  280. return nullptr;
  281. }
  282. value*
  283. array::
  284. if_contains(
  285. std::size_t pos) noexcept
  286. {
  287. if( pos < t_->size )
  288. return &(*t_)[pos];
  289. return nullptr;
  290. }
  291. //----------------------------------------------------------
  292. //
  293. // Iterators
  294. //
  295. //----------------------------------------------------------
  296. auto
  297. array::
  298. begin() noexcept ->
  299. iterator
  300. {
  301. return &(*t_)[0];
  302. }
  303. auto
  304. array::
  305. begin() const noexcept ->
  306. const_iterator
  307. {
  308. return &(*t_)[0];
  309. }
  310. auto
  311. array::
  312. cbegin() const noexcept ->
  313. const_iterator
  314. {
  315. return &(*t_)[0];
  316. }
  317. auto
  318. array::
  319. end() noexcept ->
  320. iterator
  321. {
  322. return &(*t_)[t_->size];
  323. }
  324. auto
  325. array::
  326. end() const noexcept ->
  327. const_iterator
  328. {
  329. return &(*t_)[t_->size];
  330. }
  331. auto
  332. array::
  333. cend() const noexcept ->
  334. const_iterator
  335. {
  336. return &(*t_)[t_->size];
  337. }
  338. auto
  339. array::
  340. rbegin() noexcept ->
  341. reverse_iterator
  342. {
  343. return reverse_iterator(end());
  344. }
  345. auto
  346. array::
  347. rbegin() const noexcept ->
  348. const_reverse_iterator
  349. {
  350. return const_reverse_iterator(end());
  351. }
  352. auto
  353. array::
  354. crbegin() const noexcept ->
  355. const_reverse_iterator
  356. {
  357. return const_reverse_iterator(end());
  358. }
  359. auto
  360. array::
  361. rend() noexcept ->
  362. reverse_iterator
  363. {
  364. return reverse_iterator(begin());
  365. }
  366. auto
  367. array::
  368. rend() const noexcept ->
  369. const_reverse_iterator
  370. {
  371. return const_reverse_iterator(begin());
  372. }
  373. auto
  374. array::
  375. crend() const noexcept ->
  376. const_reverse_iterator
  377. {
  378. return const_reverse_iterator(begin());
  379. }
  380. //----------------------------------------------------------
  381. //
  382. // Capacity
  383. //
  384. //----------------------------------------------------------
  385. std::size_t
  386. array::
  387. size() const noexcept
  388. {
  389. return t_->size;
  390. }
  391. constexpr
  392. std::size_t
  393. array::
  394. max_size() noexcept
  395. {
  396. // max_size depends on the address model
  397. using min = std::integral_constant<std::size_t,
  398. (std::size_t(-1) - sizeof(table)) / sizeof(value)>;
  399. return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
  400. min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
  401. }
  402. std::size_t
  403. array::
  404. capacity() const noexcept
  405. {
  406. return t_->capacity;
  407. }
  408. bool
  409. array::
  410. empty() const noexcept
  411. {
  412. return t_->size == 0;
  413. }
  414. void
  415. array::
  416. reserve(
  417. std::size_t new_capacity)
  418. {
  419. // never shrink
  420. if(new_capacity <= t_->capacity)
  421. return;
  422. reserve_impl(new_capacity);
  423. }
  424. //----------------------------------------------------------
  425. //
  426. // private
  427. //
  428. //----------------------------------------------------------
  429. template<class InputIt>
  430. array::
  431. array(
  432. InputIt first, InputIt last,
  433. storage_ptr sp,
  434. std::input_iterator_tag)
  435. : sp_(std::move(sp))
  436. , t_(&empty_)
  437. {
  438. revert_construct r(*this);
  439. while(first != last)
  440. {
  441. reserve(size() + 1);
  442. ::new(end()) value(
  443. *first++, sp_);
  444. ++t_->size;
  445. }
  446. r.commit();
  447. }
  448. template<class InputIt>
  449. array::
  450. array(
  451. InputIt first, InputIt last,
  452. storage_ptr sp,
  453. std::forward_iterator_tag)
  454. : sp_(std::move(sp))
  455. {
  456. std::size_t n =
  457. std::distance(first, last);
  458. if( n == 0 )
  459. {
  460. t_ = &empty_;
  461. return;
  462. }
  463. t_ = table::allocate(n, sp_);
  464. t_->size = 0;
  465. revert_construct r(*this);
  466. while(n--)
  467. {
  468. ::new(end()) value(
  469. *first++, sp_);
  470. ++t_->size;
  471. }
  472. r.commit();
  473. }
  474. template<class InputIt>
  475. auto
  476. array::
  477. insert(
  478. const_iterator pos,
  479. InputIt first, InputIt last,
  480. std::input_iterator_tag) ->
  481. iterator
  482. {
  483. BOOST_ASSERT(
  484. pos >= begin() && pos <= end());
  485. if(first == last)
  486. return data() + (pos - data());
  487. array temp(first, last, sp_);
  488. revert_insert r(
  489. pos, temp.size(), *this);
  490. relocate(
  491. r.p,
  492. temp.data(),
  493. temp.size());
  494. temp.t_->size = 0;
  495. return r.commit();
  496. }
  497. template<class InputIt>
  498. auto
  499. array::
  500. insert(
  501. const_iterator pos,
  502. InputIt first, InputIt last,
  503. std::forward_iterator_tag) ->
  504. iterator
  505. {
  506. std::size_t n =
  507. std::distance(first, last);
  508. revert_insert r(pos, n, *this);
  509. while(n--)
  510. {
  511. ::new(r.p) value(*first++);
  512. ++r.p;
  513. }
  514. return r.commit();
  515. }
  516. } // namespace json
  517. } // namespace boost
  518. #endif