/* This file is (c) 2008-2012 Konstantin Isakov <ikm@goldendict.org>
 * Part of GoldenDict. Licensed under GPLv3 or later, see the LICENSE file */

#ifndef __SPTR_HH_INCLUDED__
#define __SPTR_HH_INCLUDED__

// A generic non-intrusive smart-pointer template. We could use boost::, tr1::
// or whatever, but since there's no standard solution yet, it isn't worth
// the dependency given the simplicity of the template.

template< class T >
class sptr_base
{
  template< class TT > friend class sptr_base;

  T * p;
  unsigned * count;


  void increment()
  {
    if ( count )
      ++*count;
  }

public:

  sptr_base(): p( 0 ), count( 0 ) {}

  sptr_base( T * p_ ): p( p_ ), count( p ? new unsigned( 1 ) : 0 )
  {
  }

  sptr_base( sptr_base< T > const & other ): p( other.p ), count( other.count )
  { increment(); }

  // TT is meant to be a derivative of T
  template< class TT >
  sptr_base( sptr_base< TT > const & other ): p( ( T * ) other.p ),
    count( other.count )
  { increment(); }

  void reset()
  {
    if ( count )
    {
      if ( ! -- *count )
      {
        delete count;

        count = 0;

        if ( p )
        {
          T * p_ = p;
  
          p = 0;
  
          delete p_;
        }
      }
      else
      {
        p = 0;
        count = 0;
      }
    }
  }

  unsigned use_count() const
  { return count; }

  sptr_base & operator = ( sptr_base const & other )
  { if ( &other != this ) { reset(); p = other.p; count = other.count; increment(); }
    return * this; }

  bool operator ! ( void ) const
  { return !p; }

  bool operator == ( sptr_base const & other ) const
  { return p == other.p; }

  bool operator != ( sptr_base const & other ) const
  { return p != other.p; }

  ~sptr_base()
  { reset(); }

protected:

  T * get_base( void ) const
  { return p; }
};

template< class T >
class sptr: public sptr_base< T >
{
public:

  sptr() {}

  sptr( T * p ): sptr_base< T >( p ) {}
  
  // TT is meant to be a derivative of T
  template< class TT >
  sptr( sptr< TT > const & other ): sptr_base< T >( other ) {}
    
  // Retrieval

  T * get( void ) const
    { return sptr_base< T > :: get_base(); }

  T * operator -> ( void ) const
    { return get(); }

  T & operator * ( void ) const
    { return * get(); }

  // Check

  operator bool( void ) const
    { return get();  }

  bool operator ! ( void ) const
    { return !get(); }
};

template< class T >
class const_sptr: public sptr_base< T >
{
public:

  const_sptr() {}

  const_sptr( T * p_ ): sptr_base< T >( p_ ) {}
  
  const_sptr( sptr< T > const & other ): sptr_base< T >( other ) {}
  
  // TT is meant to be a derivative of T
  template< class TT >
  const_sptr( sptr_base< TT > const & other ): sptr_base< T >( other ) {}
    
  // Retrieval

  T const * get( void ) const
    { return sptr_base< T > :: get_base(); }

  T const * operator -> ( void ) const
    { return get(); }

  T const & operator * ( void ) const
    { return * get(); }
};


#endif

