object.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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_OBJECT_HPP
  10. #define BOOST_JSON_IMPL_OBJECT_HPP
  11. #include <boost/json/value.hpp>
  12. #include <iterator>
  13. #include <cmath>
  14. #include <type_traits>
  15. #include <utility>
  16. BOOST_JSON_NS_BEGIN
  17. namespace detail {
  18. // Objects with size less than or equal
  19. // to this number will use a linear search
  20. // instead of the more expensive hash function.
  21. static
  22. constexpr
  23. std::size_t
  24. small_object_size_ = 18;
  25. BOOST_STATIC_ASSERT(
  26. small_object_size_ <
  27. BOOST_JSON_MAX_STRUCTURED_SIZE);
  28. } // detail
  29. //----------------------------------------------------------
  30. struct alignas(key_value_pair)
  31. object::table
  32. {
  33. std::uint32_t size = 0;
  34. std::uint32_t capacity = 0;
  35. std::uintptr_t salt = 0;
  36. #if defined(_MSC_VER) && BOOST_JSON_ARCH == 32
  37. // VFALCO If we make key_value_pair smaller,
  38. // then we might want to revisit this
  39. // padding.
  40. BOOST_STATIC_ASSERT(
  41. sizeof(key_value_pair) == 32);
  42. char pad[4] = {}; // silence warnings
  43. #endif
  44. constexpr table();
  45. // returns true if we use a linear
  46. // search instead of the hash table.
  47. bool is_small() const noexcept
  48. {
  49. return capacity <=
  50. detail::small_object_size_;
  51. }
  52. key_value_pair&
  53. operator[](
  54. std::size_t pos) noexcept
  55. {
  56. return reinterpret_cast<
  57. key_value_pair*>(
  58. this + 1)[pos];
  59. }
  60. // VFALCO This is exported for tests
  61. BOOST_JSON_DECL
  62. std::size_t
  63. digest(string_view key) const noexcept;
  64. inline
  65. index_t&
  66. bucket(std::size_t hash) noexcept;
  67. inline
  68. index_t&
  69. bucket(string_view key) noexcept;
  70. inline
  71. void
  72. clear() noexcept;
  73. static
  74. inline
  75. table*
  76. allocate(
  77. std::size_t capacity,
  78. std::uintptr_t salt,
  79. storage_ptr const& sp);
  80. static
  81. void
  82. deallocate(
  83. table* p,
  84. storage_ptr const& sp) noexcept
  85. {
  86. if(p->capacity == 0)
  87. return;
  88. if(p->is_small())
  89. sp->deallocate(p,
  90. sizeof(table) + p->capacity * (
  91. sizeof(key_value_pair) +
  92. sizeof(index_t)));
  93. else
  94. sp->deallocate(p,
  95. sizeof(table) + p->capacity *
  96. sizeof(key_value_pair));
  97. }
  98. };
  99. //----------------------------------------------------------
  100. class object::revert_construct
  101. {
  102. object* obj_;
  103. BOOST_JSON_DECL
  104. void
  105. destroy() noexcept;
  106. public:
  107. explicit
  108. revert_construct(
  109. object& obj) noexcept
  110. : obj_(&obj)
  111. {
  112. }
  113. ~revert_construct()
  114. {
  115. if(! obj_)
  116. return;
  117. destroy();
  118. }
  119. void
  120. commit() noexcept
  121. {
  122. obj_ = nullptr;
  123. }
  124. };
  125. //----------------------------------------------------------
  126. class object::revert_insert
  127. {
  128. object* obj_;
  129. std::size_t size_;
  130. BOOST_JSON_DECL
  131. void
  132. destroy() noexcept;
  133. public:
  134. explicit
  135. revert_insert(
  136. object& obj) noexcept
  137. : obj_(&obj)
  138. , size_(obj_->size())
  139. {
  140. }
  141. ~revert_insert()
  142. {
  143. if(! obj_)
  144. return;
  145. destroy();
  146. obj_->t_->size = static_cast<
  147. index_t>(size_);
  148. }
  149. void
  150. commit() noexcept
  151. {
  152. obj_ = nullptr;
  153. }
  154. };
  155. //----------------------------------------------------------
  156. //
  157. // Iterators
  158. //
  159. //----------------------------------------------------------
  160. auto
  161. object::
  162. begin() noexcept ->
  163. iterator
  164. {
  165. return &(*t_)[0];
  166. }
  167. auto
  168. object::
  169. begin() const noexcept ->
  170. const_iterator
  171. {
  172. return &(*t_)[0];
  173. }
  174. auto
  175. object::
  176. cbegin() const noexcept ->
  177. const_iterator
  178. {
  179. return &(*t_)[0];
  180. }
  181. auto
  182. object::
  183. end() noexcept ->
  184. iterator
  185. {
  186. return &(*t_)[t_->size];
  187. }
  188. auto
  189. object::
  190. end() const noexcept ->
  191. const_iterator
  192. {
  193. return &(*t_)[t_->size];
  194. }
  195. auto
  196. object::
  197. cend() const noexcept ->
  198. const_iterator
  199. {
  200. return &(*t_)[t_->size];
  201. }
  202. auto
  203. object::
  204. rbegin() noexcept ->
  205. reverse_iterator
  206. {
  207. return reverse_iterator(end());
  208. }
  209. auto
  210. object::
  211. rbegin() const noexcept ->
  212. const_reverse_iterator
  213. {
  214. return const_reverse_iterator(end());
  215. }
  216. auto
  217. object::
  218. crbegin() const noexcept ->
  219. const_reverse_iterator
  220. {
  221. return const_reverse_iterator(end());
  222. }
  223. auto
  224. object::
  225. rend() noexcept ->
  226. reverse_iterator
  227. {
  228. return reverse_iterator(begin());
  229. }
  230. auto
  231. object::
  232. rend() const noexcept ->
  233. const_reverse_iterator
  234. {
  235. return const_reverse_iterator(begin());
  236. }
  237. auto
  238. object::
  239. crend() const noexcept ->
  240. const_reverse_iterator
  241. {
  242. return const_reverse_iterator(begin());
  243. }
  244. //----------------------------------------------------------
  245. //
  246. // Capacity
  247. //
  248. //----------------------------------------------------------
  249. bool
  250. object::
  251. empty() const noexcept
  252. {
  253. return t_->size == 0;
  254. }
  255. auto
  256. object::
  257. size() const noexcept ->
  258. std::size_t
  259. {
  260. return t_->size;
  261. }
  262. constexpr
  263. std::size_t
  264. object::
  265. max_size() noexcept
  266. {
  267. // max_size depends on the address model
  268. using min = std::integral_constant<std::size_t,
  269. (std::size_t(-1) - sizeof(table)) /
  270. (sizeof(key_value_pair) + sizeof(index_t))>;
  271. return min::value < BOOST_JSON_MAX_STRUCTURED_SIZE ?
  272. min::value : BOOST_JSON_MAX_STRUCTURED_SIZE;
  273. }
  274. auto
  275. object::
  276. capacity() const noexcept ->
  277. std::size_t
  278. {
  279. return t_->capacity;
  280. }
  281. //----------------------------------------------------------
  282. //
  283. // Lookup
  284. //
  285. //----------------------------------------------------------
  286. auto
  287. object::
  288. at(string_view key) ->
  289. value&
  290. {
  291. auto it = find(key);
  292. if(it == end())
  293. detail::throw_out_of_range(
  294. BOOST_JSON_SOURCE_POS);
  295. return it->value();
  296. }
  297. auto
  298. object::
  299. at(string_view key) const ->
  300. value const&
  301. {
  302. auto it = find(key);
  303. if(it == end())
  304. detail::throw_out_of_range(
  305. BOOST_JSON_SOURCE_POS);
  306. return it->value();
  307. }
  308. //----------------------------------------------------------
  309. template<class P, class>
  310. auto
  311. object::
  312. insert(P&& p) ->
  313. std::pair<iterator, bool>
  314. {
  315. key_value_pair v(
  316. std::forward<P>(p), sp_);
  317. return insert_impl(pilfer(v));
  318. }
  319. template<class M>
  320. auto
  321. object::
  322. insert_or_assign(
  323. string_view key, M&& m) ->
  324. std::pair<iterator, bool>
  325. {
  326. reserve(size() + 1);
  327. auto const result = find_impl(key);
  328. if(result.first)
  329. {
  330. value(std::forward<M>(m),
  331. sp_).swap(result.first->value());
  332. return { result.first, false };
  333. }
  334. key_value_pair kv(key,
  335. std::forward<M>(m), sp_);
  336. return { insert_impl(pilfer(kv),
  337. result.second), true };
  338. }
  339. template<class Arg>
  340. auto
  341. object::
  342. emplace(
  343. string_view key,
  344. Arg&& arg) ->
  345. std::pair<iterator, bool>
  346. {
  347. reserve(size() + 1);
  348. auto const result = find_impl(key);
  349. if(result.first)
  350. return { result.first, false };
  351. key_value_pair kv(key,
  352. std::forward<Arg>(arg), sp_);
  353. return { insert_impl(pilfer(kv),
  354. result.second), true };
  355. }
  356. //----------------------------------------------------------
  357. //
  358. // (private)
  359. //
  360. //----------------------------------------------------------
  361. template<class InputIt>
  362. void
  363. object::
  364. construct(
  365. InputIt first,
  366. InputIt last,
  367. std::size_t min_capacity,
  368. std::input_iterator_tag)
  369. {
  370. reserve(min_capacity);
  371. revert_construct r(*this);
  372. while(first != last)
  373. {
  374. insert(*first);
  375. ++first;
  376. }
  377. r.commit();
  378. }
  379. template<class InputIt>
  380. void
  381. object::
  382. construct(
  383. InputIt first,
  384. InputIt last,
  385. std::size_t min_capacity,
  386. std::forward_iterator_tag)
  387. {
  388. auto n = static_cast<
  389. std::size_t>(std::distance(
  390. first, last));
  391. if( n < min_capacity)
  392. n = min_capacity;
  393. reserve(n);
  394. revert_construct r(*this);
  395. while(first != last)
  396. {
  397. insert(*first);
  398. ++first;
  399. }
  400. r.commit();
  401. }
  402. template<class InputIt>
  403. void
  404. object::
  405. insert(
  406. InputIt first,
  407. InputIt last,
  408. std::input_iterator_tag)
  409. {
  410. // Since input iterators cannot be rewound,
  411. // we keep inserted elements on an exception.
  412. //
  413. while(first != last)
  414. {
  415. insert(*first);
  416. ++first;
  417. }
  418. }
  419. template<class InputIt>
  420. void
  421. object::
  422. insert(
  423. InputIt first,
  424. InputIt last,
  425. std::forward_iterator_tag)
  426. {
  427. auto const n =
  428. static_cast<std::size_t>(
  429. std::distance(first, last));
  430. auto const n0 = size();
  431. if(n > max_size() - n0)
  432. detail::throw_length_error(
  433. "object too large",
  434. BOOST_JSON_SOURCE_POS);
  435. reserve(n0 + n);
  436. revert_insert r(*this);
  437. while(first != last)
  438. {
  439. insert(*first);
  440. ++first;
  441. }
  442. r.commit();
  443. }
  444. //----------------------------------------------------------
  445. namespace detail {
  446. unchecked_object::
  447. ~unchecked_object()
  448. {
  449. if(! data_)
  450. return;
  451. if(sp_.is_not_shared_and_deallocate_is_trivial())
  452. return;
  453. value* p = data_;
  454. while(size_--)
  455. {
  456. p[0].~value();
  457. p[1].~value();
  458. p += 2;
  459. }
  460. }
  461. } // detail
  462. BOOST_JSON_NS_END
  463. #endif