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_superclass.h \
\
aux_/alert_manager_variadic_emplace.hpp \
aux_/array_view.hpp \
aux_/allocating_handler.hpp \
aux_/bind_to_device.hpp \

View File

@ -58,9 +58,6 @@ POSSIBILITY OF SUCH DAMAGE.
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
// used for emplace_alert() variadic template emulation for c++98
#define TORRENT_ALERT_MANAGER_MAX_ARITY 7
namespace libtorrent {
#ifndef TORRENT_DISABLE_EXTENSIONS
@ -74,8 +71,6 @@ namespace libtorrent {
, boost::uint32_t alert_mask = alert::error_notification);
~alert_manager();
#ifndef BOOST_NO_CXX11_VARIADIC_TEMPLATES
template <class T, typename... Args>
void emplace_alert(Args&&... args)
{
@ -95,20 +90,12 @@ namespace libtorrent {
* (1 + T::priority))
return;
T alert(m_allocations[m_generation], std::forward<Args>(args)...);
m_alerts[m_generation].push_back(alert);
T& alert = m_alerts[m_generation].emplace_back<T>(
m_allocations[m_generation], std::forward<Args>(args)...);
maybe_notify(&alert, lock);
}
#else
// emulate variadic templates for c++98
#include "libtorrent/aux_/alert_manager_variadic_emplace.hpp"
#endif
bool pending() const;
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)
{}
// TODO: 2 add emplace_back() version
template <class U>
typename boost::enable_if<boost::is_base_of<T, U> >::type
push_back(U const& a)
template <class U, typename... Args>
typename boost::enable_if<boost::is_base_of<T, U>, U&>::type
emplace_back(Args&&... args)
{
// the size of the type rounded up to pointer alignment
const int object_size = (sizeof(U) + sizeof(*m_storage) - 1)
@ -75,12 +74,13 @@ namespace libtorrent {
ptr += header_size;
// construct in-place
new (ptr) U(a);
new (ptr) U(std::forward<Args>(args)...);
// if we constructed the object without throwing any exception
// update counters to indicate the new item is in there
++m_num_items;
m_size += header_size + object_size;
return *reinterpret_cast<U*>(ptr);
}
void get_pointers(std::vector<T*>& out)

View File

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