/* -*- C++ -*- */
#include "ace/Guard_T.h"
#if !defined (ACE_NEW_THROWS_EXCEPTIONS)
#  include "ace/Log_Category.h"
#endif /* ACE_NEW_THROWS_EXCEPTIONS */

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

template <class ACE_LOCK> inline ACE_Bound_Ptr_Counter<ACE_LOCK> *
ACE_Bound_Ptr_Counter<ACE_LOCK>::internal_create (long init_obj_ref_count)
{
  ACE_Bound_Ptr_Counter<ACE_LOCK> *temp = 0;
  ACE_NEW_RETURN (temp,
                  ACE_Bound_Ptr_Counter<ACE_LOCK> (init_obj_ref_count),
                  0);
  return temp;
}

template <class ACE_LOCK> inline ACE_Bound_Ptr_Counter<ACE_LOCK> *
ACE_Bound_Ptr_Counter<ACE_LOCK>::create_strong (void)
{
  // Set initial object reference count to 1.
  ACE_Bound_Ptr_Counter<ACE_LOCK> *temp = internal_create (1);
#if defined (ACE_NEW_THROWS_EXCEPTIONS)
  if (temp == 0)
    ACE_throw_bad_alloc;
#else
  ACE_ASSERT (temp != 0);
#endif /* ACE_NEW_THROWS_EXCEPTIONS */
  return temp;
}



template <class ACE_LOCK> inline long
ACE_Bound_Ptr_Counter<ACE_LOCK>::attach_strong (ACE_Bound_Ptr_Counter<ACE_LOCK>* counter)
{
  ACE_GUARD_RETURN (ACE_LOCK, guard, counter->lock_, -1);

  // Can't attach a strong pointer to an object that has already been deleted.
  if (counter->obj_ref_count_ == -1)
    return -1;

  long new_obj_ref_count = ++counter->obj_ref_count_;
  ++counter->self_ref_count_;

  return new_obj_ref_count;
}

template <class ACE_LOCK> inline long
ACE_Bound_Ptr_Counter<ACE_LOCK>::detach_strong (ACE_Bound_Ptr_Counter<ACE_LOCK>* counter)
{
  ACE_Bound_Ptr_Counter<ACE_LOCK> *counter_del = 0;
  long new_obj_ref_count;

  {
    ACE_GUARD_RETURN (ACE_LOCK, guard, counter->lock_, -1);

    if ((new_obj_ref_count = --counter->obj_ref_count_) == 0)
      // Change the object reference count to -1 to indicate that the
      // object has been deleted, as opposed to a weak pointer that
      // simply hasn't had any strong pointers created from it yet.
      counter->obj_ref_count_ = -1;

    if (--counter->self_ref_count_ == 0)
      // Since counter contains the lock held by the guard, the
      // guard needs to be released before freeing the memory holding
      // the lock. So save the pointer to free, then release, then
      // free.
      counter_del = counter;

  }  // Release the lock

  delete counter_del;

  return new_obj_ref_count;
}

template <class ACE_LOCK> inline ACE_Bound_Ptr_Counter<ACE_LOCK> *
ACE_Bound_Ptr_Counter<ACE_LOCK>::create_weak (void)
{
  // Set initial object reference count to 0.

  ACE_Bound_Ptr_Counter<ACE_LOCK> *temp = internal_create (0);
#if defined (ACE_NEW_THROWS_EXCEPTIONS)
  if (temp == 0)
    ACE_throw_bad_alloc;
#else
  ACE_ASSERT (temp != 0);
#endif /* ACE_NEW_THROWS_EXCEPTIONS */
  return temp;
}

template <class ACE_LOCK> inline void
ACE_Bound_Ptr_Counter<ACE_LOCK>::attach_weak (ACE_Bound_Ptr_Counter<ACE_LOCK>* counter)
{
  ACE_GUARD (ACE_LOCK, guard, counter->lock_);

  ++counter->self_ref_count_;
}

template <class ACE_LOCK> inline void
ACE_Bound_Ptr_Counter<ACE_LOCK>::detach_weak (ACE_Bound_Ptr_Counter<ACE_LOCK>* counter)
{
  ACE_Bound_Ptr_Counter<ACE_LOCK> *counter_del = 0;

  {
    ACE_GUARD (ACE_LOCK, guard, counter->lock_);

    if (--counter->self_ref_count_ == 0)
      // Since counter contains the lock held by the guard, the
      // guard needs to be released before freeing the memory holding
      // the lock. So save the pointer to free, then release, then
      // free.
      counter_del = counter;

  }  // Release the lock

  delete counter_del;
}

template <class ACE_LOCK> inline bool
ACE_Bound_Ptr_Counter<ACE_LOCK>::object_was_deleted (ACE_Bound_Ptr_Counter<ACE_LOCK> *counter)
{
  ACE_GUARD_RETURN (ACE_LOCK, guard, counter->lock_, 0);

  return counter->obj_ref_count_ == -1;
}

template <class ACE_LOCK> inline
ACE_Bound_Ptr_Counter<ACE_LOCK>::ACE_Bound_Ptr_Counter (long init_obj_ref_count)
  : obj_ref_count_ (init_obj_ref_count),
    self_ref_count_ (1)
{
}

