2 // Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com)
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)
7 // Official repository: https://github.com/boostorg/json
10 #ifndef BOOST_JSON_IMPL_ARRAY_IPP
11 #define BOOST_JSON_IMPL_ARRAY_IPP
13 #include <boost/json/array.hpp>
14 #include <boost/json/pilfer.hpp>
15 #include <boost/json/detail/except.hpp>
23 //----------------------------------------------------------
25 constexpr array::table::table() = default;
27 // empty arrays point here
28 BOOST_JSON_REQUIRE_CONST_INIT
29 array::table array::empty_;
36 storage_ptr const& sp) ->
39 BOOST_ASSERT(capacity > 0);
40 if(capacity > array::max_size())
41 detail::throw_length_error(
43 BOOST_CURRENT_LOCATION);
44 auto p = reinterpret_cast<
47 capacity * sizeof(value),
49 p->capacity = static_cast<
50 std::uint32_t>(capacity);
59 storage_ptr const& sp)
65 p->capacity * sizeof(value),
69 //----------------------------------------------------------
78 , i_(pos - arr_->data())
82 pos >= arr_->begin() &&
84 if( n_ <= arr_->capacity() -
88 p = arr_->data() + i_;
95 arr_->t_->size = static_cast<
100 if(n_ > max_size() - arr_->size())
101 detail::throw_length_error(
103 BOOST_CURRENT_LOCATION);
104 auto t = table::allocate(
105 arr_->growth(arr_->size() + n_),
107 t->size = static_cast<std::uint32_t>(
118 t = detail::exchange(arr_->t_, t);
119 table::deallocate(t, arr_->sp_);
128 BOOST_ASSERT(n_ != 0);
131 arr_->destroy(pos, p);
132 arr_->t_->size = static_cast<
134 arr_->t_->size - n_);
141 //----------------------------------------------------------
146 value* first, value* last) noexcept
148 if(sp_.is_not_shared_and_deallocate_is_trivial())
150 while(last-- != first)
158 if(sp_.is_not_shared_and_deallocate_is_trivial())
161 auto const first = begin();
162 while(last-- != first)
164 table::deallocate(t_, sp_);
167 //----------------------------------------------------------
171 //----------------------------------------------------------
174 array(detail::unchecked_array&& ua)
178 alignof(table) == alignof(value));
186 t_->size = static_cast<
187 std::uint32_t>(ua.size());
212 revert_construct r(*this);
215 ::new(end()) value(v, sp_);
232 t_ = table::allocate(
234 t_->size = static_cast<
235 std::uint32_t>(count);
239 ::new(p++) value(sp_);
245 array(array const& other)
246 : array(other, other.sp_)
261 t_ = table::allocate(
264 revert_construct r(*this);
265 auto src = other.data();
267 auto const n = other.size();
284 if(*sp_ == *other.sp_)
287 t_ = detail::exchange(
291 else if(other.empty())
297 t_ = table::allocate(
300 revert_construct r(*this);
301 auto src = other.data();
303 auto const n = other.size();
316 std::initializer_list<
326 t_ = table::allocate(
329 revert_construct r(*this);
330 value_ref::write_array(
332 t_->size = static_cast<
333 std::uint32_t>(init.size());
337 //----------------------------------------------------------
341 operator=(array const& other)
344 storage()).swap(*this);
350 operator=(array&& other)
352 array(std::move(other),
353 storage()).swap(*this);
360 std::initializer_list<value_ref> init)
363 storage()).swap(*this);
367 //----------------------------------------------------------
371 //----------------------------------------------------------
375 shrink_to_fit() noexcept
377 if(capacity() <= size())
381 table::deallocate(t_, sp_);
386 #ifndef BOOST_NO_EXCEPTIONS
390 auto t = table::allocate(
396 t->size = static_cast<
397 std::uint32_t>(size());
398 t = detail::exchange(
400 table::deallocate(t, sp_);
401 #ifndef BOOST_NO_EXCEPTIONS
411 //----------------------------------------------------------
415 //----------------------------------------------------------
435 return emplace(pos, v);
445 return emplace(pos, std::move(v));
460 ::new(r.p) value(v, sp_);
470 std::initializer_list<
475 pos, init.size(), *this);
476 value_ref::write_array(
484 const_iterator pos) noexcept ->
490 auto const p = &(*t_)[0] +
493 relocate(p, p + 1, 1);
501 const_iterator first,
502 const_iterator last) noexcept ->
505 std::size_t const n =
507 auto const p = &(*t_)[0] +
513 t_->size = static_cast<
514 std::uint32_t>(t_->size - n);
520 push_back(value const& v)
529 emplace_back(std::move(v));
536 auto const p = &back();
543 resize(std::size_t count)
545 if(count <= t_->size)
550 &(*t_)[0] + t_->size);
551 t_->size = static_cast<
552 std::uint32_t>(count);
557 auto p = &(*t_)[t_->size];
558 auto const end = &(*t_)[count];
560 ::new(p++) value(sp_);
561 t_->size = static_cast<
562 std::uint32_t>(count);
577 t_->size = static_cast<
578 std::uint32_t>(count);
583 end(), count, *this);
586 ::new(r.p) value(v, sp_);
596 BOOST_ASSERT(this != &other);
597 if(*sp_ == *other.sp_)
599 t_ = detail::exchange(
617 //----------------------------------------------------------
621 //----------------------------------------------------------
626 std::size_t new_size) const
628 if(new_size > max_size())
629 detail::throw_length_error(
631 BOOST_CURRENT_LOCATION);
632 std::size_t const old = capacity();
633 if(old > max_size() - old / 2)
635 std::size_t const g =
636 old + old / 2; // 1.5x
642 // precondition: new_capacity > capacity()
646 std::size_t new_capacity)
649 new_capacity > t_->capacity);
650 auto t = table::allocate(
651 growth(new_capacity), sp_);
657 t = detail::exchange(t_, t);
658 table::deallocate(t, sp_);
661 // precondition: pv is not aliased
667 auto const n = t_->size;
672 &(*t_)[n]) value(pv);
682 &(*t_)[n]) value(pv);
688 table::deallocate(t, sp_);
692 // precondition: pv is not aliased
697 pilfered<value> pv) ->
703 std::size_t const n =
705 std::size_t const i =
723 auto const p = &(*t)[i];
733 t->size = static_cast<
734 std::uint32_t>(size() + 1);
735 t = detail::exchange(t_, t);
736 table::deallocate(t, sp_);
740 //----------------------------------------------------------
745 array const& other) const noexcept
747 if(size() != other.size())
749 for(std::size_t i = 0; i < size(); ++i)
750 if((*this)[i] != other[i])