// -*- C++ -*-

//=============================================================================
/**
 *  @file    Refcounted_Auto_Ptr.h
 *
 *  @author John Tucker <JTucker@infoglide.com>
 */
//=============================================================================

#ifndef ACE_REFCOUNTED_AUTO_PTR_H
#define ACE_REFCOUNTED_AUTO_PTR_H

#include /**/ "ace/pre.h"

#include "ace/Auto_Ptr.h"
#include "ace/Atomic_Op.h"

#if !defined (ACE_LACKS_PRAGMA_ONCE)
# pragma once
#endif /* ACE_LACKS_PRAGMA_ONCE */

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

// Forward decl.
template <class X, class ACE_LOCK> class ACE_Refcounted_Auto_Ptr_Rep;
template <class X, class ACE_LOCK> class ACE_Refcounted_Auto_Ptr;

/**
 * @class ACE_Refcounted_Auto_Ptr
 *
 * @brief This class implements support for a reference counted auto_ptr.
 * Assigning or copying instances of an ACE_Refcounted_Auto_Ptr
 * will automatically increment the reference count. When the last
 * instance that references a ACE_Refcounted_Auto_Ptr instance is
 * destroyed or overwritten, it will invoke delete on its underlying
 * pointer.
 *
 * The ACE_Refcounted_Auto_Ptr works by maintaining a reference to a
 * separate representation object, ACE_Refcounted_Auto_Ptr_Rep. That
 * separate representation object contains the reference count and
 * the actual pointer value.
 */
template <class X, class ACE_LOCK>
class ACE_Refcounted_Auto_Ptr
{
public:
  /// Constructor that initializes an ACE_Refcounted_Auto_Ptr to
  /// the specified pointer value.
  explicit ACE_Refcounted_Auto_Ptr (X *p = 0);

  /// Copy constructor binds the new ACE_Refcounted_Auto_Ptr to the
  /// representation object referenced by @a r.
  /// An ACE_Refcounted_Auto_Ptr_Rep is created if necessary.
  ACE_Refcounted_Auto_Ptr (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r);

  /// Destructor. Releases the reference to the underlying representation.
  /// If the release of that reference causes its reference count to reach 0,
  /// the representation object will also be destroyed.
  virtual ~ACE_Refcounted_Auto_Ptr (void);

  /// Assignment operator that binds the current object and @a r to the same
  /// ACE_Refcounted_Auto_Ptr_Rep. An ACE_Refcounted_Auto_Ptr_Rep
  /// is created if necessary.
  void operator = (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r);

  /// Equality operator that returns @c true if both
  /// ACE_Refcounted_Auto_Ptr objects point to the same underlying
  /// representation. It does not compare the actual pointers.
  /**
   * @note It also returns @c true if both objects have just been
   *       instantiated and not used yet.
   */
  bool operator == (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r) const;

  /// Inequality operator, which is the opposite of equality.
  bool operator != (const ACE_Refcounted_Auto_Ptr<X, ACE_LOCK> &r) const;

  /// Redirection operator
  X *operator-> (void) const;

  /// Accessor method.
  X &operator *() const;

  /// Check rep easily.
  bool operator !() const;

  /// Check rep easily.
  operator bool () const;

  /// Releases the reference to the underlying representation object.
  /// @retval The pointer value prior to releasing it.
  X *release (void);

  /// Releases the current pointer value and then sets a new
  /// pointer value specified by @a p.
  void reset (X *p = 0);

  /// Get the pointer value.
  X *get (void) const;

  /// Get the reference count value.
  long count (void) const;

  /// Returns @c true if this object does not contain a valid pointer.
  bool null (void) const;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;

protected:
  /// the ACE_Refcounted_Auto_Ptr_Rep
  typedef ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> AUTO_REFCOUNTED_PTR_REP;

  /// Protect operations on the ACE_Refcounted_Auto_Ptr.
  AUTO_REFCOUNTED_PTR_REP *rep_;
};

/**
 * @class ACE_Refcounted_Auto_Ptr_Rep
 *
 * @brief An ACE_Refcounted_Auto_Ptr_Rep object encapsulates a pointer
 * to an object of type X. It uses a lock object of type ACE_LOCK to protect
 * access to the reference count.
 *
 * @internal ACE_Refcounted_Auto_Ptr_Rep is used internally by the
 * ACE_Refcounted_Auto_Ptr class and is only accessible through it.
 */
template <class X, class ACE_LOCK>
class ACE_Refcounted_Auto_Ptr_Rep
{
private:
  friend class ACE_Refcounted_Auto_Ptr<X, ACE_LOCK>;

  /// Get the pointer value.
  X *get (void) const;

  /// Get the reference count value.
  long count (void) const;

  /// Declare the dynamic allocation hooks.
  ACE_ALLOC_HOOK_DECLARE;

  // = Encapsulate reference count and object lifetime of instances.
  // These methods must go after the others to work around a bug with
  // Borland's C++ Builder...

  /// Allocate a new ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> instance,
  /// returning NULL if it cannot be created.
  static ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *internal_create (X *p);

  /// Create a ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> and initialize
  /// the reference count.
  static ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *create (X *p);

  /// Increase the reference count on @a rep.
  ///
  /// @retval @a rep if success, 0 if there's an error obtaining the lock
  ///         on @a rep.
  static ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *attach (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *&rep);

  /// Decreases the reference count and and deletes rep if there are no
  /// more references to rep.
  ///
  /// Precondition (rep != 0)
  static void detach (ACE_Refcounted_Auto_Ptr_Rep<X, ACE_LOCK> *&rep);

  /// Pointer to the result.
  ACE_Auto_Basic_Ptr<X> ptr_;

  /// Reference count.
  mutable ACE_Atomic_Op<ACE_LOCK, long> ref_count_;

private:
  // = Constructor and destructor private.
  ACE_Refcounted_Auto_Ptr_Rep (X *p = 0);
  ~ACE_Refcounted_Auto_Ptr_Rep (void);
};

ACE_END_VERSIONED_NAMESPACE_DECL

#include "ace/Refcounted_Auto_Ptr.inl"

#if defined (ACE_TEMPLATES_REQUIRE_SOURCE)
#include "ace/Refcounted_Auto_Ptr.cpp"
#endif /* ACE_TEMPLATES_REQUIRE_SOURCE */

#if defined (ACE_TEMPLATES_REQUIRE_PRAGMA)
#pragma implementation ("Refcounted_Auto_Ptr.cpp")
#endif /* ACE_TEMPLATES_REQUIRE_PRAGMA */

#include /**/ "ace/post.h"

#endif /* ACE_REFCOUNTED_AUTO_PTR_H */
