LCOV - code coverage report
Current view: top level - json/impl - array.ipp (source / functions) Coverage Total Hit
Test: coverage_remapped.info Lines: 100.0 % 391 391
Test Date: 2026-07-07 07:42:51 Functions: 100.0 % 40 40

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

Generated by: LCOV version 2.3