// Copyright 2020 Siemens Digital Industries Software
// ==================================================
// Copyright 2013.
// Siemens Product Lifecycle Management Software Inc.
// All Rights Reserved.
// ==================================================
// Copyright 2020 Siemens Digital Industries Software

/** 
    @file 
    Implements a reference counting mechanism.

    @note This class should not be used as such. 
    <br>Use the class #SharedPtr instead.
*/

/*
Background: 
Base implementation copied from NX. The code was copied as this class was available in 
latest NX libraries which are currently not supported in Tc.
The implementation in NX uses code from Boost library, hence a reference to Boost license in included.

Changes were made to NX code to conform it to Tc. These changes include :
- namespace change
- using default heap instead of SM.
- comment code about WeakPtr as we arent supporting weak_ptr currently.
- changes in constructor to remove NX specific error handling.
*/

/* Boost license: as base implementation comes for Boost, including its license.

Copyright (c) 2001, 2002, 2003 Peter Dimov and Multi Media Ltd.
Copyright 2004-2005 Peter Dimov

Distributed under the Boost Software License, Version 1.0. 
(See copy at http://www.boost.org/LICENSE_1_0.txt)
*/
#ifndef TEAMCENTER_BASE_UTILS_SHARED_COUNT_HXX
#define TEAMCENTER_BASE_UTILS_SHARED_COUNT_HXX

#include <memory>           // std::auto_ptr
#include <functional>       // std::less
#include <base_utils/SharedPtrCountedImpl.hxx>

namespace Teamcenter
{
namespace Internal
{
    class WeakCount;
    
    class SharedCount
    {
        friend class WeakCount;
    public:
        inline SharedCount();
        inline SharedCount( SharedCount const & r );

        
        template< class Y > inline SharedCount( Y * p ): pi_( 0 )
        {
            // Take ownership of pointer before newing up refcount,
            // in case we run out of memory.
            std::auto_ptr< Y > guard( p );   
            pi_ = new Teamcenter::Internal::SharedPtrCountedBaseImpl_p< Y >( p );
            guard.release();
        }

        /// Create shared_ptr from auto_ptr. Acquires ownership from the auto_ptr.
        template< class Y > inline SharedCount( std::auto_ptr< Y > & r )
        : pi_( new Teamcenter::Internal::SharedPtrCountedBaseImpl_p< Y >( r.get() ) )        
        {
            r.release();
        }
        
#if 0 // commented as custom deallocator isnt supported.
        template< class P, class D > SharedCount( P p, D d );
#endif

#if 0 // commented as we dont support weak_ptr. Might need some changes to code for Tc.
        BASE_UTILS_API explicit SharedCount( WeakCount const & r ); 
#endif
        inline ~SharedCount(); // nothrow
        
        inline SharedCount& operator= ( SharedCount const & r ); // nothrow       
        inline void swap( SharedCount & r ); // nothrow

        inline long use_count() const; // nothrow

        /// Returns true if this is the only shared pointer holding the pointer.
        inline bool unique() const; // nothrow

        //lint -e1761 Line is wrongly confusing these operators as hiding other ones.
        friend inline bool operator==( SharedCount const & a, SharedCount const & b );       
        
        //lint -e1761 Line is wrongly confusing these operators as hiding other ones.
        friend inline bool operator<( SharedCount const & a, SharedCount const & b );        
        
    private:
        Teamcenter::Internal::SharedPtrCountedBase * pi_; // pointer to reference count 

    }; // class SharedCount
   
//// Implementation details For SharedCount   

    inline SharedCount::SharedCount(): pi_( 0 ) 
    {
    }

    inline SharedCount::~SharedCount() // nothrow
    {
        if( pi_ != NULL ) 
        {
            pi_->release();
        }
        
    } 
    
    inline SharedCount::SharedCount( SharedCount const & r )
        : pi_( r.pi_ ) //lint !e1554 
    {
        if( pi_ != NULL )
        {
            pi_->add_ref_copy();
        }
    }

#if 0 // commenting as we do not support custom deallocator. Code might need changes for Tc erorr handling.
    template< class P, class D > SharedCount::SharedCount( P p, D d ): pi_( 0 )
    {
        ERROR_PROTECT
            pi_ = new Teamcenter::Internal::SharedPtrCountedBaseImpl_pd< P, D >( p, d );
        ERROR_RECOVER
            d( p ); // delete p
        ERROR_reraise();
        ERROR_END
    }
#endif

#if 0 // Commented as we do not support weak_ptr at the moment. might need some changes for Tc error handling.
    inline SharedCount::SharedCount( Teamcenter::Internal::WeakCount const & r ): pi_( r.pi_ )
    {
        if ( pi_ == NULL || !pi_->add_ref_lock() )
        {
            ERROR_severe( ERROR_line, 0, "bad Teamcenter::BadWeakPtr()" );
        }
    }
#endif 

