remove variadic template emulation for c++98, and introduce emplace_back to heterogeneous_queue as well, to avoid all moves of alert objects (#658)

This commit is contained in:
Arvid Norberg 2016-04-28 10:30:29 -04:00
parent 10ec0234a7
commit c3e1e405b2
5 changed files with 26 additions and 95 deletions

View File

@ -159,7 +159,6 @@ nobase_include_HEADERS = \
tommath_class.h \ tommath_class.h \
tommath_superclass.h \ tommath_superclass.h \
\ \
aux_/alert_manager_variadic_emplace.hpp \
aux_/array_view.hpp \ aux_/array_view.hpp \
aux_/allocating_handler.hpp \ aux_/allocating_handler.hpp \
aux_/bind_to_device.hpp \ aux_/bind_to_device.hpp \

View File

@ -58,9 +58,6 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma GCC diagnostic ignored "-Wdeprecated-declarations" #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif #endif
// used for emplace_alert() variadic template emulation for c++98
#define TORRENT_ALERT_MANAGER_MAX_ARITY 7
namespace libtorrent { namespace libtorrent {
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
@ -74,8 +71,6 @@ namespace libtorrent {
, boost::uint32_t alert_mask = alert::error_notification); , boost::uint32_t alert_mask = alert::error_notification);
~alert_manager(); ~alert_manager();
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
template <class T, typename... Args> template <class T, typename... Args>
void emplace_alert(Args&&... args) void emplace_alert(Args&&... args)
{ {
@ -95,20 +90,12 @@ namespace libtorrent {
* (1 + T::priority)) * (1 + T::priority))
return; return;
T alert(m_allocations[m_generation], std::forward<Args>(args)...); T& alert = m_alerts[m_generation].emplace_back<T>(
m_alerts[m_generation].push_back(alert); m_allocations[m_generation], std::forward<Args>(args)...);
maybe_notify(&alert, lock); maybe_notify(&alert, lock);
} }
#else
// emulate variadic templates for c++98
#include "libtorrent/aux_/alert_manager_variadic_emplace.hpp"
#endif
bool pending() const; bool pending() const;
void get_all(std::vector<alert*>& alerts); void get_all(std::vector<alert*>& alerts);

View File

@ -1,55 +0,0 @@
#if !defined BOOST_PP_IS_ITERATING || !BOOST_PP_IS_ITERATING
// set-up iteration
#include <boost/preprocessor/repetition/enum_params.hpp>
#include <boost/preprocessor/iteration/iterate.hpp>
#include <boost/preprocessor/punctuation/comma_if.hpp>
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
#define BOOST_PP_ITERATION_PARAMS_1 \
(3, (0, TORRENT_ALERT_MANAGER_MAX_ARITY, \
"libtorrent/aux_/alert_manager_variadic_emplace.hpp"))
#include BOOST_PP_ITERATE()
#else // BOOST_PP_IS_ITERATING
// loop body
#define I BOOST_PP_ITERATION()
template <class T
BOOST_PP_COMMA_IF(I)
BOOST_PP_ENUM_PARAMS(I, typename A)>
void emplace_alert(BOOST_PP_ENUM_BINARY_PARAMS(I, A, const& a) )
{
mutex::scoped_lock lock(m_mutex);
#ifndef TORRENT_NO_DEPRECATE
if (m_dispatch)
{
m_dispatch(std::auto_ptr<alert>(new T(m_allocations[m_generation]
BOOST_PP_COMMA_IF(I)
BOOST_PP_ENUM_PARAMS(I, a))));
return;
}
#endif
// don't add more than this number of alerts, unless it's a
// high priority alert, in which case we try harder to deliver it
// for high priority alerts, double the upper limit
if (m_alerts[m_generation].size() >= m_queue_size_limit
* (1 + T::priority))
return;
T alert(m_allocations[m_generation]
BOOST_PP_COMMA_IF(I)
BOOST_PP_ENUM_PARAMS(I, a));
m_alerts[m_generation].push_back(alert);
maybe_notify(&alert, lock);
}
#undef I
#endif

View File

@ -53,10 +53,9 @@ namespace libtorrent {
, m_num_items(0) , m_num_items(0)
{} {}
// TODO: 2 add emplace_back() version template <class U, typename... Args>
template <class U> typename boost::enable_if<boost::is_base_of<T, U>, U&>::type
typename boost::enable_if<boost::is_base_of<T, U> >::type emplace_back(Args&&... args)
push_back(U const& a)
{ {
// the size of the type rounded up to pointer alignment // the size of the type rounded up to pointer alignment
const int object_size = (sizeof(U) + sizeof(*m_storage) - 1) const int object_size = (sizeof(U) + sizeof(*m_storage) - 1)
@ -75,12 +74,13 @@ namespace libtorrent {
ptr += header_size; ptr += header_size;
// construct in-place // construct in-place
new (ptr) U(a); new (ptr) U(std::forward<Args>(args)...);
// if we constructed the object without throwing any exception // if we constructed the object without throwing any exception
// update counters to indicate the new item is in there // update counters to indicate the new item is in there
++m_num_items; ++m_num_items;
m_size += header_size + object_size; m_size += header_size + object_size;
return *reinterpret_cast<U*>(ptr);
} }
void get_pointers(std::vector<T*>& out) void get_pointers(std::vector<T*>& out)

View File

@ -138,24 +138,24 @@ private:
F& operator=(F const& f); F& operator=(F const& f);
}; };
// test push_back of heterogeneous types // test emplace_back of heterogeneous types
// and retrieval of their pointers // and retrieval of their pointers
TORRENT_TEST(push_back) TORRENT_TEST(emplace_back)
{ {
using namespace libtorrent; using namespace libtorrent;
heterogeneous_queue<A> q; heterogeneous_queue<A> q;
q.push_back(B(0, 1)); q.emplace_back<B>(0, 1);
TEST_EQUAL(q.size(), 1); TEST_EQUAL(q.size(), 1);
q.push_back(B(2, 3)); q.emplace_back<B>(2, 3);
TEST_EQUAL(q.size(), 2); TEST_EQUAL(q.size(), 2);
q.push_back(B(4, 5)); q.emplace_back<B>(4, 5);
TEST_EQUAL(q.size(), 3); TEST_EQUAL(q.size(), 3);
q.push_back(C(6, 7)); q.emplace_back<C>(6, 7);
TEST_EQUAL(q.size(), 4); TEST_EQUAL(q.size(), 4);
q.push_back(C(8, 9)); q.emplace_back<C>(8, 9);
TEST_EQUAL(q.size(), 5); TEST_EQUAL(q.size(), 5);
q.push_back(C(10, 11)); q.emplace_back<C>(10, 11);
TEST_EQUAL(q.size(), 6); TEST_EQUAL(q.size(), 6);
std::vector<A*> ptrs; std::vector<A*> ptrs;
@ -196,13 +196,13 @@ TORRENT_TEST(swap)
heterogeneous_queue<A> q1; heterogeneous_queue<A> q1;
heterogeneous_queue<A> q2; heterogeneous_queue<A> q2;
q1.push_back(B(0, 1)); q1.emplace_back<B>(0, 1);
q1.push_back(B(2, 3)); q1.emplace_back<B>(2, 3);
q1.push_back(B(4, 5)); q1.emplace_back<B>(4, 5);
TEST_EQUAL(q1.size(), 3); TEST_EQUAL(q1.size(), 3);
q2.push_back(C(6, 7)); q2.emplace_back<C>(6, 7);
q2.push_back(C(8, 9)); q2.emplace_back<C>(8, 9);
TEST_EQUAL(q2.size(), 2); TEST_EQUAL(q2.size(), 2);
std::vector<A*> ptrs; std::vector<A*> ptrs;
@ -245,13 +245,13 @@ TORRENT_TEST(destruction)
heterogeneous_queue<D> q; heterogeneous_queue<D> q;
TEST_EQUAL(D::instances, 0); TEST_EQUAL(D::instances, 0);
q.push_back(D()); q.emplace_back<D>();
TEST_EQUAL(D::instances, 1); TEST_EQUAL(D::instances, 1);
q.push_back(D()); q.emplace_back<D>();
TEST_EQUAL(D::instances, 2); TEST_EQUAL(D::instances, 2);
q.push_back(D()); q.emplace_back<D>();
TEST_EQUAL(D::instances, 3); TEST_EQUAL(D::instances, 3);
q.push_back(D()); q.emplace_back<D>();
TEST_EQUAL(D::instances, 4); TEST_EQUAL(D::instances, 4);
q.clear(); q.clear();
@ -269,7 +269,7 @@ TORRENT_TEST(copy_move)
// make sure the queue has to grow at some point, to exercise its // make sure the queue has to grow at some point, to exercise its
// copy/move of elements // copy/move of elements
for (int i = 0; i < 1000; ++i) for (int i = 0; i < 1000; ++i)
q.push_back(F(i)); q.emplace_back<F>(i);
std::vector<F*> ptrs; std::vector<F*> ptrs;
q.get_pointers(ptrs); q.get_pointers(ptrs);
@ -293,7 +293,7 @@ TORRENT_TEST(nontrivial)
heterogeneous_queue<E> q; heterogeneous_queue<E> q;
for (int i = 0; i < 10000; ++i) for (int i = 0; i < 10000; ++i)
{ {
q.push_back(E("testing to allocate non-trivial objects")); q.emplace_back<E>("testing to allocate non-trivial objects");
} }
} }