template <class ACE_LOCK> inline
ACE_Bound_Ptr_Counter<ACE_LOCK>::~ACE_Bound_Ptr_Counter (void)
{
}

template <class X, class ACE_LOCK> inline
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::ACE_Strong_Bound_Ptr (X *p)
  : counter_ (COUNTER::create_strong ()),
    ptr_ (p)
{
}

#if !defined (ACE_HAS_CPP11)
template <class X, class ACE_LOCK> inline
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::ACE_Strong_Bound_Ptr (auto_ptr<X> p)
  : counter_ (COUNTER::create_strong ()),
    ptr_ (p.release())
{
}
#endif /* !ACE_HAS_CPP11 */

template <class X, class ACE_LOCK> inline
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::ACE_Strong_Bound_Ptr (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &r)
  : counter_ (r.counter_),
    ptr_ (r.ptr_)
{
  COUNTER::attach_strong (this->counter_);
}

template <class X, class ACE_LOCK> inline
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::ACE_Strong_Bound_Ptr (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &r)
  : counter_ (r.counter_),
    ptr_ (r.ptr_)
{
  // When creating a strong pointer from a weak one we can't assume that the
  // underlying object still exists. Therefore we must check for a return value
  // of -1, which indicates that the object has been destroyed.
  if (COUNTER::attach_strong (this->counter_) == -1)
    {
      // Underlying object has already been deleted, so set this pointer to null.
      this->counter_ = COUNTER::create_strong ();
      this->ptr_ = 0;
    }
}

template <class X, class ACE_LOCK> inline
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::~ACE_Strong_Bound_Ptr (void)
{
  if (COUNTER::detach_strong (this->counter_) == 0)
    delete this->ptr_;
}

template <class X, class ACE_LOCK> inline void
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator = (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &rhs)
{
  // This will work if &r == this, by first increasing the ref count, but
  // why go through all that?
  if (&rhs == this)
    return;

  COUNTER *new_counter = rhs.counter_;
  X_t *new_ptr = rhs.ptr_;
  COUNTER::attach_strong (new_counter);
  if (COUNTER::detach_strong (this->counter_) == 0)
    delete this->ptr_;
  this->counter_ = new_counter;
  this->ptr_ = new_ptr;
}

template <class X, class ACE_LOCK> inline void
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator = (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &rhs)
{
  // This will work if &r == this, by first increasing the ref count, but
  // why go through all that?
  if (&rhs == this)
    return;

  COUNTER *new_counter = rhs.counter_;
  X_t *new_ptr = rhs.ptr_;

  // When creating a strong pointer from a weak one we can't assume that the
  // underlying object still exists. Therefore we must check for a return value
  // of -1, which indicates that the object has been destroyed.
  if (COUNTER::attach_strong (new_counter) == -1)
    {
      // Underlying object has already been deleted, so set this pointer to null.
      new_counter = COUNTER::create_strong ();
      new_ptr = 0;
    }

  if (COUNTER::detach_strong (this->counter_) == 0)
    delete this->ptr_;
  this->counter_ = new_counter;
  this->ptr_ = new_ptr;
}

