From 45bb461c323a27d269aeeea0f659c4cf702efbb8 Mon Sep 17 00:00:00 2001 From: Michael Davidsaver Date: Thu, 25 Jul 2013 15:26:29 -0400 Subject: [PATCH] shared_vector require freeze/thaw Remove the implicit cast from non-const to const. Require the use of freeze/thaw when changing between const and non-const. Change argument of const_shared_vector_cast to a non-const shared_vector reference to allow it to be cleared by freeze/thaw. --- pvDataApp/misc/sharedVector.h | 201 ++++++++++++++++++++-------------- 1 file changed, 120 insertions(+), 81 deletions(-) diff --git a/pvDataApp/misc/sharedVector.h b/pvDataApp/misc/sharedVector.h index bc90ae8..ed3fd11 100644 --- a/pvDataApp/misc/sharedVector.h +++ b/pvDataApp/misc/sharedVector.h @@ -15,28 +15,17 @@ namespace epics { namespace pvData { -template class shared_vector; +template class shared_vector; + +template +static FORCE_INLINE +shared_vector +const_shared_vector_cast(shared_vector& src); namespace detail { template struct default_array_deleter {void operator()(E a){delete[] a;}}; - // Implicit casts allowed during copy construction of shared_vector - template - struct vector_implicit_cast { - // There is intentionally no implmentation here to cause - // compile errors for illegal casts. - //static std::tr1::shared_ptr cast(const std::tr1::shared_ptr); - }; - // non-const -> const - template - struct vector_implicit_cast { - static std::tr1::shared_ptr cast(const std::tr1::shared_ptr input) - { - return std::tr1::shared_ptr(input); - } - }; - // How values should be passed as arguments to shared_vector methods // really should use boost::call_traits template struct call_with { typedef T type; }; @@ -44,6 +33,10 @@ namespace detail { { typedef const std::tr1::shared_ptr& type; }; template<> struct call_with { typedef const std::string& type; }; + struct _shared_vector_freeze_tag {}; + struct _shared_vector_thaw_tag {}; + struct _shared_vector_cast_tag {}; + /* All the parts of shared_vector which * don't need special handling for E=void */ @@ -100,11 +93,33 @@ namespace detail { ,m_count(O.m_count), m_total(O.m_total) {} - template - shared_vector_base(const shared_vector_base& o) - : m_data(vector_implicit_cast::cast(o.m_data)) - , m_offset(o.m_offset), m_count(o.m_count), m_total(o.m_total) - {_null_input();} + protected: + typedef typename meta::strip_const::type _E_non_const; + public: + shared_vector_base(shared_vector_base<_E_non_const>& O, + _shared_vector_freeze_tag) + :m_data() + ,m_offset(O.m_offset) + ,m_count(O.m_count) + ,m_total(O.m_total) + { + if(!O.unique()) + throw std::runtime_error("Can't freeze non-unique vector"); + m_data = O.m_data; + O.clear(); + } + + shared_vector_base(shared_vector& O, + _shared_vector_thaw_tag) + :m_data() + ,m_offset(O.m_offset) + ,m_count(O.m_count) + ,m_total(O.m_total) + { + O.make_unique(); + m_data = std::tr1::const_pointer_cast(O.m_data); + O.clear(); + } //! @brief Copy an existing vector shared_vector_base& operator=(const shared_vector_base& o) @@ -118,19 +133,6 @@ namespace detail { return *this; } - //! @brief Copy an existing vector of a related type - template - shared_vector_base& operator=(const shared_vector_base& o) - { - if(&o!=this) { - m_data=vector_implicit_cast::cast(o.m_data); - m_offset=o.m_offset; - m_count=o.m_count; - m_total=o.m_total; - } - return *this; - } - //! @brief Swap the contents of this vector with another void swap(shared_vector_base& o) { if(&o!=this) { @@ -200,9 +202,6 @@ namespace detail { size_t dataCount() const { return m_count; } size_t dataTotal() const { return m_total; } }; - - - struct _shared_vector_cast_tag {}; } /** @brief A holder for a contigious piece of memory. @@ -223,11 +222,12 @@ namespace detail { * by make_unique() that unique()==true implies exclusive * ownership. */ -template +template class shared_vector : public detail::shared_vector_base { typedef detail::shared_vector_base base_t; typedef typename detail::call_with::type param_type; + typedef typename meta::strip_const::type _E_non_const; public: typedef E value_type; typedef E& reference; @@ -253,14 +253,14 @@ public: //! @brief Allocate (with new[]) a new vector of size c explicit shared_vector(size_t c) - :base_t(new E[c], 0, c) + :base_t(new _E_non_const[c], 0, c) {} //! @brief Allocate (with new[]) a new vector of size c and fill with value e shared_vector(size_t c, param_type e) - :base_t(new E[c], 0, c) + :base_t(new _E_non_const[c], 0, c) { - std::fill_n(this->m_data.get(), this->m_count, e); + std::fill_n((_E_non_const*)this->m_data.get(), this->m_count, e); } /** @brief Build vector from a raw pointer @@ -296,10 +296,6 @@ public: //! @brief Copy an existing vector of same type shared_vector(const shared_vector& o) :base_t(o) {} - //! @brief Copy an existing vector of a related type - template - shared_vector(const shared_vector& o) :base_t(o) {} - //! @internal //! Internal for static_shared_vector_cast template @@ -310,6 +306,17 @@ public: src.dataCount()/sizeof(E)) {} + + shared_vector(shared_vector& O, + detail::_shared_vector_freeze_tag t) + :base_t(O,t) + {} + + shared_vector(shared_vector& O, + detail::_shared_vector_thaw_tag t) + :base_t(O,t) + {} + size_t max_size() const{return ((size_t)-1)/sizeof(E);} size_t capacity() const { return this->m_total; } @@ -325,7 +332,7 @@ public: void reserve(size_t i) { if(this->unique() && i<=this->m_total) return; - pointer temp=new E[i]; + _E_non_const* temp=new _E_non_const[i]; try{ std::copy(begin(), end(), temp); this->m_data.reset(temp, detail::default_array_deleter()); @@ -360,7 +367,7 @@ public: } // must re-allocate :( size_t new_total = std::max(this->m_total, i); - pointer temp=new E[new_total]; + _E_non_const* temp=new _E_non_const[new_total]; try{ // Copy as much as possible from old, // remaining elements are uninitialized. @@ -409,11 +416,17 @@ public: void make_unique() { 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, - this->m_data.get()+this->m_offset+this->m_count, - d.get()); - this->m_data.swap(d); + typedef typename meta::strip_const::type nE; + nE *d = new nE[this->m_total]; + try { + std::copy(this->m_data.get()+this->m_offset, + this->m_data.get()+this->m_offset+this->m_count, + d); + }catch(...){ + delete[] d; + throw; + } + this->m_data.reset(d, detail::default_array_deleter()); this->m_offset=0; } @@ -517,10 +530,6 @@ public: shared_vector(const std::tr1::shared_ptr& d, size_t o, size_t c) :base_t(d,o,c), m_vtype((ScalarType)-1) {} - template - shared_vector(const shared_vector& o) - :base_t(o), m_vtype(o.m_vtype) {} - shared_vector(const shared_vector& o) :base_t(o), m_vtype(o.m_vtype) {} @@ -535,6 +544,16 @@ public: ,m_vtype((ScalarType)ScalarTypeID::value) {} + shared_vector(shared_vector& O, + detail::_shared_vector_freeze_tag t) + :base_t(O,t) + {} + + shared_vector(shared_vector& O, + detail::_shared_vector_thaw_tag t) + :base_t(O,t) + {} + shared_vector& operator=(const shared_vector& o) { if(&o!=this) { @@ -614,15 +633,14 @@ namespace detail { // alloc and convert shared_vector ret(src.size()/ScalarTypeFunc::elementSize(stype)); castUnsafeV(ret.size(), - (ScalarType)ScalarTypeID::value, + dtype, static_cast(ret.data()), stype, static_cast(src.data())); - return ret; + return const_shared_vector_cast(ret); } } }; - } /** @brief Allow casting of shared_vector between types @@ -658,18 +676,6 @@ shared_vector_convert(const shared_vector& src) return detail::shared_vector_converter::op(src); } -//! Allows casting from const TYPE -> TYPE. -template -static FORCE_INLINE -shared_vector -const_shared_vector_cast(const shared_vector& src) -{ - return shared_vector( - std::tr1::const_pointer_cast(src.dataPtr()), - src.dataOffset(), - src.dataCount()); -} - /** @brief transform a shared_vector to shared_vector * * Transform a reference to mutable data into a reference to read-only data. @@ -681,12 +687,8 @@ static FORCE_INLINE shared_vector::type> freeze(SRC& src) { - if(!src.unique()) - throw std::runtime_error("Can't freeze non-unique vector"); typedef typename meta::decorate_const::type const_value; - shared_vector ret(src); - src.clear(); - return ret; + return shared_vector(src, detail::_shared_vector_freeze_tag()); } /** @brief transform a shared_vector to shared_vector @@ -701,10 +703,47 @@ shared_vector::type> thaw(SRC& src) { typedef typename meta::strip_const::type value; - shared_vector ret(const_shared_vector_cast(src)); - src.clear(); - ret.make_unique(); - return ret; + return shared_vector(src, detail::_shared_vector_thaw_tag()); +} + +namespace detail { + template + struct const_caster {}; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + return thaw(src); + } + }; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + return freeze(src); + } + }; + + template + struct const_caster { + static FORCE_INLINE shared_vector op(shared_vector& src) + { + shared_vector ret(src); + src.clear(); + return ret; + } + }; +} + +//! Allows casting from const TYPE -> TYPE. +template +static FORCE_INLINE +shared_vector +const_shared_vector_cast(shared_vector& src) +{ + return detail::const_caster::op(src); }