diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index 9d9cc5e..611b3c9 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -36,6 +36,31 @@ namespace detail { template struct decorate_const { typedef const T type; }; template struct decorate_const { typedef const T type; }; + // How values should be passed as arguments to shared_vector methods + // really should use boost::call_traits + template struct call_with { typedef T type; }; + template struct call_with > + { typedef const std::tr1::shared_ptr& type; }; + template<> struct call_with { typedef const std::string& type; }; + + // For lack of C++11's std::move do our own special handling of shared_ptr + template + struct moveme { + template + static void op(const arg& a, const arg& b, const arg& c) + {std::copy(a,b,c);} + }; + template + struct moveme > { + template + 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 class shared_vector : public detail::shared_vector_base { typedef detail::shared_vector_base base_t; + typedef typename detail::call_with::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()); + detail::moveme::op(begin(), end(), temp); + this->m_data.reset(temp, detail::default_array_deleter()); }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::op(begin(), begin()+std::min(i,this->size()), temp); - this->m_data.reset(temp, detail::default_array_deleter()); + this->m_data.reset(temp, detail::default_array_deleter()); }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()); - std::copy(this->m_data.get()+this->m_offset, + detail::moveme::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; diff --git a/testApp/misc/testSharedVector.cpp b/testApp/misc/testSharedVector.cpp index 71fd943..b36d5b6 100644 --- a/testApp/misc/testSharedVector.cpp +++ b/testApp/misc/testSharedVector.cpp @@ -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 strings(6); + epics::pvData::shared_vector > 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 > 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)=%lu", @@ -351,5 +385,6 @@ MAIN(testSharedVector) testConst(); testSlice(); testVoid(); + testNonPOD(); return testDone(); }