Skip to content

Instantly share code, notes, and snippets.

@paniq
Created September 7, 2016 16:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save paniq/e21cd82c71a99e20e129aef2887ca26f to your computer and use it in GitHub Desktop.
Save paniq/e21cd82c71a99e20e129aef2887ca26f to your computer and use it in GitHub Desktop.
// 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