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.
This commit is contained in:
Michael Davidsaver
2013-07-25 15:26:29 -04:00
parent 105c3185f7
commit 45bb461c32

View File

@@ -15,28 +15,17 @@
namespace epics { namespace pvData {
template<typename E, class Enable> class shared_vector;
template<typename E, class Enable = void> class shared_vector;
template<typename TO, typename FROM>
static FORCE_INLINE
shared_vector<TO>
const_shared_vector_cast(shared_vector<FROM>& src);
namespace detail {
template<typename E>
struct default_array_deleter {void operator()(E a){delete[] a;}};
// Implicit casts allowed during copy construction of shared_vector
template<typename FROM, typename TO>
struct vector_implicit_cast {
// There is intentionally no implmentation here to cause
// compile errors for illegal casts.
//static std::tr1::shared_ptr<TO> cast(const std::tr1::shared_ptr<FROM>);
};
// non-const -> const
template<typename E>
struct vector_implicit_cast<E,const E> {
static std::tr1::shared_ptr<const E> cast(const std::tr1::shared_ptr<E> input)
{
return std::tr1::shared_ptr<const E>(input);
}
};
// 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; };
@@ -44,6 +33,10 @@ namespace detail {
{ typedef const std::tr1::shared_ptr<T>& type; };
template<> struct call_with<std::string> { 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<typename E1>
shared_vector_base(const shared_vector_base<E1>& o)
: m_data(vector_implicit_cast<E1,E>::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<E>::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<const E>& 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<E>(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<typename E1>
shared_vector_base& operator=(const shared_vector_base<E1>& o)
{
if(&o!=this) {
m_data=vector_implicit_cast<E1,E>::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<typename E, class Enable = void>
template<typename E, class Enable>
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;
typedef typename meta::strip_const<E>::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<typename E1>
shared_vector(const shared_vector<E1>& o) :base_t(o) {}
//! @internal
//! Internal for static_shared_vector_cast
template<typename FROM>
@@ -310,6 +306,17 @@ public:
src.dataCount()/sizeof(E))
{}
shared_vector(shared_vector<typename base_t::_E_non_const>& O,
detail::_shared_vector_freeze_tag t)
:base_t(O,t)
{}
shared_vector(shared_vector<const E>& 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<E*>());
@@ -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<E*>());
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<E>::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<E*>());
this->m_offset=0;
}
@@ -517,10 +530,6 @@ public:
shared_vector(const std::tr1::shared_ptr<E1>& d, size_t o, size_t c)
:base_t(d,o,c), m_vtype((ScalarType)-1) {}
template<typename E1>
shared_vector(const shared_vector<E1>& 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<FROM>::value)
{}
shared_vector(shared_vector<void>& O,
detail::_shared_vector_freeze_tag t)
:base_t(O,t)
{}
shared_vector(shared_vector<const void>& 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<to_t> ret(src.size()/ScalarTypeFunc::elementSize(stype));
castUnsafeV(ret.size(),
(ScalarType)ScalarTypeID<TO>::value,
dtype,
static_cast<void*>(ret.data()),
stype,
static_cast<const void*>(src.data()));
return ret;
return const_shared_vector_cast<TO>(ret);
}
}
};
}
/** @brief Allow casting of shared_vector between types
@@ -658,18 +676,6 @@ shared_vector_convert(const shared_vector<FROM>& src)
return detail::shared_vector_converter<TO,FROM>::op(src);
}
//! Allows casting from const TYPE -> TYPE.
template<typename TYPE>
static FORCE_INLINE
shared_vector<TYPE>
const_shared_vector_cast(const shared_vector<const TYPE>& src)
{
return shared_vector<TYPE>(
std::tr1::const_pointer_cast<TYPE>(src.dataPtr()),
src.dataOffset(),
src.dataCount());
}
/** @brief transform a shared_vector<T> to shared_vector<const T>
*
* Transform a reference to mutable data into a reference to read-only data.
@@ -681,12 +687,8 @@ static FORCE_INLINE
shared_vector<typename meta::decorate_const<typename SRC::value_type>::type>
freeze(SRC& src)
{
if(!src.unique())
throw std::runtime_error("Can't freeze non-unique vector");
typedef typename meta::decorate_const<typename SRC::value_type>::type const_value;
shared_vector<const_value> ret(src);
src.clear();
return ret;
return shared_vector<const_value>(src, detail::_shared_vector_freeze_tag());
}
/** @brief transform a shared_vector<const T> to shared_vector<T>
@@ -701,10 +703,47 @@ shared_vector<typename meta::strip_const<typename SRC::value_type>::type>
thaw(SRC& src)
{
typedef typename meta::strip_const<typename SRC::value_type>::type value;
shared_vector<value> ret(const_shared_vector_cast<value>(src));
src.clear();
ret.make_unique();
return ret;
return shared_vector<value>(src, detail::_shared_vector_thaw_tag());
}
namespace detail {
template<typename TO, typename FROM, class Enable = void>
struct const_caster {};
template<typename TYPE>
struct const_caster<TYPE,const TYPE> {
static FORCE_INLINE shared_vector<TYPE> op(shared_vector<const TYPE>& src)
{
return thaw(src);
}
};
template<typename TYPE>
struct const_caster<const TYPE,TYPE> {
static FORCE_INLINE shared_vector<const TYPE> op(shared_vector<TYPE>& src)
{
return freeze(src);
}
};
template<typename TYPE>
struct const_caster<TYPE,TYPE> {
static FORCE_INLINE shared_vector<TYPE> op(shared_vector<TYPE>& src)
{
shared_vector<TYPE> ret(src);
src.clear();
return ret;
}
};
}
//! Allows casting from const TYPE -> TYPE.
template<typename TO, typename FROM>
static FORCE_INLINE
shared_vector<TO>
const_shared_vector_cast(shared_vector<FROM>& src)
{
return detail::const_caster<TO,FROM>::op(src);
}