I had the need for a functionality similar to shallow_array_adaptor. I wrote a quick and dirty solution based on ublas::unbounded_array. I call this storage class my_unbounded_array which can hold data with/without ownership. The implementation is as follows
// Storage class
template <class T>
class my_unbounded_array : public boost::numeric::ublas::storage_array<my_unbounded_array<T>> {
private:
typedef my_unbounded_array<T> self_type;
public:
typedef std::size_t size_type;
typedef std::ptrdiff_t difference_type;
typedef T value_type;
typedef const T& const_reference;
typedef T& reference;
typedef const T* const_pointer;
typedef T* pointer;
typedef const_pointer const_iterator;
typedef pointer iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
inline explicit my_unbounded_array() : own_(true), size_(0), data_(nullptr) {};
inline explicit my_unbounded_array(size_type n) : own_(true), size_(n), data_(allocate(n)) {}
// If bind is true then just copy the address of external data
inline my_unbounded_array(size_type n, pointer arr, bool bind=false) : own_(!bind), size_(n), data_(nullptr) {
if(bind) data_.reset(arr);
else {
data_.reset(allocate(n));
std::uninitialized_copy(arr, arr+n, begin());
}
}
inline my_unbounded_array(size_type n, const value_type& init) : own_(true), size_(n), data_(allocate(n)) {
std::uninitialized_fill_n(begin(), n, init);
}
inline my_unbounded_array(const my_unbounded_array& rhs) : own_(true), size_(rhs.size_), data_(allocate(rhs.size_)) {
std::uninitialized_copy(rhs.begin(), rhs.end(), begin());
}
inline ~my_unbounded_array() {
if(!own_) data_.release();
}
inline size_type size() const {return size_;}
inline bool owner() const {return own_;}
inline bool empty() const {return size_==0;}
//! Bind to external data. Set ownership to false.
inline void bind(size_type n, pointer arr) {
if(!own_) data_.release();
own_=false;
size_=n;
data_.reset(arr);
}
inline void resize(size_type n) {
if(size_!=n) {
if(!own_) {
data_.release();
throw("Cannot resize external data."); // Throw an appropriate exception here. This is just an example
}
data_.reset(allocate(n));
size_=n;
}
}
inline void resize(size_type n, value_type init) {
if(size_!=n) {
if(!own_) {
data_.release();
throw("Cannot resize external data."); // Throw an appropriate exception here. This is just an example
}
pointer tmp=nullptr;
if(n) {
tmp=allocate(n);
if(size_<n) {
std::uninitialized_copy(begin(), end(), tmp);
std::uninitialized_fill(tmp+size_, tmp+n, init);
} else
std::uninitialized_copy(begin(), begin()+n, tmp);
}
size_=n;
data_.reset(tmp);
}
}
// Element access
inline const_reference operator[](size_type i) const {
return (data_.get())[i];
}
inline reference operator[](size_type i) {
return (data_.get())[i];
}
// Assignment
inline my_unbounded_array& operator=(const my_unbounded_array& rhs) {
if(this!=&rhs) {
resize(rhs.size_);
std::copy(rhs.data_.get(), (rhs.data_.get())+rhs.size_, data_.get());
}
return *this;
}
inline my_unbounded_array& assign_temporary(my_unbounded_array& rhs) {
swap(rhs);
return *this;
}
inline void swap(my_unbounded_array& rhs) {
if(!own_) {
data_.release();
throw("Cannot resize external data."); // Throw an appropriate exception here. This is just an example
}
if(this!=&rhs) {
std::swap(size_, rhs.size_);
std::swap(own_, rhs.own_);
data_.swap(rhs.data_);
}
}
friend inline void swap(my_unbounded_array& x, my_unbounded_array& y) {x.swap(y);}
inline const_iterator begin() const {return data_.get();}
inline const_iterator end() const {return data_.get()+size_;}
inline iterator begin() {return data_.get();}
inline iterator end() {return data_.get()+size_;}
inline const_reverse_iterator rbegin() const {return const_reverse_iterator(end());}
inline const_reverse_iterator rend() const {return const_reverse_iterator(begin());}
inline reverse_iterator rbegin() {return const_reverse_iterator(end());}
inline reverse_iterator rend() {return const_reverse_iterator(begin());}
private:
friend class boost::serialization::access;
// Serialization
template<class Archive>
void serialize(Archive& ar, const unsigned int version) {
boost::serialization::collection_size_type s(size_);
ar& boost::serialization::make_nvp("size", s);
if(Archive::is_loading::value) resize(s);
ar& boost::serialization::make_array(data_.get(), s);
}
static inline pointer allocate(const size_t n) {
try {
return n>0 ? new T[n] : nullptr;
} catch(std::bad_alloc& e) {
// Do something here!!!!!!!!!!!!
}
}
//! Data ownership. True if it owns the memory block.
/*!If false then data is treated as external and not deleted by the destructor,
* and any operation involving resizing is not allowed. */
bool own_;
size_type size_;
std::unique_ptr<T> data_;
};
// End of class my_unbounded_array
// Usage example
// vector<double, my_unbounded_array<double>> x(10, 0.); // x is just like normal ublas vector
// x.bind(10, ptr); // x is now holding external data pointed by raw pointer (ptr)
I hope this helps.
Univ. of Florida