Program Listing for File intrusive_ptr.h

Return to documentation for file (src/common/intrusive_ptr.h)

#pragma once

#include <cassert>
#include <iostream>
#include "common/logging.h"

// Smart pointer class for small objects with reference counting but no thread-safety.
// Inspired by boost::intrusive_ptr<T>.

// Compared to std::shared_ptr this is small and cheap to construct and destroy.
// Does not hold the counter, the pointed to class `T` needs to add
// ENABLE_INTRUSIVE_PTR(T) into the body of the class (private section). This adds
// the reference counters and count manipulation functions to the class.

#define ENABLE_INTRUSIVE_PTR(type)           \
  size_t references_{0};                     \
                                             \
  inline friend void intrusivePtrAddRef(type* x) {  \
    if(x != 0)                               \
      ++x->references_;                      \
  }                                          \
                                             \
  inline friend void intrusivePtrRelease(type* x) { \
    if(x != 0 && --x->references_ == 0) {    \
      delete x;                              \
      x = 0;                                 \
    }                                        \
  }                                          \
                                             \
  inline friend size_t references(type* x) {        \
    return x->references_;                   \
  }                                          \


template<class T>
class IntrusivePtr {
private:
  typedef IntrusivePtr this_type;

public:
  typedef T element_type;

  IntrusivePtr() : ptr_(0) {};

  IntrusivePtr(T* p)
  : ptr_(p) {
      if(ptr_ != 0)
        intrusivePtrAddRef(ptr_);
  }

  template<class Y>
  IntrusivePtr(const IntrusivePtr<Y>& rhs)
  : ptr_(rhs.get()) {
    if(ptr_ != 0)
      intrusivePtrAddRef(ptr_);
  }

  IntrusivePtr(const IntrusivePtr& rhs)
  : ptr_(rhs.ptr_) {
    if(ptr_ != 0)
      intrusivePtrAddRef(ptr_);
  }

  ~IntrusivePtr() {
    if(ptr_ != 0)
      intrusivePtrRelease(ptr_);
  }

  IntrusivePtr(IntrusivePtr&& rhs)
  : ptr_(rhs.ptr_) {
    rhs.ptr_ = 0;
  }

  inline size_t useCount() {
    return references(ptr_);
  }

  inline IntrusivePtr& operator=(IntrusivePtr&& rhs) {
    this_type(static_cast<IntrusivePtr&&>(rhs)).swap(*this);
    return *this;
  }

  inline IntrusivePtr& operator=(const IntrusivePtr& rhs) {
    this_type(rhs).swap(*this);
    return *this;
  }

  template<class Y>
  inline IntrusivePtr& operator=(const IntrusivePtr<Y>& rhs) {
    this_type(rhs).swap(*this);
    return *this;
  }

  inline void reset() {
    this_type().swap(*this);
  }

  inline void reset(T* rhs) {
    this_type(rhs).swap(*this);
  }

  inline T* get() const {
    return ptr_;
  }

  inline T* detach() {
    T* ret = ptr_;
    ptr_ = 0;
    return ret;
  }

  inline T& operator*() const {
    //ABORT_IF(ptr_ == 0, "Null pointer in IntrusivePtr");
    return *ptr_;
  }

  inline T* operator->() const {
    //ABORT_IF(ptr_ == 0, "Null pointer in IntrusivePtr");
    return ptr_;
  }

  inline explicit operator bool() const {
    return ptr_ != 0;
  }

  inline bool operator!() const {
    return ptr_ == 0;
  }

  inline void swap(IntrusivePtr& rhs) {
    T* tmp = ptr_;
    ptr_ = rhs.ptr_;
    rhs.ptr_ = tmp;
  }

private:
  T* ptr_;
};

template<class T, class U>
inline bool operator==(const IntrusivePtr<T>& a, const IntrusivePtr<U>& b) {
  return a.get() == b.get();
}

template<class T, class U>
inline bool operator!=(const IntrusivePtr<T>& a, const IntrusivePtr<U>& b) {
  return a.get() != b.get();
}

template<class T>
inline bool operator==(const IntrusivePtr<T>& a, std::nullptr_t) {
  return a.get() == 0;
}

template<class T>
inline bool operator!=(const IntrusivePtr<T>& a, std::nullptr_t) {
  return a.get() != 0;
}

template<class T>
inline bool operator==(const IntrusivePtr<T>& a, T* b) {
  return a.get() == b;
}

template<class T>
inline bool operator!=(const IntrusivePtr<T>& a, T* b) {
  return a.get() != b;
}

template<class T>
inline bool operator==(T* a, const IntrusivePtr<T>& b) {
  return a == b.get();
}

template<class T>
inline bool operator!=(T* a, const IntrusivePtr<T>& b) {
  return a != b.get();
}

template<class T, class U>
inline bool operator<(const IntrusivePtr<T>& a, const IntrusivePtr<U>& b) {
  return std::less<T*>()(a.get(), b.get());
}

template<class T>
inline void swap(IntrusivePtr<T> & a, IntrusivePtr<T> & b) {
  a.swap(b);
}

template<class E, class T, class Y>
std::basic_ostream<E, T>& operator<<(std::basic_ostream<E, T>& os, const IntrusivePtr<Y>& p) {
  os << p.get();
  return os;
}

// compatibility functions to make std::*_pointer_cast<T> work, also for automatic hashing
namespace std {
  template<class T>
  T* get_pointer(const IntrusivePtr<T>& p) {
    return p.get();
  }

  template<class T, class U>
  IntrusivePtr<T> static_pointer_cast(const IntrusivePtr<U>& p) {
    return static_cast<T*>(p.get());
  }

  template<class T, class U>
  IntrusivePtr<T> const_pointer_cast(const IntrusivePtr<U>& p) {
    return const_cast<T*>(p.get());
  }

  template<class T, class U>
  IntrusivePtr<T> dynamic_pointer_cast(const IntrusivePtr<U>& p) {
    return dynamic_cast<T*>(p.get());
  }

  // IntrusivePtr<T> can be used as hash map key
  template <class T> struct hash<IntrusivePtr<T>> {
    size_t operator()(const IntrusivePtr<T>& x) const {
      std::hash<size_t> hasher;
      return hasher((size_t)x.get());
    }
  };
}