optimize shared_vector for storing non-POD types
pass values by reference where appropriate. When reallocating arrays of shared_ptr "move" with swap() instead of operator= to avoid ref counter inc and dec for each element.
This commit is contained in:
@@ -36,6 +36,31 @@ namespace detail {
|
||||
template<typename T> struct decorate_const { typedef const T type; };
|
||||
template<typename T> struct decorate_const<const T> { typedef const T type; };
|
||||
|
||||
// How values should be passed as arguments to shared_vector methods
|
||||
// really should use boost::call_traits
|
||||
template<typename T> struct call_with { typedef T type; };
|
||||
template<typename T> struct call_with<std::tr1::shared_ptr<T> >
|
||||
{ typedef const std::tr1::shared_ptr<T>& type; };
|
||||
template<> struct call_with<std::string> { typedef const std::string& type; };
|
||||
|
||||
// For lack of C++11's std::move do our own special handling of shared_ptr
|
||||
template<typename T>
|
||||
struct moveme {
|
||||
template<typename arg>
|
||||
static void op(const arg& a, const arg& b, const arg& c)
|
||||
{std::copy(a,b,c);}
|
||||
};
|
||||
template<typename T>
|
||||
struct moveme<std::tr1::shared_ptr<T> > {
|
||||
template<typename arg>
|
||||
static void op(arg a, arg b, arg c)
|
||||
{
|
||||
// "move" with swap to avoid ref counter operations
|
||||
for(;a!=b;a++,c++)
|
||||
c->swap(*a);
|
||||
}
|
||||
};
|
||||
|
||||
/* All the parts of shared_vector which
|
||||
* don't need special handling for E=void
|
||||
*/
|
||||
@@ -194,6 +219,7 @@ template<typename E>
|
||||
class shared_vector : public detail::shared_vector_base<E>
|
||||
{
|
||||
typedef detail::shared_vector_base<E> base_t;
|
||||
typedef typename detail::call_with<E>::type param_type;
|
||||
public:
|
||||
typedef E value_type;
|
||||
typedef E& reference;
|
||||
@@ -222,7 +248,7 @@ public:
|
||||
{}
|
||||
|
||||
//! @brief Allocate (with new[]) a new vector of size c and fill with value e
|
||||
shared_vector(size_t c, E e)
|
||||
shared_vector(size_t c, param_type e)
|
||||
:base_t(new E[c], 0, c)
|
||||
{
|
||||
std::fill_n(this->m_data.get(), this->m_count, e);
|
||||
@@ -277,8 +303,8 @@ public:
|
||||
return;
|
||||
pointer temp=new E[i];
|
||||
try{
|
||||
std::copy(begin(), end(), temp);
|
||||
this->m_data.reset(temp, detail::default_array_deleter<E*>());
|
||||
detail::moveme<E>::op(begin(), end(), temp);
|
||||
this->m_data.reset(temp, detail::default_array_deleter<pointer>());
|
||||
}catch(...){
|
||||
delete[] temp;
|
||||
throw;
|
||||
@@ -314,10 +340,10 @@ public:
|
||||
try{
|
||||
// Copy as much as possible from old,
|
||||
// remaining elements are uninitialized.
|
||||
std::copy(begin(),
|
||||
detail::moveme<E>::op(begin(),
|
||||
begin()+std::min(i,this->size()),
|
||||
temp);
|
||||
this->m_data.reset(temp, detail::default_array_deleter<E*>());
|
||||
this->m_data.reset(temp, detail::default_array_deleter<pointer>());
|
||||
}catch(...){
|
||||
delete[] temp;
|
||||
throw;
|
||||
@@ -331,7 +357,7 @@ public:
|
||||
*
|
||||
* see @ref resize(size_t)
|
||||
*/
|
||||
void resize(size_t i, E v) {
|
||||
void resize(size_t i, param_type v) {
|
||||
size_t oldsize=this->size();
|
||||
resize(i);
|
||||
if(this->size()>oldsize) {
|
||||
@@ -360,7 +386,7 @@ public:
|
||||
if(this->unique())
|
||||
return;
|
||||
shared_pointer_type d(new E[this->m_total], detail::default_array_deleter<E*>());
|
||||
std::copy(this->m_data.get()+this->m_offset,
|
||||
detail::moveme<E>::op(this->m_data.get()+this->m_offset,
|
||||
this->m_data.get()+this->m_offset+this->m_count,
|
||||
d.get());
|
||||
this->m_data.swap(d);
|
||||
@@ -387,7 +413,7 @@ public:
|
||||
|
||||
// Modifications
|
||||
|
||||
void push_back(const E& v)
|
||||
void push_back(param_type v)
|
||||
{
|
||||
resize(this->size()+1);
|
||||
back() = v;
|
||||
|
||||
@@ -160,12 +160,14 @@ static void testShare()
|
||||
|
||||
one.make_unique();
|
||||
|
||||
testOk1(one[1]==43);
|
||||
one[1] = 143;
|
||||
testOk1(two[1]==43);
|
||||
testOk1(three[1]==43);
|
||||
|
||||
two.resize(two.size());
|
||||
|
||||
testOk1(two[1]==43);
|
||||
two[1] = 243;
|
||||
testOk1(one[1]==143);
|
||||
testOk1(three[1]==43);
|
||||
@@ -177,11 +179,13 @@ static void testShare()
|
||||
one.resize(2);
|
||||
|
||||
testOk1(one.size()==2);
|
||||
testOk1(one[1]==143);
|
||||
testOk1(two.size()==15);
|
||||
testOk1(three.size()==15);
|
||||
|
||||
two.resize(20, 5000);
|
||||
|
||||
testOk1(two[1]==243);
|
||||
testOk1(one.size()==2);
|
||||
testOk1(two.size()==20);
|
||||
testOk1(three.size()==15);
|
||||
@@ -335,9 +339,39 @@ static void testVoid()
|
||||
testOk1(typed.size()==2);
|
||||
}
|
||||
|
||||
struct dummyStruct {};
|
||||
|
||||
static void testNonPOD()
|
||||
{
|
||||
testDiag("Test vector of non-POD types");
|
||||
|
||||
epics::pvData::shared_vector<std::string> strings(6);
|
||||
epics::pvData::shared_vector<std::tr1::shared_ptr<dummyStruct> > structs(5);
|
||||
|
||||
testOk1(strings[0].empty());
|
||||
testOk1(structs[0].get()==NULL);
|
||||
|
||||
structs[1].reset(new dummyStruct);
|
||||
dummyStruct *temp = structs[1].get();
|
||||
|
||||
epics::pvData::shared_vector<std::tr1::shared_ptr<dummyStruct> > structs2(structs);
|
||||
|
||||
testOk1(!structs.unique());
|
||||
testOk1(structs[1].unique());
|
||||
|
||||
testOk1(structs2[1].get()==temp);
|
||||
|
||||
structs2.make_unique();
|
||||
|
||||
testOk1(structs.unique());
|
||||
testOk1(!structs[1].unique());
|
||||
|
||||
testOk1(structs2[1].get()==temp);
|
||||
}
|
||||
|
||||
MAIN(testSharedVector)
|
||||
{
|
||||
testPlan(101);
|
||||
testPlan(113);
|
||||
testDiag("Tests for shared_vector");
|
||||
|
||||
testDiag("sizeof(shared_vector<int>)=%lu",
|
||||
@@ -351,5 +385,6 @@ MAIN(testSharedVector)
|
||||
testConst();
|
||||
testSlice();
|
||||
testVoid();
|
||||
testNonPOD();
|
||||
return testDone();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user