/* -*- c++ -*- */
#ifndef AKAXISO_SHARED_PTR_H__
#define AKAXISO_SHARED_PTR_H__

/**
 * @file akaxiso/classes/shared_ptr.h
 * @author Tetsu Yoshioka (yoshioka@users.sourceforge.jp)
 */

#include <cassert>

namespace aka2 {

template <class T> class shared_ptr {
public:
  typedef shared_ptr<T> this_type;
  explicit shared_ptr(T* ptr = 0) : ptr_(ptr), refcnt_(new int(1)) {}
  shared_ptr(const shared_ptr<T>& rhs) : ptr_(rhs.ptr_), refcnt_(rhs.refcnt_) {
    ++*refcnt_;
  }
  ~shared_ptr() {
    dec_count();
  }

  shared_ptr<T>& operator =(const shared_ptr<T>& rhs) {
    if (ptr_ != rhs.ptr_) {
      dec_count();
      ptr_ = rhs.ptr_;
      refcnt_ = rhs.refcnt_;
      ++*refcnt_;
    }
    return *this;
  }

  bool operator ==(const T *rhs) const { return ptr_ == rhs; }
  bool operator !=(const T *rhs) const { return ptr_ != rhs; }

  bool operator ==(const this_type &rhs) const { 
    if (refcnt_ != rhs.refcnt_) {
      assert(ptr_ != rhs.ptr_);
      return false;
    }
    else {
      assert(ptr_ == rhs.ptr_);
      return true;
    }
  }
  bool operator !=(const this_type &rhs) const { return !(*this == rhs); }


  T* get() const { return ptr_; }

  T& operator *() const { return *ptr_; }
  T* operator ->() const { return ptr_; }

private:
  T* ptr_;
  int* refcnt_;

  void dec_count() {
    if (--*refcnt_ == 0) {
      delete ptr_;
      delete refcnt_;
    }
  }
};

} // namespace aka2

#endif /* AKAXISO_SHARED_PTR_H__ */
