Instantly share code, notes, and snippets.
Created
September 7, 2016 16:48
-
Save paniq/e21cd82c71a99e20e129aef2887ca26f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// an implementation for a managed object that can enumerate its references | |
template<typename T> | |
class shared_back_ptr; | |
template<typename T> | |
class enable_shared_back_from_this : | |
public std::enable_shared_from_this<T> { | |
public: | |
private: | |
friend class shared_back_ptr<T>; | |
shared_back_ptr<T> *_first_shared_back_ptr; | |
T *_shared_back_ptr_upcast() const { | |
return static_cast<T*>(this); | |
} | |
enable_shared_back_from_this(const enable_shared_back_from_this<T> &) = delete; | |
public: | |
enable_shared_back_from_this() : | |
_first_shared_back_ptr(nullptr) | |
{ | |
} | |
template<typename PointerT> | |
struct iteratorT { | |
PointerT *_p; | |
PointerT *_next; | |
iteratorT(PointerT *p) : | |
_p(p), | |
_next(p?p->_next:nullptr) | |
{} | |
bool operator !=(const iteratorT &other) const { | |
return _p != other._p; | |
} | |
void operator ++() { | |
if (_p) { | |
_p = _next; | |
_next = _p?_p->_next:nullptr; | |
} | |
} | |
PointerT *operator *() const { | |
return _p; | |
} | |
}; | |
struct back_ptr_iterable { | |
std::shared_ptr<T> _ref; | |
typedef iteratorT<shared_back_ptr<T> > iterator; | |
typedef iteratorT<const shared_back_ptr<T> > const_iterator; | |
back_ptr_iterable(const std::shared_ptr<T> &ref) : | |
_ref(ref) {} | |
iterator begin() { return _ref->_first_shared_back_ptr; } | |
const_iterator begin() const { return _ref->_first_shared_back_ptr; } | |
iterator end() { return nullptr; } | |
const_iterator end() const { return nullptr; } | |
}; | |
back_ptr_iterable back_ptrs() { | |
return back_ptr_iterable( | |
std::enable_shared_from_this<T>::shared_from_this()); | |
} | |
}; | |
template<typename T> | |
class shared_back_ptr { | |
friend struct std::hash< bangra::shared_back_ptr<T> >; | |
friend struct bangra::enable_shared_back_from_this<T>::iteratorT<shared_back_ptr<T> >; | |
friend struct bangra::enable_shared_back_from_this<T>::iteratorT<const shared_back_ptr<T> >; | |
private: | |
std::shared_ptr<T> _ref; | |
shared_back_ptr *_prev; | |
shared_back_ptr *_next; | |
void _link_shared_back_ptr() { | |
if (_ref) { | |
_prev = nullptr; | |
_next = _ref->_first_shared_back_ptr; | |
if (_next) { | |
assert(_next->_prev == nullptr); | |
_next->_prev = this; | |
} | |
_ref->_first_shared_back_ptr = this; | |
} | |
} | |
void _unlink_shared_back_ptr() { | |
if (_ref) { | |
if (_next) { | |
_next->_prev = _prev; | |
} | |
if (_prev) { | |
_prev->_next = _next; | |
} else { | |
assert(_ref->_first_shared_back_ptr == this); | |
_ref->_first_shared_back_ptr = _next; | |
} | |
_prev = _next = nullptr; | |
_ref = nullptr; | |
} | |
} | |
public: | |
shared_back_ptr() : | |
_ref(nullptr), | |
_prev(nullptr), | |
_next(nullptr) | |
{} | |
shared_back_ptr(const std::nullptr_t &) : | |
_ref(nullptr), | |
_prev(nullptr), | |
_next(nullptr) | |
{} | |
template<typename AnyT> | |
shared_back_ptr(const std::shared_ptr<AnyT> &ref) : | |
_ref(ref) | |
{ | |
_link_shared_back_ptr(); | |
} | |
shared_back_ptr(const shared_back_ptr &O) : | |
_ref(O._ref) { | |
_link_shared_back_ptr(); | |
} | |
~shared_back_ptr() { | |
_unlink_shared_back_ptr(); | |
} | |
T *get() const { | |
return _ref.get(); | |
} | |
T *operator ->() const { | |
return _ref.get(); | |
} | |
operator bool() const { | |
return (bool)_ref; | |
} | |
operator const std::shared_ptr<T> &() const { | |
return _ref; | |
} | |
void operator =(const std::nullptr_t &) { | |
_unlink_shared_back_ptr(); | |
} | |
template<typename AnyT> | |
void operator =(const std::shared_ptr<AnyT> &ref) { | |
if (_ref == ref) return; | |
_unlink_shared_back_ptr(); | |
_ref = ref; | |
_link_shared_back_ptr(); | |
} | |
}; | |
} // namespace bangra | |
namespace std { | |
template<typename T> | |
struct hash< bangra::shared_back_ptr<T> > | |
{ | |
typedef bangra::shared_back_ptr<T> argument_type; | |
typedef std::size_t result_type; | |
result_type operator()(argument_type const& s) const { | |
return std::hash<std::shared_ptr<T> >{}(s._ref); | |
} | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment