Newer
Older
#ifndef Q_MOC_RUN
#include <mutex>
Janik Zikovsky
committed
#include <vector>
namespace Mantid {
namespace Kernel {
Janik Zikovsky
committed
/**
Russell Taylor
committed
\brief Implements a copy on write data template
It is thread safe and works in the Standard template
Russell Taylor
committed
libraries (but appropriate functionals are needed for
Renamed from RefControl on the 11/12/2007,
as it was agreed that copy on write pointer better
The underlying data can be accessed via the normal pointer
semantics but call the access function if the data is required
to be modified.
Copyright © 2007-2010 ISIS Rutherford Appleton Laboratory, NScD Oak Ridge
National Laboratory & European Spallation Source
Mantid is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
Mantid is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
File change history is stored at: <https://github.com/mantidproject/mantid>
template <typename DataType> class cow_ptr {
public:
using ptr_type = boost::shared_ptr<DataType>; ///< typedef for the storage
using value_type = DataType; ///< typedef for the data type
private:
ptr_type Data; ///< Real object Ptr
std::mutex copyMutex;
cow_ptr(ptr_type &&resourceSptr) noexcept;
cow_ptr(const ptr_type &resourceSptr) noexcept;
/// Constructs a cow_ptr with no managed object, i.e. empty cow_ptr.
constexpr cow_ptr(std::nullptr_t) noexcept : Data(nullptr) {}
cow_ptr(const cow_ptr<DataType> &) noexcept;
// Move is hand-written, since std::mutex member prevents auto-generation.
cow_ptr(cow_ptr<DataType> &&other) noexcept : Data(std::move(other.Data)) {}
cow_ptr<DataType> &operator=(const cow_ptr<DataType> &) noexcept;
// Move is hand-written, since std::mutex member prevents auto-generation.
cow_ptr<DataType> &operator=(cow_ptr<DataType> &&rhs) noexcept {
Data = std::move(rhs.Data);
return *this;
}
cow_ptr<DataType> &operator=(const ptr_type &) noexcept;
/// Returns the stored pointer.
const DataType *get() const noexcept { return Data.get(); }
/// Checks if *this stores a non-null pointer, i.e. whether get() != nullptr.
explicit operator bool() const noexcept { return bool(Data); }
/// Returns the number of different shared_ptr instances (this included)
/// managing the current object. If there is no managed object, 0 is returned.
long use_count() const noexcept { return Data.use_count(); }
/// Checks if *this is the only shared_ptr instance managing the current
/// object, i.e. whether use_count() == 1.
bool unique() const noexcept { return Data.unique(); }
const DataType &operator*() const {
return *Data;
} ///< Pointer dereference access
const DataType *operator->() const {
return Data.get();
} ///<indirectrion dereference access
bool operator==(const cow_ptr<DataType> &A) const noexcept {
return Data == A.Data;
} ///< Based on ptr equality
bool operator!=(const cow_ptr<DataType> &A) const noexcept {
return Data != A.Data;
} ///< Based on ptr inequality
/**
Constructor : creates a new cow_ptr around the resource
resource is a sink.
*/
template <typename DataType>
cow_ptr<DataType>::cow_ptr(DataType *resourcePtr)
: Data(resourcePtr) {}
Janik Zikovsky
committed
/**
Russell Taylor
committed
Constructor : creates new data() object
*/
template <typename DataType>
cow_ptr<DataType>::cow_ptr()
/**
Copy constructor : double references the data object
@param A :: object to copy
*/
// Note: Need custom implementation, since std::mutex is not copyable.
template <typename DataType>
cow_ptr<DataType>::cow_ptr(const cow_ptr<DataType> &A) noexcept
: Data(boost::atomic_load(&A.Data)) {}
/**
Assignment operator : double references the data object
maybe drops the old reference.
@param A :: object to copy
@return *this
*/
// Note: Need custom implementation, since std::mutex is not copyable.
template <typename DataType>
cow_ptr<DataType> &cow_ptr<DataType>::
operator=(const cow_ptr<DataType> &A) noexcept {
if (this != &A) {
boost::atomic_store(&Data, boost::atomic_load(&A.Data));
}
return *this;
}
Janik Zikovsky
committed
/**
Russell Taylor
committed
Assignment operator : double references the data object
maybe drops the old reference.
Janik Zikovsky
committed
@param A :: object to copy
@return *this
Russell Taylor
committed
*/
cow_ptr<DataType> &cow_ptr<DataType>::operator=(const ptr_type &A) noexcept {
boost::atomic_store(&Data, boost::atomic_load(&A));
Russell Taylor
committed
}
Janik Zikovsky
committed
/**
Russell Taylor
committed
Access function.
If data is shared, creates a copy of Data so that it can be modified.
In certain situations this function is not thread safe. Specifically it is not
thread
safe in the presence of a simultaneous cow_ptr copy. Copies of the underlying
data are only
made when the reference count > 1.
Janik Zikovsky
committed
@return new copy of *this, if required
Russell Taylor
committed
*/
template <typename DataType> DataType &cow_ptr<DataType>::access() {
// Use a double-check for sharing so that we only acquire the lock if
// absolutely necessary
std::lock_guard<std::mutex> lock{copyMutex};
// Check again because another thread may have taken copy and dropped
// reference count since previous check
if (!Data.unique()) {
boost::atomic_store(&Data, boost::make_shared<DataType>(*Data));
}
Russell Taylor
committed
}
template <typename DataType>
cow_ptr<DataType>::cow_ptr(ptr_type &&resourceSptr) noexcept {
boost::atomic_store(&this->Data, std::move(resourceSptr));
cow_ptr<DataType>::cow_ptr(const ptr_type &resourceSptr) noexcept {
boost::atomic_store(&this->Data, boost::atomic_load(&resourceSptr));
Janik Zikovsky
committed
/// typedef for the data storage used in Mantid matrix workspaces
using MantidVec = std::vector<double>;
Janik Zikovsky
committed
/// typedef for the pointer to data storage used in Mantid matrix workspaces
using MantidVecPtr = Kernel::cow_ptr<MantidVec>;
Janik Zikovsky
committed