object.ipp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825
  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_IPP
  10. #define BOOST_JSON_IMPL_OBJECT_IPP
  11. #include <boost/json/object.hpp>
  12. #include <boost/json/detail/digest.hpp>
  13. #include <boost/json/detail/except.hpp>
  14. #include <algorithm>
  15. #include <cmath>
  16. #include <cstdlib>
  17. #include <cstring>
  18. #include <new>
  19. #include <stdexcept>
  20. #include <type_traits>
  21. BOOST_JSON_NS_BEGIN
  22. //----------------------------------------------------------
  23. constexpr object::table::table() = default;
  24. // empty objects point here
  25. BOOST_JSON_REQUIRE_CONST_INIT
  26. object::table object::empty_;
  27. std::size_t
  28. object::table::
  29. digest(string_view key) const noexcept
  30. {
  31. BOOST_ASSERT(salt != 0);
  32. return detail::digest(
  33. key.data(), key.size(), salt);
  34. }
  35. auto
  36. object::table::
  37. bucket(std::size_t hash) noexcept ->
  38. index_t&
  39. {
  40. return reinterpret_cast<
  41. index_t*>(&(*this)[capacity])[
  42. hash % capacity];
  43. }
  44. auto
  45. object::table::
  46. bucket(string_view key) noexcept ->
  47. index_t&
  48. {
  49. return bucket(digest(key));
  50. }
  51. void
  52. object::table::
  53. clear() noexcept
  54. {
  55. BOOST_ASSERT(! is_small());
  56. // initialize buckets
  57. std::memset(
  58. reinterpret_cast<index_t*>(
  59. &(*this)[capacity]),
  60. 0xff, // null_index_
  61. capacity * sizeof(index_t));
  62. }
  63. object::table*
  64. object::table::
  65. allocate(
  66. std::size_t capacity,
  67. std::uintptr_t salt,
  68. storage_ptr const& sp)
  69. {
  70. BOOST_STATIC_ASSERT(
  71. alignof(key_value_pair) >=
  72. alignof(index_t));
  73. BOOST_ASSERT(capacity > 0);
  74. BOOST_ASSERT(capacity <= max_size());
  75. table* p;
  76. if(capacity <= detail::small_object_size_)
  77. {
  78. p = reinterpret_cast<
  79. table*>(sp->allocate(
  80. sizeof(table) + capacity *
  81. sizeof(key_value_pair)));
  82. p->capacity = static_cast<
  83. std::uint32_t>(capacity);
  84. }
  85. else
  86. {
  87. p = reinterpret_cast<
  88. table*>(sp->allocate(
  89. sizeof(table) + capacity * (
  90. sizeof(key_value_pair) +
  91. sizeof(index_t))));
  92. p->capacity = static_cast<
  93. std::uint32_t>(capacity);
  94. p->clear();
  95. }
  96. if(salt)
  97. {
  98. p->salt = salt;
  99. }
  100. else
  101. {
  102. // VFALCO This would be better if it
  103. // was random, but maybe this
  104. // is good enough.
  105. p->salt = reinterpret_cast<
  106. std::uintptr_t>(p);
  107. }
  108. return p;
  109. }
  110. //----------------------------------------------------------
  111. void
  112. object::
  113. revert_construct::
  114. destroy() noexcept
  115. {
  116. obj_->destroy();
  117. }
  118. //----------------------------------------------------------
  119. void
  120. object::
  121. revert_insert::
  122. destroy() noexcept
  123. {
  124. obj_->destroy(
  125. &(*obj_->t_)[size_],
  126. obj_->end());
  127. }
  128. //----------------------------------------------------------
  129. //
  130. // Construction
  131. //
  132. //----------------------------------------------------------
  133. object::
  134. object(detail::unchecked_object&& uo)
  135. : sp_(uo.storage())
  136. {
  137. if(uo.size() == 0)
  138. {
  139. t_ = &empty_;
  140. return;
  141. }
  142. // should already be checked
  143. BOOST_ASSERT(
  144. uo.size() <= max_size());
  145. t_ = table::allocate(
  146. uo.size(), 0, sp_);
  147. // insert all elements, keeping
  148. // the last of any duplicate keys.
  149. auto dest = begin();
  150. auto src = uo.release();
  151. auto const end = src + 2 * uo.size();
  152. if(t_->is_small())
  153. {
  154. t_->size = 0;
  155. while(src != end)
  156. {
  157. access::construct_key_value_pair(
  158. dest, pilfer(src[0]), pilfer(src[1]));
  159. src += 2;
  160. auto result = find_impl(dest->key());
  161. if(! result.first)
  162. {
  163. ++dest;
  164. ++t_->size;
  165. continue;
  166. }
  167. // handle duplicate
  168. auto& v = *result.first;
  169. // don't bother to check if
  170. // storage deallocate is trivial
  171. v.~key_value_pair();
  172. // trivial relocate
  173. std::memcpy(
  174. static_cast<void*>(&v),
  175. dest, sizeof(v));
  176. }
  177. return;
  178. }
  179. while(src != end)
  180. {
  181. access::construct_key_value_pair(
  182. dest, pilfer(src[0]), pilfer(src[1]));
  183. src += 2;
  184. auto& head = t_->bucket(dest->key());
  185. auto i = head;
  186. for(;;)
  187. {
  188. if(i == null_index_)
  189. {
  190. // end of bucket
  191. access::next(
  192. *dest) = head;
  193. head = static_cast<index_t>(
  194. dest - begin());
  195. ++dest;
  196. break;
  197. }
  198. auto& v = (*t_)[i];
  199. if(v.key() != dest->key())
  200. {
  201. i = access::next(v);
  202. continue;
  203. }
  204. // handle duplicate
  205. access::next(*dest) =
  206. access::next(v);
  207. // don't bother to check if
  208. // storage deallocate is trivial
  209. v.~key_value_pair();
  210. // trivial relocate
  211. std::memcpy(
  212. static_cast<void*>(&v),
  213. dest, sizeof(v));
  214. break;
  215. }
  216. }
  217. t_->size = static_cast<
  218. index_t>(dest - begin());
  219. }
  220. object::
  221. ~object()
  222. {
  223. if(sp_.is_not_shared_and_deallocate_is_trivial())
  224. return;
  225. if(t_->capacity == 0)
  226. return;
  227. destroy();
  228. }
  229. object::
  230. object(
  231. std::size_t min_capacity,
  232. storage_ptr sp)
  233. : sp_(std::move(sp))
  234. , t_(&empty_)
  235. {
  236. reserve(min_capacity);
  237. }
  238. object::
  239. object(object&& other) noexcept
  240. : sp_(other.sp_)
  241. , t_(detail::exchange(
  242. other.t_, &empty_))
  243. {
  244. }
  245. object::
  246. object(
  247. object&& other,
  248. storage_ptr sp)
  249. : sp_(std::move(sp))
  250. {
  251. if(*sp_ == *other.sp_)
  252. {
  253. t_ = detail::exchange(
  254. other.t_, &empty_);
  255. return;
  256. }
  257. t_ = &empty_;
  258. object(other, sp_).swap(*this);
  259. }
  260. object::
  261. object(
  262. object const& other,
  263. storage_ptr sp)
  264. : sp_(std::move(sp))
  265. , t_(&empty_)
  266. {
  267. reserve(other.size());
  268. revert_construct r(*this);
  269. if(t_->is_small())
  270. {
  271. for(auto const& v : other)
  272. {
  273. ::new(end())
  274. key_value_pair(v, sp_);
  275. ++t_->size;
  276. }
  277. r.commit();
  278. return;
  279. }
  280. for(auto const& v : other)
  281. {
  282. // skip duplicate checking
  283. auto& head =
  284. t_->bucket(v.key());
  285. auto pv = ::new(end())
  286. key_value_pair(v, sp_);
  287. access::next(*pv) = head;
  288. head = t_->size;
  289. ++t_->size;
  290. }
  291. r.commit();
  292. }
  293. object::
  294. object(
  295. std::initializer_list<std::pair<
  296. string_view, value_ref>> init,
  297. std::size_t min_capacity,
  298. storage_ptr sp)
  299. : sp_(std::move(sp))
  300. , t_(&empty_)
  301. {
  302. if( min_capacity < init.size())
  303. min_capacity = init.size();
  304. reserve(min_capacity);
  305. revert_construct r(*this);
  306. insert(init);
  307. r.commit();
  308. }
  309. //----------------------------------------------------------
  310. //
  311. // Assignment
  312. //
  313. //----------------------------------------------------------
  314. object&
  315. object::
  316. operator=(object const& other)
  317. {
  318. object tmp(other, sp_);
  319. this->~object();
  320. ::new(this) object(pilfer(tmp));
  321. return *this;
  322. }
  323. object&
  324. object::
  325. operator=(object&& other)
  326. {
  327. object tmp(std::move(other), sp_);
  328. this->~object();
  329. ::new(this) object(pilfer(tmp));
  330. return *this;
  331. }
  332. object&
  333. object::
  334. operator=(
  335. std::initializer_list<std::pair<
  336. string_view, value_ref>> init)
  337. {
  338. object tmp(init, sp_);
  339. this->~object();
  340. ::new(this) object(pilfer(tmp));
  341. return *this;
  342. }
  343. //----------------------------------------------------------
  344. //
  345. // Modifiers
  346. //
  347. //----------------------------------------------------------
  348. void
  349. object::
  350. clear() noexcept
  351. {
  352. if(empty())
  353. return;
  354. if(! sp_.is_not_shared_and_deallocate_is_trivial())
  355. destroy(begin(), end());
  356. if(! t_->is_small())
  357. t_->clear();
  358. t_->size = 0;
  359. }
  360. void
  361. object::
  362. insert(
  363. std::initializer_list<std::pair<
  364. string_view, value_ref>> init)
  365. {
  366. auto const n0 = size();
  367. if(init.size() > max_size() - n0)
  368. detail::throw_length_error(
  369. "object too large",
  370. BOOST_JSON_SOURCE_POS);
  371. reserve(n0 + init.size());
  372. revert_insert r(*this);
  373. if(t_->is_small())
  374. {
  375. for(auto& iv : init)
  376. {
  377. auto result =
  378. find_impl(iv.first);
  379. if(result.first)
  380. {
  381. // ignore duplicate
  382. continue;
  383. }
  384. ::new(end()) key_value_pair(
  385. iv.first,
  386. iv.second.make_value(sp_));
  387. ++t_->size;
  388. }
  389. r.commit();
  390. return;
  391. }
  392. for(auto& iv : init)
  393. {
  394. auto& head = t_->bucket(iv.first);
  395. auto i = head;
  396. for(;;)
  397. {
  398. if(i == null_index_)
  399. {
  400. // VFALCO value_ref should construct
  401. // a key_value_pair using placement
  402. auto& v = *::new(end())
  403. key_value_pair(
  404. iv.first,
  405. iv.second.make_value(sp_));
  406. access::next(v) = head;
  407. head = static_cast<index_t>(
  408. t_->size);
  409. ++t_->size;
  410. break;
  411. }
  412. auto& v = (*t_)[i];
  413. if(v.key() == iv.first)
  414. {
  415. // ignore duplicate
  416. break;
  417. }
  418. i = access::next(v);
  419. }
  420. }
  421. r.commit();
  422. }
  423. auto
  424. object::
  425. erase(const_iterator pos) noexcept ->
  426. iterator
  427. {
  428. auto p = begin() + (pos - begin());
  429. if(t_->is_small())
  430. {
  431. p->~value_type();
  432. --t_->size;
  433. auto const pb = end();
  434. if(p != end())
  435. {
  436. // the casts silence warnings
  437. std::memcpy(
  438. static_cast<void*>(p),
  439. static_cast<void const*>(pb),
  440. sizeof(*p));
  441. }
  442. return p;
  443. }
  444. remove(t_->bucket(p->key()), *p);
  445. p->~value_type();
  446. --t_->size;
  447. auto const pb = end();
  448. if(p != end())
  449. {
  450. auto& head = t_->bucket(pb->key());
  451. remove(head, *pb);
  452. // the casts silence warnings
  453. std::memcpy(
  454. static_cast<void*>(p),
  455. static_cast<void const*>(pb),
  456. sizeof(*p));
  457. access::next(*p) = head;
  458. head = static_cast<
  459. index_t>(p - begin());
  460. }
  461. return p;
  462. }
  463. auto
  464. object::
  465. erase(string_view key) noexcept ->
  466. std::size_t
  467. {
  468. auto it = find(key);
  469. if(it == end())
  470. return 0;
  471. erase(it);
  472. return 1;
  473. }
  474. void
  475. object::
  476. swap(object& other)
  477. {
  478. if(*sp_ == *other.sp_)
  479. {
  480. t_ = detail::exchange(
  481. other.t_, t_);
  482. return;
  483. }
  484. object temp1(
  485. std::move(*this),
  486. other.storage());
  487. object temp2(
  488. std::move(other),
  489. this->storage());
  490. other.~object();
  491. ::new(&other) object(pilfer(temp1));
  492. this->~object();
  493. ::new(this) object(pilfer(temp2));
  494. }
  495. //----------------------------------------------------------
  496. //
  497. // Lookup
  498. //
  499. //----------------------------------------------------------
  500. auto
  501. object::
  502. operator[](string_view key) ->
  503. value&
  504. {
  505. auto const result =
  506. emplace(key, nullptr);
  507. return result.first->value();
  508. }
  509. auto
  510. object::
  511. count(string_view key) const noexcept ->
  512. std::size_t
  513. {
  514. if(find(key) == end())
  515. return 0;
  516. return 1;
  517. }
  518. auto
  519. object::
  520. find(string_view key) noexcept ->
  521. iterator
  522. {
  523. if(empty())
  524. return end();
  525. auto const p =
  526. find_impl(key).first;
  527. if(p)
  528. return p;
  529. return end();
  530. }
  531. auto
  532. object::
  533. find(string_view key) const noexcept ->
  534. const_iterator
  535. {
  536. if(empty())
  537. return end();
  538. auto const p =
  539. find_impl(key).first;
  540. if(p)
  541. return p;
  542. return end();
  543. }
  544. bool
  545. object::
  546. contains(
  547. string_view key) const noexcept
  548. {
  549. if(empty())
  550. return false;
  551. return find_impl(
  552. key).first != nullptr;
  553. }
  554. value const*
  555. object::
  556. if_contains(
  557. string_view key) const noexcept
  558. {
  559. auto const it = find(key);
  560. if(it != end())
  561. return &it->value();
  562. return nullptr;
  563. }
  564. value*
  565. object::
  566. if_contains(
  567. string_view key) noexcept
  568. {
  569. auto const it = find(key);
  570. if(it != end())
  571. return &it->value();
  572. return nullptr;
  573. }
  574. //----------------------------------------------------------
  575. //
  576. // (private)
  577. //
  578. //----------------------------------------------------------
  579. auto
  580. object::
  581. find_impl(
  582. string_view key) const noexcept ->
  583. std::pair<
  584. key_value_pair*,
  585. std::size_t>
  586. {
  587. BOOST_ASSERT(t_->capacity > 0);
  588. if(t_->is_small())
  589. {
  590. auto it = &(*t_)[0];
  591. auto const last =
  592. &(*t_)[t_->size];
  593. for(;it != last; ++it)
  594. if(key == it->key())
  595. return { it, 0 };
  596. return { nullptr, 0 };
  597. }
  598. std::pair<
  599. key_value_pair*,
  600. std::size_t> result;
  601. result.second = t_->digest(key);
  602. auto i = t_->bucket(
  603. result.second);
  604. while(i != null_index_)
  605. {
  606. auto& v = (*t_)[i];
  607. if(v.key() == key)
  608. {
  609. result.first = &v;
  610. return result;
  611. }
  612. i = access::next(v);
  613. }
  614. result.first = nullptr;
  615. return result;
  616. }
  617. auto
  618. object::
  619. insert_impl(
  620. pilfered<key_value_pair> p) ->
  621. std::pair<iterator, bool>
  622. {
  623. // caller is responsible
  624. // for preventing aliasing.
  625. reserve(size() + 1);
  626. auto const result =
  627. find_impl(p.get().key());
  628. if(result.first)
  629. return { result.first, false };
  630. return { insert_impl(
  631. p, result.second), true };
  632. }
  633. key_value_pair*
  634. object::
  635. insert_impl(
  636. pilfered<key_value_pair> p,
  637. std::size_t hash)
  638. {
  639. BOOST_ASSERT(
  640. capacity() > size());
  641. if(t_->is_small())
  642. {
  643. auto const pv = ::new(end())
  644. key_value_pair(p);
  645. ++t_->size;
  646. return pv;
  647. }
  648. auto& head =
  649. t_->bucket(hash);
  650. auto const pv = ::new(end())
  651. key_value_pair(p);
  652. access::next(*pv) = head;
  653. head = t_->size;
  654. ++t_->size;
  655. return pv;
  656. }
  657. // rehash to at least `n` buckets
  658. void
  659. object::
  660. rehash(std::size_t new_capacity)
  661. {
  662. BOOST_ASSERT(
  663. new_capacity > t_->capacity);
  664. auto t = table::allocate(
  665. growth(new_capacity),
  666. t_->salt, sp_);
  667. if(! empty())
  668. std::memcpy(
  669. static_cast<
  670. void*>(&(*t)[0]),
  671. begin(),
  672. size() * sizeof(
  673. key_value_pair));
  674. t->size = t_->size;
  675. table::deallocate(t_, sp_);
  676. t_ = t;
  677. if(! t_->is_small())
  678. {
  679. // rebuild hash table,
  680. // without dup checks
  681. auto p = end();
  682. index_t i = t_->size;
  683. while(i-- > 0)
  684. {
  685. --p;
  686. auto& head =
  687. t_->bucket(p->key());
  688. access::next(*p) = head;
  689. head = i;
  690. }
  691. }
  692. }
  693. bool
  694. object::
  695. equal(object const& other) const noexcept
  696. {
  697. if(size() != other.size())
  698. return false;
  699. auto const end_ = other.end();
  700. for(auto e : *this)
  701. {
  702. auto it = other.find(e.key());
  703. if(it == end_)
  704. return false;
  705. if(it->value() != e.value())
  706. return false;
  707. }
  708. return true;
  709. }
  710. std::size_t
  711. object::
  712. growth(
  713. std::size_t new_size) const
  714. {
  715. if(new_size > max_size())
  716. detail::throw_length_error(
  717. "object too large",
  718. BOOST_JSON_SOURCE_POS);
  719. std::size_t const old = capacity();
  720. if(old > max_size() - old / 2)
  721. return new_size;
  722. std::size_t const g =
  723. old + old / 2; // 1.5x
  724. if(g < new_size)
  725. return new_size;
  726. return g;
  727. }
  728. void
  729. object::
  730. remove(
  731. index_t& head,
  732. key_value_pair& v) noexcept
  733. {
  734. BOOST_ASSERT(! t_->is_small());
  735. auto const i = static_cast<
  736. index_t>(&v - begin());
  737. if(head == i)
  738. {
  739. head = access::next(v);
  740. return;
  741. }
  742. auto* pn =
  743. &access::next((*t_)[head]);
  744. while(*pn != i)
  745. pn = &access::next((*t_)[*pn]);
  746. *pn = access::next(v);
  747. }
  748. void
  749. object::
  750. destroy() noexcept
  751. {
  752. BOOST_ASSERT(t_->capacity > 0);
  753. BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial());
  754. destroy(begin(), end());
  755. table::deallocate(t_, sp_);
  756. }
  757. void
  758. object::
  759. destroy(
  760. key_value_pair* first,
  761. key_value_pair* last) noexcept
  762. {
  763. BOOST_ASSERT(! sp_.is_not_shared_and_deallocate_is_trivial());
  764. while(last != first)
  765. (--last)->~key_value_pair();
  766. }
  767. BOOST_JSON_NS_END
  768. #endif