Implemented P0084R2 (Emplace Return Type)

This commit is contained in:
Ion Gaztañaga
2016-08-29 16:53:44 +02:00
parent 9f9fdeaa9a
commit 0617d0e538
8 changed files with 79 additions and 41 deletions

View File

@@ -1234,6 +1234,8 @@ use [*Boost.Container]? There are several reasons for that:
* Implemented C++17 `insert_or_assign`/`try_emplace` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map]. * Implemented C++17 `insert_or_assign`/`try_emplace` for [classref boost::container::map map] and [classref boost::container::flat_map flat_map].
* Implemented C++17 `extract`/`insert(node)` for [classref boost::container::map map], [classref boost::container::multimap multimap], * Implemented C++17 `extract`/`insert(node)` for [classref boost::container::map map], [classref boost::container::multimap multimap],
[classref boost::container::set set], [classref boost::container::multiset multiset]. [classref boost::container::set set], [classref boost::container::multiset multiset].
* Implemented C++17's [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0084r2.pdf P0084R2 Emplace Return Type]
in `deque`, `vector`, `stable_vector`, `small_vector`, `static_vector`, `list` and `slist`.
[endsect] [endsect]

View File

@@ -1348,44 +1348,52 @@ class deque : protected deque_base<Allocator>
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... in the beginning of the deque. //! std::forward<Args>(args)... in the beginning of the deque.
//! //!
//! <b>Returns</b>: A reference to the created object.
//!
//! <b>Throws</b>: If memory allocation throws or the in-place constructor throws. //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
//! //!
//! <b>Complexity</b>: Amortized constant time //! <b>Complexity</b>: Amortized constant time
template <class... Args> template <class... Args>
void emplace_front(BOOST_FWD_REF(Args)... args) reference emplace_front(BOOST_FWD_REF(Args)... args)
{ {
if(this->priv_push_front_simple_available()){ if(this->priv_push_front_simple_available()){
reference r = *this->priv_push_front_simple_pos();
allocator_traits_type::construct allocator_traits_type::construct
( this->alloc() ( this->alloc()
, this->priv_push_front_simple_pos() , this->priv_push_front_simple_pos()
, boost::forward<Args>(args)...); , boost::forward<Args>(args)...);
this->priv_push_front_simple_commit(); this->priv_push_front_simple_commit();
return r;
} }
else{ else{
typedef container_detail::insert_nonmovable_emplace_proxy<Allocator, iterator, Args...> type; typedef container_detail::insert_nonmovable_emplace_proxy<Allocator, iterator, Args...> type;
this->priv_insert_front_aux_impl(1, type(boost::forward<Args>(args)...)); return *this->priv_insert_front_aux_impl(1, type(boost::forward<Args>(args)...));
} }
} }
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... in the end of the deque. //! std::forward<Args>(args)... in the end of the deque.
//! //!
//! <b>Returns</b>: A reference to the created object.
//!
//! <b>Throws</b>: If memory allocation throws or the in-place constructor throws. //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
//! //!
//! <b>Complexity</b>: Amortized constant time //! <b>Complexity</b>: Amortized constant time
template <class... Args> template <class... Args>
void emplace_back(BOOST_FWD_REF(Args)... args) reference emplace_back(BOOST_FWD_REF(Args)... args)
{ {
if(this->priv_push_back_simple_available()){ if(this->priv_push_back_simple_available()){
reference r = *this->priv_push_back_simple_pos();
allocator_traits_type::construct allocator_traits_type::construct
( this->alloc() ( this->alloc()
, this->priv_push_back_simple_pos() , this->priv_push_back_simple_pos()
, boost::forward<Args>(args)...); , boost::forward<Args>(args)...);
this->priv_push_back_simple_commit(); this->priv_push_back_simple_commit();
return r;
} }
else{ else{
typedef container_detail::insert_nonmovable_emplace_proxy<Allocator, iterator, Args...> type; typedef container_detail::insert_nonmovable_emplace_proxy<Allocator, iterator, Args...> type;
this->priv_insert_back_aux_impl(1, type(boost::forward<Args>(args)...)); return *this->priv_insert_back_aux_impl(1, type(boost::forward<Args>(args)...));
} }
} }
@@ -1420,32 +1428,36 @@ class deque : protected deque_base<Allocator>
#define BOOST_CONTAINER_DEQUE_EMPLACE_CODE(N) \ #define BOOST_CONTAINER_DEQUE_EMPLACE_CODE(N) \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\
void emplace_front(BOOST_MOVE_UREF##N)\ reference emplace_front(BOOST_MOVE_UREF##N)\
{\ {\
if(priv_push_front_simple_available()){\ if(priv_push_front_simple_available()){\
reference r = *this->priv_push_front_simple_pos();\
allocator_traits_type::construct\ allocator_traits_type::construct\
( this->alloc(), this->priv_push_front_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ ( this->alloc(), this->priv_push_front_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
priv_push_front_simple_commit();\ priv_push_front_simple_commit();\
return r;\
}\ }\
else{\ else{\
typedef container_detail::insert_nonmovable_emplace_proxy##N\ typedef container_detail::insert_nonmovable_emplace_proxy##N\
<Allocator, iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\ <Allocator, iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\
priv_insert_front_aux_impl(1, type(BOOST_MOVE_FWD##N));\ return *priv_insert_front_aux_impl(1, type(BOOST_MOVE_FWD##N));\
}\ }\
}\ }\
\ \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N\
void emplace_back(BOOST_MOVE_UREF##N)\ reference emplace_back(BOOST_MOVE_UREF##N)\
{\ {\
if(priv_push_back_simple_available()){\ if(priv_push_back_simple_available()){\
reference r = *this->priv_push_back_simple_pos();\
allocator_traits_type::construct\ allocator_traits_type::construct\
( this->alloc(), this->priv_push_back_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ ( this->alloc(), this->priv_push_back_simple_pos() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
priv_push_back_simple_commit();\ priv_push_back_simple_commit();\
return r;\
}\ }\
else{\ else{\
typedef container_detail::insert_nonmovable_emplace_proxy##N\ typedef container_detail::insert_nonmovable_emplace_proxy##N\
<Allocator, iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\ <Allocator, iterator BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\
priv_insert_back_aux_impl(1, type(BOOST_MOVE_FWD##N));\ return *priv_insert_back_aux_impl(1, type(BOOST_MOVE_FWD##N));\
}\ }\
}\ }\
\ \

View File

@@ -709,24 +709,28 @@ class list
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... in the end of the list. //! std::forward<Args>(args)... in the end of the list.
//! //!
//! <b>Returns</b>: A reference to the created object.
//!
//! <b>Throws</b>: If memory allocation throws or //! <b>Throws</b>: If memory allocation throws or
//! T's in-place constructor throws. //! T's in-place constructor throws.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
template <class... Args> template <class... Args>
void emplace_back(BOOST_FWD_REF(Args)... args) reference emplace_back(BOOST_FWD_REF(Args)... args)
{ this->emplace(this->cend(), boost::forward<Args>(args)...); } { return *this->emplace(this->cend(), boost::forward<Args>(args)...); }
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... in the beginning of the list. //! std::forward<Args>(args)... in the beginning of the list.
//! //!
//! <b>Returns</b>: A reference to the created object.
//!
//! <b>Throws</b>: If memory allocation throws or //! <b>Throws</b>: If memory allocation throws or
//! T's in-place constructor throws. //! T's in-place constructor throws.
//! //!
//! <b>Complexity</b>: Constant //! <b>Complexity</b>: Constant
template <class... Args> template <class... Args>
void emplace_front(BOOST_FWD_REF(Args)... args) reference emplace_front(BOOST_FWD_REF(Args)... args)
{ this->emplace(this->cbegin(), boost::forward<Args>(args)...); } { return *this->emplace(this->cbegin(), boost::forward<Args>(args)...); }
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... before p. //! std::forward<Args>(args)... before p.
@@ -747,12 +751,12 @@ class list
#define BOOST_CONTAINER_LIST_EMPLACE_CODE(N) \ #define BOOST_CONTAINER_LIST_EMPLACE_CODE(N) \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
void emplace_back(BOOST_MOVE_UREF##N)\ reference emplace_back(BOOST_MOVE_UREF##N)\
{ this->emplace(this->cend() BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\ { return *this->emplace(this->cend() BOOST_MOVE_I##N BOOST_MOVE_FWD##N); }\
\ \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
void emplace_front(BOOST_MOVE_UREF##N)\ reference emplace_front(BOOST_MOVE_UREF##N)\
{ this->emplace(this->cbegin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\ { return *this->emplace(this->cbegin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\
\ \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
iterator emplace(const_iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ iterator emplace(const_iterator position BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\

View File

@@ -714,13 +714,15 @@ class slist
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... in the front of the list //! std::forward<Args>(args)... in the front of the list
//! //!
//! <b>Returns</b>: A reference to the created object.
//!
//! <b>Throws</b>: If memory allocation throws or //! <b>Throws</b>: If memory allocation throws or
//! T's copy constructor throws. //! T's copy constructor throws.
//! //!
//! <b>Complexity</b>: Amortized constant time. //! <b>Complexity</b>: Amortized constant time.
template <class... Args> template <class... Args>
void emplace_front(BOOST_FWD_REF(Args)... args) reference emplace_front(BOOST_FWD_REF(Args)... args)
{ this->emplace_after(this->cbefore_begin(), boost::forward<Args>(args)...); } { return *this->emplace_after(this->cbefore_begin(), boost::forward<Args>(args)...); }
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... after prev //! std::forward<Args>(args)... after prev
@@ -740,8 +742,8 @@ class slist
#define BOOST_CONTAINER_SLIST_EMPLACE_CODE(N) \ #define BOOST_CONTAINER_SLIST_EMPLACE_CODE(N) \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
void emplace_front(BOOST_MOVE_UREF##N)\ reference emplace_front(BOOST_MOVE_UREF##N)\
{ this->emplace_after(this->cbefore_begin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\ { return *this->emplace_after(this->cbefore_begin() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);}\
\ \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
iterator emplace_after(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\ iterator emplace_after(const_iterator p BOOST_MOVE_I##N BOOST_MOVE_UREF##N)\

View File

@@ -1374,16 +1374,18 @@ class stable_vector
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... in the end of the stable_vector. //! std::forward<Args>(args)... in the end of the stable_vector.
//! //!
//! <b>Returns</b>: A reference to the created object.
//!
//! <b>Throws</b>: If memory allocation throws or the in-place constructor throws. //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws.
//! //!
//! <b>Complexity</b>: Amortized constant time. //! <b>Complexity</b>: Amortized constant time.
template<class ...Args> template<class ...Args>
void emplace_back(Args &&...args) reference emplace_back(Args &&...args)
{ {
typedef emplace_functor<Args...> EmplaceFunctor; typedef emplace_functor<Args...> EmplaceFunctor;
typedef emplace_iterator<value_type, EmplaceFunctor, difference_type> EmplaceIterator; typedef emplace_iterator<value_type, EmplaceFunctor, difference_type> EmplaceIterator;
EmplaceFunctor &&ef = EmplaceFunctor(boost::forward<Args>(args)...); EmplaceFunctor &&ef = EmplaceFunctor(boost::forward<Args>(args)...);
this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator()); return *this->insert(this->cend(), EmplaceIterator(ef), EmplaceIterator());
} }
//! <b>Requires</b>: p must be a valid iterator of *this. //! <b>Requires</b>: p must be a valid iterator of *this.
@@ -1411,13 +1413,13 @@ class stable_vector
#define BOOST_CONTAINER_STABLE_VECTOR_EMPLACE_CODE(N) \ #define BOOST_CONTAINER_STABLE_VECTOR_EMPLACE_CODE(N) \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
void emplace_back(BOOST_MOVE_UREF##N)\ reference emplace_back(BOOST_MOVE_UREF##N)\
{\ {\
typedef emplace_functor##N\ typedef emplace_functor##N\
BOOST_MOVE_LT##N BOOST_MOVE_TARG##N BOOST_MOVE_GT##N EmplaceFunctor;\ BOOST_MOVE_LT##N BOOST_MOVE_TARG##N BOOST_MOVE_GT##N EmplaceFunctor;\
typedef emplace_iterator<value_type, EmplaceFunctor, difference_type> EmplaceIterator;\ typedef emplace_iterator<value_type, EmplaceFunctor, difference_type> EmplaceIterator;\
EmplaceFunctor ef BOOST_MOVE_LP##N BOOST_MOVE_FWD##N BOOST_MOVE_RP##N;\ EmplaceFunctor ef BOOST_MOVE_LP##N BOOST_MOVE_FWD##N BOOST_MOVE_RP##N;\
this->insert(this->cend() , EmplaceIterator(ef), EmplaceIterator());\ return *this->insert(this->cend() , EmplaceIterator(ef), EmplaceIterator());\
}\ }\
\ \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \

View File

@@ -677,6 +677,8 @@ public:
//! @brief Inserts a Value constructed with //! @brief Inserts a Value constructed with
//! \c std::forward<Args>(args)... in the end of the container. //! \c std::forward<Args>(args)... in the end of the container.
//! //!
//! @return A reference to the created object.
//!
//! @param args The arguments of the constructor of the new element which will be created at the end of the container. //! @param args The arguments of the constructor of the new element which will be created at the end of the container.
//! //!
//! @par Throws //! @par Throws
@@ -685,7 +687,7 @@ public:
//! @par Complexity //! @par Complexity
//! Constant O(1). //! Constant O(1).
template<class ...Args> template<class ...Args>
void emplace_back(Args &&...args); reference emplace_back(Args &&...args);
//! @pre //! @pre
//! @li \c p must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt> //! @li \c p must be a valid iterator of \c *this in range <tt>[begin(), end()]</tt>

View File

@@ -1724,21 +1724,24 @@ class vector
//! <b>Effects</b>: Inserts an object of type T constructed with //! <b>Effects</b>: Inserts an object of type T constructed with
//! std::forward<Args>(args)... in the end of the vector. //! std::forward<Args>(args)... in the end of the vector.
//! //!
//! <b>Returns</b>: A reference to the created object.
//!
//! <b>Throws</b>: If memory allocation throws or the in-place constructor throws or //! <b>Throws</b>: If memory allocation throws or the in-place constructor throws or
//! T's copy/move constructor throws. //! T's copy/move constructor throws.
//! //!
//! <b>Complexity</b>: Amortized constant time. //! <b>Complexity</b>: Amortized constant time.
template<class ...Args> template<class ...Args>
BOOST_CONTAINER_FORCEINLINE void emplace_back(BOOST_FWD_REF(Args)...args) BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_FWD_REF(Args)...args)
{ {
if (BOOST_LIKELY(this->room_enough())){ if (BOOST_LIKELY(this->room_enough())){
//There is more memory, just construct a new object at the end //There is more memory, just construct a new object at the end
allocator_traits_type::construct(this->m_holder.alloc(), this->priv_raw_end(), ::boost::forward<Args>(args)...); allocator_traits_type::construct(this->m_holder.alloc(), this->priv_raw_end(), ::boost::forward<Args>(args)...);
++this->m_holder.m_size; ++this->m_holder.m_size;
return *this->priv_raw_end();
} }
else{ else{
typedef container_detail::insert_emplace_proxy<Allocator, T*, Args...> type; typedef container_detail::insert_emplace_proxy<Allocator, T*, Args...> type;
this->priv_forward_range_insert_no_capacity return *this->priv_forward_range_insert_no_capacity
(this->back_ptr(), 1, type(::boost::forward<Args>(args)...), alloc_version()); (this->back_ptr(), 1, type(::boost::forward<Args>(args)...), alloc_version());
} }
} }
@@ -1787,16 +1790,17 @@ class vector
#define BOOST_CONTAINER_VECTOR_EMPLACE_CODE(N) \ #define BOOST_CONTAINER_VECTOR_EMPLACE_CODE(N) \
BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \ BOOST_MOVE_TMPL_LT##N BOOST_MOVE_CLASS##N BOOST_MOVE_GT##N \
BOOST_CONTAINER_FORCEINLINE void emplace_back(BOOST_MOVE_UREF##N)\ BOOST_CONTAINER_FORCEINLINE reference emplace_back(BOOST_MOVE_UREF##N)\
{\ {\
if (BOOST_LIKELY(this->room_enough())){\ if (BOOST_LIKELY(this->room_enough())){\
allocator_traits_type::construct (this->m_holder.alloc()\ allocator_traits_type::construct (this->m_holder.alloc()\
, this->priv_raw_end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\ , this->priv_raw_end() BOOST_MOVE_I##N BOOST_MOVE_FWD##N);\
++this->m_holder.m_size;\ ++this->m_holder.m_size;\
return *this->priv_raw_end();\
}\ }\
else{\ else{\
typedef container_detail::insert_emplace_proxy_arg##N<Allocator, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\ typedef container_detail::insert_emplace_proxy_arg##N<Allocator, T* BOOST_MOVE_I##N BOOST_MOVE_TARG##N> type;\
this->priv_forward_range_insert_no_capacity\ return *this->priv_forward_range_insert_no_capacity\
( this->back_ptr(), 1, type(BOOST_MOVE_FWD##N), alloc_version());\ ( this->back_ptr(), 1, type(BOOST_MOVE_FWD##N), alloc_version());\
}\ }\
}\ }\

View File

@@ -175,13 +175,18 @@ bool test_emplace_back(container_detail::true_)
new(&expected [4]) EmplaceInt(1, 2, 3, 4); new(&expected [4]) EmplaceInt(1, 2, 3, 4);
new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5); new(&expected [5]) EmplaceInt(1, 2, 3, 4, 5);
Container c; Container c;
c.emplace_back(); typedef typename Container::reference reference;
if(!test_expected_container(c, &expected[0], 1)){ {
return false; reference r = c.emplace_back();
if(&r != &c.back() && !test_expected_container(c, &expected[0], 1)){
return false;
}
} }
c.emplace_back(1); {
if(!test_expected_container(c, &expected[0], 2)){ reference r = c.emplace_back(1);
return false; if(&r != &c.back() && !test_expected_container(c, &expected[0], 2)){
return false;
}
} }
c.emplace_back(1, 2); c.emplace_back(1, 2);
if(!test_expected_container(c, &expected[0], 3)){ if(!test_expected_container(c, &expected[0], 3)){
@@ -222,13 +227,18 @@ bool test_emplace_front(container_detail::true_)
new(&expected [4]) EmplaceInt(1); new(&expected [4]) EmplaceInt(1);
new(&expected [5]) EmplaceInt(); new(&expected [5]) EmplaceInt();
Container c; Container c;
c.emplace_front(); typedef typename Container::reference reference;
if(!test_expected_container(c, &expected[0] + 5, 1)){ {
return false; reference r = c.emplace_front();
if(&r != &c.front() && !test_expected_container(c, &expected[0] + 5, 1)){
return false;
}
} }
c.emplace_front(1); {
if(!test_expected_container(c, &expected[0] + 4, 2)){ reference r = c.emplace_front(1);
return false; if(&r != &c.front() && !test_expected_container(c, &expected[0] + 4, 2)){
return false;
}
} }
c.emplace_front(1, 2); c.emplace_front(1, 2);
if(!test_expected_container(c, &expected[0] + 3, 3)){ if(!test_expected_container(c, &expected[0] + 3, 3)){