template <class X, class ACE_LOCK> inline bool
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator== (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &r) const
{
  return this->ptr_ == r.ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator== (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &r) const
{
  // Use the weak pointer's operator== since it will check for null.
  return r == *this;
}

template <class X, class ACE_LOCK> inline bool
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator== (X *p) const
{
  return this->ptr_ == p;
}

template <class X, class ACE_LOCK> inline bool
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator!= (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &r) const
{
  return this->ptr_ != r.ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator!= (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &r) const
{
  // Use the weak pointer's operator!= since it will check for null.
  return r != *this;
}

template <class X, class ACE_LOCK> inline bool
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator!= (X *p) const
{
  return this->ptr_ != p;
}

template <class X, class ACE_LOCK> inline X *
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator-> (void) const
{
  return this->ptr_;
}

template<class X, class ACE_LOCK> inline X &
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::operator *() const
{
  return *this->ptr_;
}

template <class X, class ACE_LOCK> inline X*
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::get (void) const
{
  return this->ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::null (void) const
{
  return this->ptr_ == 0;
}

template<class X, class ACE_LOCK> inline void
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::reset (X *p)
{
  COUNTER *old_counter = this->counter_;
  X_t *old_ptr = this->ptr_;
  this->counter_ = COUNTER::create_strong ();
  this->ptr_ = p;
  if (COUNTER::detach_strong (old_counter) == 0)
    delete old_ptr;
}

#if !defined (ACE_HAS_CPP11)
template<class X, class ACE_LOCK> inline void
ACE_Strong_Bound_Ptr<X, ACE_LOCK>::reset (auto_ptr<X> p)
{
  COUNTER *old_counter = this->counter_;
  X_t *old_ptr = this->ptr_;
  this->counter_ = COUNTER::create_strong ();
  this->ptr_ = p.release ();
  if (COUNTER::detach_strong (old_counter) == 0)
    delete old_ptr;
}
#endif /* !ACE_HAS_CPP11 */

template <class X, class ACE_LOCK> inline
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::ACE_Weak_Bound_Ptr (X *p)
  : counter_ (COUNTER::create_weak ()),
    ptr_ (p)
{
}

template <class X, class ACE_LOCK> inline
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::ACE_Weak_Bound_Ptr (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &r)
  : counter_ (r.counter_),
    ptr_ (r.ptr_)
{
  COUNTER::attach_weak (this->counter_);
}

template <class X, class ACE_LOCK> inline
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::ACE_Weak_Bound_Ptr (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &r)
  : counter_ (r.counter_),
    ptr_ (r.ptr_)
{
  COUNTER::attach_weak (this->counter_);
}

template <class X, class ACE_LOCK> inline
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::~ACE_Weak_Bound_Ptr (void)
{
  COUNTER::detach_weak (this->counter_);
}

template <class X, class ACE_LOCK> inline void
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator = (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &rhs)
{
  // This will work if &rhs == this, by first increasing the ref count
  COUNTER *new_counter = rhs.counter_;
  COUNTER::attach_weak (new_counter);
  COUNTER::detach_weak (this->counter_);
  this->counter_ = new_counter;
  this->ptr_ = rhs.ptr_;
}

template <class X, class ACE_LOCK> inline void
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator = (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &rhs)
{
  // This will work if &rhs == this, by first increasing the ref count
  COUNTER *new_counter = rhs.counter_;
  COUNTER::attach_weak (new_counter);
  COUNTER::detach_weak (this->counter_);
  this->counter_ = new_counter;
  this->ptr_ = rhs.ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator== (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &r) const
{
  // A weak pointer must behave as though it is automatically set to null
  // if the underlying object has been deleted.
  if (COUNTER::object_was_deleted (this->counter_))
    return r.ptr_ == 0;

  return this->ptr_ == r.ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator== (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &r) const
{
  // A weak pointer must behave as though it is automatically set to null
  // if the underlying object has been deleted.
  if (COUNTER::object_was_deleted (this->counter_))
    return r.ptr_ == 0;

  return this->ptr_ == r.ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator== (X *p) const
{
  // A weak pointer must behave as though it is automatically set to null
  // if the underlying object has been deleted.
  if (COUNTER::object_was_deleted (this->counter_))
    return p == 0;

  return this->ptr_ == p;
}

template <class X, class ACE_LOCK> inline bool
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator!= (const ACE_Weak_Bound_Ptr<X, ACE_LOCK> &r) const
{
  // A weak pointer must behave as though it is automatically set to null
  // if the underlying object has been deleted.
  if (COUNTER::object_was_deleted (this->counter_))
    return r.ptr_ != 0;

  return this->ptr_ != r.ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator!= (const ACE_Strong_Bound_Ptr<X, ACE_LOCK> &r) const
{
  // A weak pointer must behave as though it is automatically set to null
  // if the underlying object has been deleted.
  if (COUNTER::object_was_deleted (this->counter_))
    return r.ptr_ != 0;

  return this->ptr_ != r.ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator!= (X *p) const
{
  // A weak pointer must behave as though it is automatically set to null
  // if the underlying object has been deleted.
  if (COUNTER::object_was_deleted (this->counter_))
    return p != 0;

  return this->ptr_ != p;
}

template <class X, class ACE_LOCK> inline ACE_Strong_Bound_Ptr<X, ACE_LOCK>
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::operator-> (void) const
{
  return ACE_Strong_Bound_Ptr<X, ACE_LOCK> (*this);
}

template <class X, class ACE_LOCK> inline ACE_Strong_Bound_Ptr<X, ACE_LOCK>
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::strong (void) const
{
  return ACE_Strong_Bound_Ptr<X, ACE_LOCK> (*this);
}

template <class X, class ACE_LOCK> inline X*
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::unsafe_get (void) const
{
  // We do not check if the object has been deleted, since this operation
  // is defined to be unsafe!
  return this->ptr_;
}

template <class X, class ACE_LOCK> inline bool
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::null (void) const
{
  // A weak pointer must behave as though it is automatically set to null
  // if the underlying object has been deleted.
  if (COUNTER::object_was_deleted (this->counter_))
    return true;

  return this->ptr_ == 0;
}

template<class X, class ACE_LOCK> inline void
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::reset (X *p)
{
  COUNTER *old_counter = this->counter_;
  this->counter_ = COUNTER::create_weak ();
  this->ptr_ = p;
  COUNTER::detach_weak (old_counter);
}

template<class X, class ACE_LOCK> inline long
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::add_ref ()
{
  return COUNTER::attach_strong (counter_);
}

template<class X, class ACE_LOCK> inline long
ACE_Weak_Bound_Ptr<X, ACE_LOCK>::remove_ref ()
{
  long new_obj_ref_count = COUNTER::detach_strong (counter_);
  if (new_obj_ref_count == 0)
    {
      delete this->ptr_;
      this->ptr_ = 0;
    }
  return new_obj_ref_count;
}

ACE_END_VERSIONED_NAMESPACE_DECL
