123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757 |
- //
- // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
- //
- // Distributed under the Boost Software License, Version 1.0. (See accompanying
- // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- //
- // Official repository: https://github.com/boostorg/json
- //
- #ifndef BOOST_JSON_IMPL_ARRAY_IPP
- #define BOOST_JSON_IMPL_ARRAY_IPP
- #include <boost/json/array.hpp>
- #include <boost/json/pilfer.hpp>
- #include <boost/json/detail/except.hpp>
- #include <cstdlib>
- #include <limits>
- #include <new>
- #include <utility>
- BOOST_JSON_NS_BEGIN
- //----------------------------------------------------------
- constexpr array::table::table() = default;
- // empty arrays point here
- BOOST_JSON_REQUIRE_CONST_INIT
- array::table array::empty_;
- auto
- array::
- table::
- allocate(
- std::size_t capacity,
- storage_ptr const& sp) ->
- table*
- {
- BOOST_ASSERT(capacity > 0);
- if(capacity > array::max_size())
- detail::throw_length_error(
- "array too large",
- BOOST_JSON_SOURCE_POS);
- auto p = reinterpret_cast<
- table*>(sp->allocate(
- sizeof(table) +
- capacity * sizeof(value),
- alignof(value)));
- p->capacity = static_cast<
- std::uint32_t>(capacity);
- return p;
- }
- void
- array::
- table::
- deallocate(
- table* p,
- storage_ptr const& sp)
- {
- if(p->capacity == 0)
- return;
- sp->deallocate(p,
- sizeof(table) +
- p->capacity * sizeof(value),
- alignof(value));
- }
- //----------------------------------------------------------
- array::
- revert_insert::
- revert_insert(
- const_iterator pos,
- std::size_t n,
- array& arr)
- : arr_(&arr)
- , i_(pos - arr_->data())
- , n_(n)
- {
- BOOST_ASSERT(
- pos >= arr_->begin() &&
- pos <= arr_->end());
- if( n_ <= arr_->capacity() -
- arr_->size())
- {
- // fast path
- p = arr_->data() + i_;
- if(n_ == 0)
- return;
- relocate(
- p + n_,
- p,
- arr_->size() - i_);
- arr_->t_->size = static_cast<
- std::uint32_t>(
- arr_->t_->size + n_);
- return;
- }
- if(n_ > max_size() - arr_->size())
- detail::throw_length_error(
- "array too large",
- BOOST_JSON_SOURCE_POS);
- auto t = table::allocate(
- arr_->growth(arr_->size() + n_),
- arr_->sp_);
- t->size = static_cast<std::uint32_t>(
- arr_->size() + n_);
- p = &(*t)[0] + i_;
- relocate(
- &(*t)[0],
- arr_->data(),
- i_);
- relocate(
- &(*t)[i_ + n_],
- arr_->data() + i_,
- arr_->size() - i_);
- t = detail::exchange(arr_->t_, t);
- table::deallocate(t, arr_->sp_);
- }
- array::
- revert_insert::
- ~revert_insert()
- {
- if(! arr_)
- return;
- BOOST_ASSERT(n_ != 0);
- auto const pos =
- arr_->data() + i_;
- arr_->destroy(pos, p);
- arr_->t_->size = static_cast<
- std::uint32_t>(
- arr_->t_->size - n_);
- relocate(
- pos,
- pos + n_,
- arr_->size() - i_);
- }
- //----------------------------------------------------------
- void
- array::
- destroy(
- value* first, value* last) noexcept
- {
- if(sp_.is_not_shared_and_deallocate_is_trivial())
- return;
- while(last-- != first)
- last->~value();
- }
- void
- array::
- destroy() noexcept
- {
- if(sp_.is_not_shared_and_deallocate_is_trivial())
- return;
- auto last = end();
- auto const first = begin();
- while(last-- != first)
- last->~value();
- table::deallocate(t_, sp_);
- }
- //----------------------------------------------------------
- //
- // Special Members
- //
- //----------------------------------------------------------
- array::
- array(detail::unchecked_array&& ua)
- : sp_(ua.storage())
- {
- BOOST_STATIC_ASSERT(
- alignof(table) == alignof(value));
- if(ua.size() == 0)
- {
- t_ = &empty_;
- return;
- }
- t_= table::allocate(
- ua.size(), sp_);
- t_->size = static_cast<
- std::uint32_t>(ua.size());
- ua.relocate(data());
- }
- array::
- ~array()
- {
- destroy();
- }
- array::
- array(
- std::size_t count,
- value const& v,
- storage_ptr sp)
- : sp_(std::move(sp))
- {
- if(count == 0)
- {
- t_ = &empty_;
- return;
- }
- t_= table::allocate(
- count, sp_);
- t_->size = 0;
- revert_construct r(*this);
- while(count--)
- {
- ::new(end()) value(v, sp_);
- ++t_->size;
- }
- r.commit();
- }
- array::
- array(
- std::size_t count,
- storage_ptr sp)
- : sp_(std::move(sp))
- {
- if(count == 0)
- {
- t_ = &empty_;
- return;
- }
- t_ = table::allocate(
- count, sp_);
- t_->size = static_cast<
- std::uint32_t>(count);
- auto p = data();
- do
- {
- ::new(p++) value(sp_);
- }
- while(--count);
- }
- array::
- array(array const& other)
- : array(other, other.sp_)
- {
- }
- array::
- array(
- array const& other,
- storage_ptr sp)
- : sp_(std::move(sp))
- {
- if(other.empty())
- {
- t_ = &empty_;
- return;
- }
- t_ = table::allocate(
- other.size(), sp_);
- t_->size = 0;
- revert_construct r(*this);
- auto src = other.data();
- auto dest = data();
- auto const n = other.size();
- do
- {
- ::new(dest++) value(
- *src++, sp_);
- ++t_->size;
- }
- while(t_->size < n);
- r.commit();
- }
- array::
- array(
- array&& other,
- storage_ptr sp)
- : sp_(std::move(sp))
- {
- if(*sp_ == *other.sp_)
- {
- // same resource
- t_ = detail::exchange(
- other.t_, &empty_);
- return;
- }
- else if(other.empty())
- {
- t_ = &empty_;
- return;
- }
- // copy
- t_ = table::allocate(
- other.size(), sp_);
- t_->size = 0;
- revert_construct r(*this);
- auto src = other.data();
- auto dest = data();
- auto const n = other.size();
- do
- {
- ::new(dest++) value(
- *src++, sp_);
- ++t_->size;
- }
- while(t_->size < n);
- r.commit();
- }
- array::
- array(
- std::initializer_list<
- value_ref> init,
- storage_ptr sp)
- : sp_(std::move(sp))
- {
- if(init.size() == 0)
- {
- t_ = &empty_;
- return;
- }
- t_ = table::allocate(
- init.size(), sp_);
- t_->size = 0;
- revert_construct r(*this);
- value_ref::write_array(
- data(), init, sp_);
- t_->size = static_cast<
- std::uint32_t>(init.size());
- r.commit();
- }
- //----------------------------------------------------------
- array&
- array::
- operator=(array const& other)
- {
- array(other,
- storage()).swap(*this);
- return *this;
- }
- array&
- array::
- operator=(array&& other)
- {
- array(std::move(other),
- storage()).swap(*this);
- return *this;
- }
- array&
- array::
- operator=(
- std::initializer_list<value_ref> init)
- {
- array(init,
- storage()).swap(*this);
- return *this;
- }
- //----------------------------------------------------------
- //
- // Capacity
- //
- //----------------------------------------------------------
- void
- array::
- shrink_to_fit() noexcept
- {
- if(capacity() <= size())
- return;
- if(size() == 0)
- {
- table::deallocate(t_, sp_);
- t_ = &empty_;
- return;
- }
- #ifndef BOOST_NO_EXCEPTIONS
- try
- {
- #endif
- auto t = table::allocate(
- size(), sp_);
- relocate(
- &(*t)[0],
- data(),
- size());
- t->size = static_cast<
- std::uint32_t>(size());
- t = detail::exchange(
- t_, t);
- table::deallocate(t, sp_);
- #ifndef BOOST_NO_EXCEPTIONS
- }
- catch(...)
- {
- // eat the exception
- return;
- }
- #endif
- }
- //----------------------------------------------------------
- //
- // Modifiers
- //
- //----------------------------------------------------------
- void
- array::
- clear() noexcept
- {
- if(size() == 0)
- return;
- destroy(
- begin(), end());
- t_->size = 0;
- }
- auto
- array::
- insert(
- const_iterator pos,
- value const& v) ->
- iterator
- {
- return emplace(pos, v);
- }
- auto
- array::
- insert(
- const_iterator pos,
- value&& v) ->
- iterator
- {
- return emplace(pos, std::move(v));
- }
- auto
- array::
- insert(
- const_iterator pos,
- std::size_t count,
- value const& v) ->
- iterator
- {
- revert_insert r(
- pos, count, *this);
- while(count--)
- {
- ::new(r.p) value(v, sp_);
- ++r.p;
- }
- return r.commit();
- }
- auto
- array::
- insert(
- const_iterator pos,
- std::initializer_list<
- value_ref> init) ->
- iterator
- {
- revert_insert r(
- pos, init.size(), *this);
- value_ref::write_array(
- r.p, init, sp_);
- return r.commit();
- }
- auto
- array::
- erase(
- const_iterator pos) noexcept ->
- iterator
- {
- BOOST_ASSERT(
- pos >= begin() &&
- pos <= end());
- auto const p = &(*t_)[0] +
- (pos - &(*t_)[0]);
- destroy(p, p + 1);
- relocate(p, p + 1, 1);
- --t_->size;
- return p;
- }
- auto
- array::
- erase(
- const_iterator first,
- const_iterator last) noexcept ->
- iterator
- {
- std::size_t const n =
- last - first;
- auto const p = &(*t_)[0] +
- (first - &(*t_)[0]);
- destroy(p, p + n);
- relocate(p, p + n,
- t_->size - (last -
- &(*t_)[0]));
- t_->size = static_cast<
- std::uint32_t>(t_->size - n);
- return p;
- }
- void
- array::
- push_back(value const& v)
- {
- emplace_back(v);
- }
- void
- array::
- push_back(value&& v)
- {
- emplace_back(std::move(v));
- }
- void
- array::
- pop_back() noexcept
- {
- auto const p = &back();
- destroy(p, p + 1);
- --t_->size;
- }
- void
- array::
- resize(std::size_t count)
- {
- if(count <= t_->size)
- {
- // shrink
- destroy(
- &(*t_)[0] + count,
- &(*t_)[0] + t_->size);
- t_->size = static_cast<
- std::uint32_t>(count);
- return;
- }
- reserve(count);
- auto p = &(*t_)[t_->size];
- auto const end = &(*t_)[count];
- while(p != end)
- ::new(p++) value(sp_);
- t_->size = static_cast<
- std::uint32_t>(count);
- }
- void
- array::
- resize(
- std::size_t count,
- value const& v)
- {
- if(count <= size())
- {
- // shrink
- destroy(
- data() + count,
- data() + size());
- t_->size = static_cast<
- std::uint32_t>(count);
- return;
- }
- count -= size();
- revert_insert r(
- end(), count, *this);
- while(count--)
- {
- ::new(r.p) value(v, sp_);
- ++r.p;
- }
- r.commit();
- }
- void
- array::
- swap(array& other)
- {
- BOOST_ASSERT(this != &other);
- if(*sp_ == *other.sp_)
- {
- t_ = detail::exchange(
- other.t_, t_);
- return;
- }
- array temp1(
- std::move(*this),
- other.storage());
- array temp2(
- std::move(other),
- this->storage());
- this->~array();
- ::new(this) array(
- pilfer(temp2));
- other.~array();
- ::new(&other) array(
- pilfer(temp1));
- }
- //----------------------------------------------------------
- //
- // Private
- //
- //----------------------------------------------------------
- std::size_t
- array::
- growth(
- std::size_t new_size) const
- {
- if(new_size > max_size())
- detail::throw_length_error(
- "array too large",
- BOOST_JSON_SOURCE_POS);
- std::size_t const old = capacity();
- if(old > max_size() - old / 2)
- return new_size;
- std::size_t const g =
- old + old / 2; // 1.5x
- if(g < new_size)
- return new_size;
- return g;
- }
- // precondition: new_capacity > capacity()
- void
- array::
- reserve_impl(
- std::size_t new_capacity)
- {
- BOOST_ASSERT(
- new_capacity > t_->capacity);
- auto t = table::allocate(
- growth(new_capacity), sp_);
- relocate(
- &(*t)[0],
- &(*t_)[0],
- t_->size);
- t->size = t_->size;
- t = detail::exchange(t_, t);
- table::deallocate(t, sp_);
- }
- // precondition: pv is not aliased
- value&
- array::
- push_back(
- pilfered<value> pv)
- {
- auto const n = t_->size;
- if(n < t_->capacity)
- {
- // fast path
- auto& v = *::new(
- &(*t_)[n]) value(pv);
- ++t_->size;
- return v;
- }
- auto const t =
- detail::exchange(t_,
- table::allocate(
- growth(n + 1),
- sp_));
- auto& v = *::new(
- &(*t_)[n]) value(pv);
- relocate(
- &(*t_)[0],
- &(*t)[0],
- n);
- t_->size = n + 1;
- table::deallocate(t, sp_);
- return v;
- }
- // precondition: pv is not aliased
- auto
- array::
- insert(
- const_iterator pos,
- pilfered<value> pv) ->
- iterator
- {
- BOOST_ASSERT(
- pos >= begin() &&
- pos <= end());
- std::size_t const n =
- t_->size;
- std::size_t const i =
- pos - &(*t_)[0];
- if(n < t_->capacity)
- {
- // fast path
- auto const p =
- &(*t_)[i];
- relocate(
- p + 1,
- p,
- n - i);
- ::new(p) value(pv);
- ++t_->size;
- return p;
- }
- auto t =
- table::allocate(
- growth(n + 1), sp_);
- auto const p = &(*t)[i];
- ::new(p) value(pv);
- relocate(
- &(*t)[0],
- &(*t_)[0],
- i);
- relocate(
- p + 1,
- &(*t_)[i],
- n - i);
- t->size = static_cast<
- std::uint32_t>(size() + 1);
- t = detail::exchange(t_, t);
- table::deallocate(t, sp_);
- return p;
- }
- //----------------------------------------------------------
- bool
- array::
- equal(
- array const& other) const noexcept
- {
- if(size() != other.size())
- return false;
- for(std::size_t i = 0; i < size(); ++i)
- if((*this)[i] != other[i])
- return false;
- return true;
- }
- BOOST_JSON_NS_END
- #endif
|