Initial commit
This commit is contained in:
816
common/ptr.h
Normal file
816
common/ptr.h
Normal file
@@ -0,0 +1,816 @@
|
||||
/* ScummVM - Graphic Adventure Engine
|
||||
*
|
||||
* ScummVM is the legal property of its developers, whose names
|
||||
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||
* file distributed with this source distribution.
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COMMON_PTR_H
|
||||
#define COMMON_PTR_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "common/noncopyable.h"
|
||||
#include "common/safe-bool.h"
|
||||
#include "common/types.h"
|
||||
|
||||
/* For nullptr_t */
|
||||
#include <cstddef>
|
||||
|
||||
namespace Common {
|
||||
|
||||
/**
|
||||
* @defgroup common_ptr Pointers
|
||||
* @ingroup common
|
||||
*
|
||||
* @brief API and templates for pointers.
|
||||
* @{
|
||||
*/
|
||||
|
||||
class BasePtrTrackerInternal {
|
||||
public:
|
||||
typedef int RefValue;
|
||||
|
||||
BasePtrTrackerInternal() : _weakRefCount(1), _strongRefCount(1) {}
|
||||
virtual ~BasePtrTrackerInternal() {}
|
||||
|
||||
void incWeak() {
|
||||
_weakRefCount++;
|
||||
}
|
||||
|
||||
void decWeak() {
|
||||
if (--_weakRefCount == 0)
|
||||
delete this;
|
||||
}
|
||||
|
||||
void incStrong() {
|
||||
_strongRefCount++;
|
||||
}
|
||||
|
||||
void decStrong() {
|
||||
if (--_strongRefCount == 0) {
|
||||
destructObject();
|
||||
decWeak();
|
||||
}
|
||||
}
|
||||
|
||||
bool isAlive() const {
|
||||
return _strongRefCount > 0;
|
||||
}
|
||||
|
||||
RefValue getStrongCount() const {
|
||||
return _strongRefCount;
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void destructObject() = 0;
|
||||
|
||||
private:
|
||||
RefValue _weakRefCount; // Weak ref count + 1 if object ref count > 0
|
||||
RefValue _strongRefCount;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class BasePtrTrackerImpl : public BasePtrTrackerInternal {
|
||||
public:
|
||||
BasePtrTrackerImpl(T *ptr) : _ptr(ptr) {}
|
||||
|
||||
protected:
|
||||
void destructObject() override {
|
||||
static_assert(sizeof(T) > 0, "SharedPtr: cannot delete incomplete type");
|
||||
delete _ptr;
|
||||
}
|
||||
|
||||
T *_ptr;
|
||||
};
|
||||
|
||||
template<class T, class DL>
|
||||
class BasePtrTrackerDeletionImpl : public BasePtrTrackerInternal {
|
||||
public:
|
||||
BasePtrTrackerDeletionImpl(T *ptr, DL d) : _ptr(ptr), _deleter(d) {}
|
||||
|
||||
private:
|
||||
void destructObject() override {
|
||||
_deleter(_ptr);
|
||||
}
|
||||
|
||||
T *_ptr;
|
||||
DL _deleter;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
class WeakPtr;
|
||||
|
||||
/**
|
||||
* A simple shared pointer implementation modelled after boost.
|
||||
*
|
||||
* This object keeps track of the assigned pointer and automatically
|
||||
* frees it when no more SharedPtr references to it exist.
|
||||
*
|
||||
* To achieve that the object implements an internal reference counting.
|
||||
* Thus you should try to avoid using the plain pointer after assigning
|
||||
* it to a SharedPtr object for the first time. If you still use the
|
||||
* plain pointer be sure you do not delete it on your own. You may also
|
||||
* not use the plain pointer to create a new SharedPtr object, since that
|
||||
* would result in a double deletion of the pointer sooner or later.
|
||||
*
|
||||
* Example creation:
|
||||
* Common::SharedPtr<int> pointer(new int(1));
|
||||
* would create a pointer to int. Later on usage via *pointer is the same
|
||||
* as for a normal pointer. If you need to access the plain pointer value
|
||||
* itself later on use the get method. The class also supplies a operator
|
||||
* ->, which does the same as the -> operator on a normal pointer.
|
||||
*
|
||||
* Be sure you are using new to initialize the pointer you want to manage.
|
||||
* If you do not use new for allocating, you have to supply a deleter as
|
||||
* second parameter when creating a SharedPtr object. The deleter has to
|
||||
* implement operator() which takes the pointer it should free as argument.
|
||||
*
|
||||
* Note that you have to specify the type itself not the pointer type as
|
||||
* template parameter.
|
||||
*
|
||||
* When creating a SharedPtr object from a normal pointer you need a real
|
||||
* definition of the type you want SharedPtr to manage, a simple forward
|
||||
* definition is not enough.
|
||||
*
|
||||
* The class has implicit upcast support, so if you got a class B derived
|
||||
* from class A, you can assign a pointer to B without any problems to a
|
||||
* SharedPtr object with template parameter A. The very same applies to
|
||||
* assignment of a SharedPtr<B> object to a SharedPtr<A> object.
|
||||
*
|
||||
* There are also operators != and == to compare two SharedPtr objects
|
||||
* with compatible pointers. Comparison between a SharedPtr object and
|
||||
* a plain pointer is only possible via SharedPtr::get.
|
||||
*/
|
||||
template<class T>
|
||||
class SharedPtr : public SafeBool<SharedPtr<T> > {
|
||||
template<class T2>
|
||||
friend class WeakPtr;
|
||||
template<class T2>
|
||||
friend class SharedPtr;
|
||||
public:
|
||||
// Invariant: If _tracker is non-null, then the object is alive
|
||||
typedef T *PointerType;
|
||||
typedef T &ReferenceType;
|
||||
typedef BasePtrTrackerInternal::RefValue RefValue;
|
||||
|
||||
SharedPtr() : _pointer(nullptr), _tracker(nullptr) {
|
||||
}
|
||||
|
||||
SharedPtr(std::nullptr_t) : _pointer(nullptr), _tracker(nullptr) {
|
||||
}
|
||||
|
||||
~SharedPtr() {
|
||||
if (_tracker)
|
||||
_tracker->decStrong();
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
explicit SharedPtr(T2 *p) : _pointer(p), _tracker(p ? (new BasePtrTrackerImpl<T2>(p)) : nullptr) {
|
||||
}
|
||||
|
||||
template<class T2, class DL>
|
||||
SharedPtr(T2 *p, DL d) : _pointer(p), _tracker(p ? (new BasePtrTrackerDeletionImpl<T2, DL>(p, d)) : nullptr) {
|
||||
}
|
||||
|
||||
SharedPtr(const SharedPtr<T> &r) : _pointer(r._pointer), _tracker(r._tracker) {
|
||||
if (_tracker)
|
||||
_tracker->incStrong();
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
SharedPtr(const SharedPtr<T2> &r) : _pointer(r._pointer), _tracker(r._tracker) {
|
||||
if (_tracker)
|
||||
_tracker->incStrong();
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
explicit SharedPtr(const WeakPtr<T2> &r) : _pointer(nullptr), _tracker(nullptr) {
|
||||
if (r._tracker && r._tracker->isAlive()) {
|
||||
_pointer = r._pointer;
|
||||
_tracker = r._tracker;
|
||||
_tracker->incStrong();
|
||||
}
|
||||
}
|
||||
|
||||
SharedPtr &operator=(const SharedPtr &r) {
|
||||
reset(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
SharedPtr &operator=(const SharedPtr<T2> &r) {
|
||||
reset(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
T &operator*() const { assert(_pointer); return *_pointer; }
|
||||
T *operator->() const { assert(_pointer); return _pointer; }
|
||||
|
||||
/**
|
||||
* Returns the plain pointer value. Be sure you know what you
|
||||
* do if you are continuing to use that pointer.
|
||||
*
|
||||
* @return the pointer the SharedPtr object manages
|
||||
*/
|
||||
PointerType get() const { return _pointer; }
|
||||
|
||||
template<class T2>
|
||||
bool operator==(const SharedPtr<T2> &r) const {
|
||||
return _pointer == r.get();
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
bool operator!=(const SharedPtr<T2> &r) const {
|
||||
return _pointer != r.get();
|
||||
}
|
||||
|
||||
bool operator==(std::nullptr_t) const {
|
||||
return _pointer == nullptr;
|
||||
}
|
||||
|
||||
bool operator!=(std::nullptr_t) const {
|
||||
return _pointer != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implicit conversion operator to bool for convenience, to make
|
||||
* checks like "if (sharedPtr) ..." possible.
|
||||
*/
|
||||
bool operator_bool() const {
|
||||
return _pointer != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of strong references to the object.
|
||||
*/
|
||||
int refCount() const {
|
||||
if (_tracker == nullptr)
|
||||
return 0;
|
||||
return _tracker->getStrongCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the object is the only object referring
|
||||
* to the assigned pointer. This should just be used for
|
||||
* debugging purposes.
|
||||
*/
|
||||
bool unique() const {
|
||||
return refCount() == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the object to a NULL pointer.
|
||||
*/
|
||||
void reset() {
|
||||
if (_tracker)
|
||||
_tracker->decStrong();
|
||||
_tracker = nullptr;
|
||||
_pointer = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the object to the specified shared pointer
|
||||
*/
|
||||
template<class T2>
|
||||
void reset(const SharedPtr<T2> &r) {
|
||||
BasePtrTrackerInternal *oldTracker = _tracker;
|
||||
|
||||
_pointer = r._pointer;
|
||||
_tracker = r._tracker;
|
||||
|
||||
if (_tracker)
|
||||
_tracker->incStrong();
|
||||
if (oldTracker)
|
||||
oldTracker->decStrong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the object to the specified weak pointer
|
||||
*/
|
||||
template<class T2>
|
||||
void reset(const WeakPtr<T2> &r) {
|
||||
BasePtrTrackerInternal *oldTracker = _tracker;
|
||||
|
||||
if (r._tracker && r._tracker->isAlive()) {
|
||||
_tracker = r._tracker;
|
||||
_pointer = r._pointer;
|
||||
_tracker->incStrong();
|
||||
} else {
|
||||
_tracker = nullptr;
|
||||
_pointer = nullptr;
|
||||
}
|
||||
|
||||
if (oldTracker)
|
||||
oldTracker->decStrong();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the object to the specified pointer
|
||||
*/
|
||||
void reset(T *ptr) {
|
||||
if (_tracker)
|
||||
_tracker->decStrong();
|
||||
|
||||
_pointer = ptr;
|
||||
_tracker = new BasePtrTrackerImpl<T>(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of static_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
SharedPtr<T2> staticCast() const {
|
||||
return SharedPtr<T2>(static_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of dynamic_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
SharedPtr<T2> dynamicCast() const {
|
||||
return SharedPtr<T2>(dynamic_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of const_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
SharedPtr<T2> constCast() const {
|
||||
return SharedPtr<T2>(const_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of const_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
SharedPtr<T2> reinterpretCast() const {
|
||||
return SharedPtr<T2>(reinterpret_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
private:
|
||||
SharedPtr(T *pointer, BasePtrTrackerInternal *tracker) : _pointer(pointer), _tracker(tracker) {
|
||||
if (tracker)
|
||||
tracker->incStrong();
|
||||
}
|
||||
|
||||
T *_pointer;
|
||||
BasePtrTrackerInternal *_tracker;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Implements a smart pointer that holds a non-owning ("weak") reference to
|
||||
* a pointer. It needs to be converted to a SharedPtr to access it.
|
||||
*/
|
||||
template<class T>
|
||||
class WeakPtr {
|
||||
template<class T2>
|
||||
friend class WeakPtr;
|
||||
template<class T2>
|
||||
friend class SharedPtr;
|
||||
public:
|
||||
WeakPtr() : _pointer(nullptr), _tracker(nullptr) {
|
||||
}
|
||||
|
||||
WeakPtr(std::nullptr_t) : _pointer(nullptr), _tracker(nullptr) {
|
||||
}
|
||||
|
||||
WeakPtr(const WeakPtr<T> &r) : _pointer(r._pointer), _tracker(r._tracker) {
|
||||
if (_tracker)
|
||||
_tracker->incWeak();
|
||||
}
|
||||
|
||||
~WeakPtr() {
|
||||
if (_tracker)
|
||||
_tracker->decWeak();
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
WeakPtr(const WeakPtr<T2> &r) : _pointer(r._pointer), _tracker(r._tracker) {
|
||||
if (_tracker)
|
||||
_tracker->incWeak();
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
WeakPtr(const SharedPtr<T2> &r) : _pointer(r._pointer), _tracker(r._tracker) {
|
||||
if (_tracker)
|
||||
_tracker->incWeak();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of static_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
WeakPtr<T2> staticCast() const {
|
||||
return WeakPtr<T2>(expired() ? nullptr : static_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of dynamic_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
WeakPtr<T2> dynamicCast() const {
|
||||
return WeakPtr<T2>(expired() ? nullptr : dynamic_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of const_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
WeakPtr<T2> constCast() const {
|
||||
return WeakPtr<T2>(expired() ? nullptr : const_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the equivalent of const_cast to a new pointer type
|
||||
*/
|
||||
template<class T2>
|
||||
WeakPtr<T2> reinterpretCast() const {
|
||||
return WeakPtr<T2>(expired() ? nullptr : reinterpret_cast<T2 *>(_pointer), _tracker);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a SharedPtr that manages the referenced object
|
||||
*/
|
||||
SharedPtr<T> lock() const {
|
||||
return SharedPtr<T>(*this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of strong references to the object.
|
||||
*/
|
||||
int refCount() const {
|
||||
if (_tracker == nullptr)
|
||||
return 0;
|
||||
return _tracker->getStrongCount();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the referenced object isn't valid
|
||||
*/
|
||||
bool expired() const {
|
||||
return _tracker == nullptr || _tracker->getStrongCount() == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this precedes another weak pointer in owner-based order
|
||||
*/
|
||||
template<class T2>
|
||||
bool owner_before(const WeakPtr<T2>& other) const {
|
||||
return _tracker < other._tracker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether this precedes a shared pointer in owner-based order
|
||||
*/
|
||||
template<class T2>
|
||||
bool owner_before(const SharedPtr<T2> &other) const {
|
||||
return _tracker < other._tracker;
|
||||
}
|
||||
|
||||
WeakPtr<T> &operator=(const WeakPtr<T> &r) {
|
||||
reset(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
WeakPtr<T> &operator=(const WeakPtr<T2> &r) {
|
||||
reset(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class T2>
|
||||
WeakPtr<T> &operator=(const SharedPtr<T2> &r) {
|
||||
reset(r);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the object to a NULL pointer.
|
||||
*/
|
||||
void reset() {
|
||||
if (_tracker)
|
||||
_tracker->decWeak();
|
||||
_tracker = nullptr;
|
||||
_pointer = nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the object to the specified shared pointer
|
||||
*/
|
||||
template<class T2>
|
||||
void reset(const SharedPtr<T2> &r) {
|
||||
BasePtrTrackerInternal *oldTracker = _tracker;
|
||||
|
||||
_pointer = r._pointer;
|
||||
_tracker = r._tracker;
|
||||
|
||||
if (_tracker)
|
||||
_tracker->incWeak();
|
||||
if (oldTracker)
|
||||
oldTracker->decWeak();
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the object to the specified weak pointer
|
||||
*/
|
||||
template<class T2>
|
||||
void reset(const WeakPtr<T2> &r) {
|
||||
BasePtrTrackerInternal *oldTracker = _tracker;
|
||||
|
||||
_pointer = r._pointer;
|
||||
_tracker = r._tracker;
|
||||
|
||||
if (_tracker)
|
||||
_tracker->incWeak();
|
||||
if (oldTracker)
|
||||
oldTracker->decWeak();
|
||||
}
|
||||
|
||||
private:
|
||||
WeakPtr(T *pointer, BasePtrTrackerInternal *tracker) : _pointer(pointer), _tracker(tracker) {
|
||||
if (tracker)
|
||||
tracker->incWeak();
|
||||
}
|
||||
|
||||
T *_pointer;
|
||||
BasePtrTrackerInternal *_tracker;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct DefaultDeleter {
|
||||
inline void operator()(T *object) {
|
||||
static_assert(sizeof(T) > 0, "cannot delete incomplete type");
|
||||
delete object;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ArrayDeleter {
|
||||
inline void operator()(T *object) {
|
||||
static_assert(sizeof(T) > 0, "cannot delete incomplete type");
|
||||
delete[] object;
|
||||
}
|
||||
};
|
||||
|
||||
template<typename T, class DL = DefaultDeleter<T> >
|
||||
class ScopedPtr : private NonCopyable, public SafeBool<ScopedPtr<T, DL> > {
|
||||
template<class T2, class DL2>
|
||||
friend class ScopedPtr;
|
||||
public:
|
||||
typedef T ValueType;
|
||||
typedef T *PointerType;
|
||||
typedef T &ReferenceType;
|
||||
|
||||
explicit ScopedPtr(PointerType o = nullptr) : _pointer(o) {}
|
||||
ScopedPtr(std::nullptr_t) : _pointer(nullptr) {}
|
||||
|
||||
/**
|
||||
* Move constructor
|
||||
*/
|
||||
template<class T2>
|
||||
ScopedPtr(ScopedPtr<T2> &&o) : _pointer(o._pointer) {
|
||||
o._pointer = nullptr;
|
||||
}
|
||||
|
||||
ReferenceType operator*() const { return *_pointer; }
|
||||
PointerType operator->() const { return _pointer; }
|
||||
|
||||
/**
|
||||
* Implicit conversion operator to bool for convenience, to make
|
||||
* checks like "if (scopedPtr) ..." possible.
|
||||
*/
|
||||
bool operator_bool() const { return _pointer != nullptr; }
|
||||
|
||||
~ScopedPtr() {
|
||||
DL()(_pointer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the pointer with the new value. Old object will be destroyed.
|
||||
*/
|
||||
void reset(PointerType o = nullptr) {
|
||||
DL()(_pointer);
|
||||
_pointer = o;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affectation with nullptr
|
||||
*/
|
||||
ScopedPtr &operator=(std::nullptr_t) {
|
||||
reset(nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces the ScopedPtr with another scoped ScopedPtr.
|
||||
*/
|
||||
template<class T2>
|
||||
ScopedPtr &operator=(ScopedPtr<T2> &&other) {
|
||||
PointerType oldPointer = _pointer;
|
||||
_pointer = other._pointer;
|
||||
other._pointer = nullptr;
|
||||
DL()(oldPointer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plain pointer value.
|
||||
*
|
||||
* @return the pointer the ScopedPtr manages
|
||||
*/
|
||||
PointerType get() const { return _pointer; }
|
||||
|
||||
/**
|
||||
* Returns the plain pointer value and releases ScopedPtr.
|
||||
* After release() call you need to delete object yourself
|
||||
*
|
||||
* @return the pointer the ScopedPtr manages
|
||||
*/
|
||||
PointerType release() {
|
||||
PointerType r = _pointer;
|
||||
_pointer = nullptr;
|
||||
return r;
|
||||
}
|
||||
|
||||
private:
|
||||
PointerType _pointer;
|
||||
};
|
||||
|
||||
template<typename T, class DL = DefaultDeleter<T> >
|
||||
class DisposablePtr : private NonCopyable, public SafeBool<DisposablePtr<T, DL> > {
|
||||
public:
|
||||
typedef T ValueType;
|
||||
typedef T *PointerType;
|
||||
typedef T &ReferenceType;
|
||||
|
||||
explicit DisposablePtr(PointerType o, DisposeAfterUse::Flag dispose) : _pointer(o), _dispose(dispose), _shared() {}
|
||||
explicit DisposablePtr(SharedPtr<T> o) : _pointer(o.get()), _dispose(DisposeAfterUse::NO), _shared(o) {}
|
||||
DisposablePtr(DisposablePtr<T, DL>&& o) : _pointer(o._pointer), _dispose(o._dispose), _shared(o._shared) {
|
||||
o._pointer = nullptr;
|
||||
o._dispose = DisposeAfterUse::NO;
|
||||
o._shared.reset();
|
||||
}
|
||||
|
||||
~DisposablePtr() {
|
||||
if (_dispose) DL()(_pointer);
|
||||
}
|
||||
|
||||
ReferenceType operator*() const { return *_pointer; }
|
||||
PointerType operator->() const { return _pointer; }
|
||||
|
||||
/**
|
||||
* Implicit conversion operator to bool for convenience, to make
|
||||
* checks like "if (scopedPtr) ..." possible.
|
||||
*/
|
||||
bool operator_bool() const { return _pointer != nullptr; }
|
||||
|
||||
/**
|
||||
* Resets the pointer with the new value. Old object will be destroyed if flagged as disposable.
|
||||
*/
|
||||
void reset(PointerType o, DisposeAfterUse::Flag dispose) {
|
||||
if (_dispose) DL()(_pointer);
|
||||
_pointer = o;
|
||||
_dispose = dispose;
|
||||
_shared.reset();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the pointer. Old object will be destroyed if flagged as disposable.
|
||||
*/
|
||||
void reset() {
|
||||
reset(nullptr, DisposeAfterUse::NO);
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
bool isDynamicallyCastable() {
|
||||
return dynamic_cast<T2 *>(_pointer) != nullptr;
|
||||
}
|
||||
|
||||
/* Destroys the smart pointer while returning a pointer to
|
||||
assign to a new object.
|
||||
*/
|
||||
template <class T2, class DL2 = DefaultDeleter<T2> >
|
||||
DisposablePtr<T2, DL2> moveAndDynamicCast() {
|
||||
DisposablePtr<T2, DL2> ret(nullptr, DisposeAfterUse::NO);
|
||||
ret._pointer = dynamic_cast<T2 *>(_pointer);
|
||||
ret._dispose = _dispose;
|
||||
ret._shared = _shared.template dynamicCast<T2>();
|
||||
_pointer = nullptr;
|
||||
_dispose = DisposeAfterUse::NO;
|
||||
_shared.reset();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the plain pointer value.
|
||||
*
|
||||
* @return the pointer the DisposablePtr manages
|
||||
*/
|
||||
PointerType get() const { return _pointer; }
|
||||
|
||||
template <class T2, class DL2>
|
||||
friend class DisposablePtr;
|
||||
|
||||
private:
|
||||
DisposablePtr() : _pointer(nullptr), _dispose(DisposeAfterUse::NO), _shared() {}
|
||||
PointerType _pointer;
|
||||
DisposeAfterUse::Flag _dispose;
|
||||
SharedPtr<T> _shared;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* UnalignedPtr: Allows pointers to and access of memory addresses where the underlying data
|
||||
* doesn't have proper alignment.
|
||||
*/
|
||||
|
||||
#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_ARM) || defined(_M_ARM64))
|
||||
|
||||
template<class T>
|
||||
class UnalignedPtr {
|
||||
public:
|
||||
UnalignedPtr();
|
||||
UnalignedPtr(__unaligned T *ptr);
|
||||
|
||||
T load() const;
|
||||
void store(const T &value) const;
|
||||
|
||||
private:
|
||||
__unaligned T *_ptr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
UnalignedPtr<T>::UnalignedPtr() : _ptr(nullptr) {
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UnalignedPtr<T>::UnalignedPtr(__unaligned T *ptr) : _ptr(ptr) {
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T UnalignedPtr<T>::load() const {
|
||||
return *_ptr;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void UnalignedPtr<T>::store(const T &value) const {
|
||||
*_ptr = value;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<class T>
|
||||
class UnalignedPtr {
|
||||
public:
|
||||
UnalignedPtr();
|
||||
UnalignedPtr(T *ptr);
|
||||
|
||||
T load() const;
|
||||
void store(const T &value) const;
|
||||
|
||||
private:
|
||||
void *_ptr;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
UnalignedPtr<T>::UnalignedPtr() : _ptr(nullptr) {
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UnalignedPtr<T>::UnalignedPtr(T *ptr) : _ptr(ptr) {
|
||||
}
|
||||
|
||||
template<class T>
|
||||
T UnalignedPtr<T>::load() const {
|
||||
T result;
|
||||
memcpy(&result, _ptr, sizeof(T));
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void UnalignedPtr<T>::store(const T &value) const {
|
||||
memcpy(_ptr, &value, sizeof(T));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/** @} */
|
||||
|
||||
} // End of namespace Common
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user