    inline SharedCount& SharedCount::operator= ( SharedCount const & rhs ) 
    {
        if( &rhs != this )
        {
            SharedPtrCountedBase* tmp = rhs.pi_;

            if( tmp != NULL )
            {
                tmp->add_ref_copy();
            }

            if( pi_ != NULL )
            {
                pi_->release();
            }

            pi_ = tmp;
        }

        return *this;
    }

    inline void SharedCount::swap( SharedCount & other ) // nothrow
    {
        std::swap( pi_, other.pi_ );
    }

    inline long SharedCount::use_count() const // nothrow
    {
        return pi_ != NULL ? pi_->use_count(): 0;
    }

    inline bool SharedCount::unique() const // nothrow
    {
        return use_count() == 1;
    }

#if 0 // custom deallocator isnt supported
    inline void * SharedCount::get_deleter( std::type_info const & ti ) const
    {
        return pi_? pi_->get_deleter( ti ): 0;
    }
#endif 
    inline bool operator==( SharedCount const & a, SharedCount const & b )
    {
        return a.pi_ == b.pi_;
    }

    inline bool operator<( SharedCount const & a, SharedCount const & b )
    {
        return std::less< SharedPtrCountedBase* >()( a.pi_, b.pi_ );
    }


#if 0 // WeakCount is used for weak_ptr. As weak_ptr isnt supported yet, commenting the code. 
         // consider moving this class to a separate file.

    class WeakCount
    {
    private:
        Teamcenter::Internal::SharedPtrCountedBase * pi_;

        friend class SharedCount;

    public:
        /** @brief constructor */
        WeakCount(): pi_( 0 ) // nothrow
        {
        }
        /** @brief constructor */
        WeakCount( SharedCount const & r ): pi_( r.pi_ ) //lint !e1931 // can be used for conversion // nothrow
        {
            if( pi_ != NULL ) pi_->weak_add_ref();
        }
        /** @brief constructor */
        WeakCount( WeakCount const & r ): pi_( r.pi_ ) //lint !e1554 // nothrow
        {
            if( pi_ != NULL ) pi_->weak_add_ref();
        }

        ~WeakCount() // nothrow
        {
            if( pi_ != NULL ) pi_->weak_release();
            //  <BJS> 20-Jun-2008
            //  Because we want shared pointers to be as efficient as possible this ifdef
            //  is to show we know what is happening to qaz yet not affect performance
#ifdef _lint
            pi_ = NULL;
#endif
        }

        WeakCount & operator= ( SharedCount const & r ) // nothrow
        {
            Teamcenter::Internal::SharedPtrCountedBase * tmp = r.pi_;
            if( tmp != NULL ) tmp->weak_add_ref();
            if( pi_ != NULL ) pi_->weak_release();
            pi_ = tmp;

            return *this;
        }

        WeakCount & operator= ( WeakCount const & r ) // nothrow
        {
            if ( &r != this )
            {
                Teamcenter::Internal::SharedPtrCountedBase * tmp = r.pi_;
                if( tmp != NULL ) tmp->weak_add_ref();
                if( pi_ != NULL ) pi_->weak_release();
                pi_ = tmp;
            }

            return *this;
        }

        void swap( WeakCount & r ) // nothrow
        {
            Teamcenter::Internal::SharedPtrCountedBase * tmp = r.pi_;
            r.pi_ = pi_;
            pi_ = tmp;
        }

        long use_count() const // nothrow
        {
            return pi_ != NULL ? pi_->use_count(): 0;
        }

        friend inline bool operator==( WeakCount const & a, WeakCount const & b )
        {
            return a.pi_ == b.pi_;
        }

        friend inline bool operator<( WeakCount const & a, WeakCount const & b )
        {
            return std::less< Teamcenter::Internal::SharedPtrCountedBase * >()( a.pi_, b.pi_ );
        }
    }; // class WeakCount
#endif 

} // end namespace Internal
} // end namespace Teamcenter

#endif ///TEAMCENTER_BASE_UTILS_SHARED_COUNT_HXX
