Commit 42e1c100 authored by scc%netscape.com's avatar scc%netscape.com
Browse files

updated to new interface for nsCOMPtr

parent 149e9ed6
Loading
Loading
Loading
Loading
+170 −331
Original line number Diff line number Diff line
@@ -36,10 +36,12 @@
/*
  TO DO...
  
    + Factor out some base behavior to reduce possible bloating
    + Find an alternative to the current illegal and non-functioning comparison operators
    + make alternative function for |getter_AddRefs| (or something)
    + make constructor for |nsQueryInterface| explicit (suddenly construct/assign from raw pointer becomes illegal)
    + Improve internal documentation
      + mention *&
      + alternatives for comparison
      + do_QueryInterface
*/


@@ -299,7 +301,6 @@
        nsDerivedSafe < nsCOMPtr
        nsDontAddRef < nsCOMPtr
        nsCOMPtr < nsGetterAddRefs
				nsCOMPtr < nsGetterDoesntAddRef

      The other compilers probably won't complain, so please don't reorder these
      classes, on pain of breaking 4.2 compatibility.
@@ -352,6 +353,57 @@ nsDerivedSafe<T>::Release()



template <class T>
struct nsDontQueryInterface
    /*
      ...
    */
  {
    explicit
    nsDontQueryInterface( T* aRawPtr )
        : mRawPtr(aRawPtr)
      {
        // nothing else to do here
      }

    T* mRawPtr;
  };

template <class T>
inline
nsDontQueryInterface<T>
dont_QueryInterface( T* aRawPtr )
  {
    return nsDontQueryInterface<T>(aRawPtr);
  }




struct nsQueryInterface
  {
    // explicit
    nsQueryInterface( nsISupports* aRawPtr, nsresult* error = 0 )
        : mRawPtr(aRawPtr),
          mErrorPtr(error)
      {
        // nothing else to do here
      }

    nsISupports* mRawPtr;
    nsresult*    mErrorPtr;
  };

inline
nsQueryInterface
do_QueryInterface( nsISupports* aRawPtr, nsresult* error = 0 )
  {
    return nsQueryInterface(aRawPtr, error);
  }




template <class T>
struct nsDontAddRef
    /*
@@ -390,36 +442,35 @@ dont_AddRef( T* aRawPtr )




template <class T>
struct nsDontQueryInterface
		/*
			...
		*/
class nsCOMPtr_base
  {
		explicit
		nsDontQueryInterface( T* aRawPtr )
				: mRawPtr(aRawPtr)
    public:

      nsCOMPtr_base( nsISupports* rawPtr = 0 )
          : mRawPtr(rawPtr)
        {
          // nothing else to do here
        }

		T* mRawPtr;
	};

template <class T>
inline
nsDontQueryInterface<T>
dont_QueryInterface( T* aRawPtr )
     ~nsCOMPtr_base()
        {
		return nsDontQueryInterface<T>(aRawPtr);
          if ( mRawPtr )
            NSCAP_RELEASE(mRawPtr);
        }

      NS_EXPORT void    assign_with_AddRef( nsISupports* );
      NS_EXPORT void    assign_with_QueryInterface( nsISupports*, const nsIID&, nsresult* );
      NS_EXPORT void**  begin_assignment();

    protected:
      nsISupports* mRawPtr;
  };




template <class T>
class nsCOMPtr
class nsCOMPtr : private nsCOMPtr_base
    /*
      ...
    */
@@ -427,143 +478,73 @@ class nsCOMPtr
    public:
      typedef T element_type;

				/*
					Note: the following constructor is only |explicit| because of a bug in egcs 1.0.
					This bug prevents egcs from compiling statements like
					
					  nsCOMPtr<Y> y;
					  // ...
					  nsCOMPtr<X> x = y;
					
					Using the parenthesis form of the constructor works fine.  In an effort to
					help other people not break the linux build, I am making this constructor
					|explicit|.  That prevents _any_ platform (that supports |explicit|) from compiling
					the thing that egcs can't compile.
					
					When egcs fixes this bug, and we have reasonable agreement that interested parties
					have or will upgrade, the |explicit| will go away.
				*/

			explicit
      nsCOMPtr( nsISupports* aRawPtr = 0 )
					/*
						...it's unfortunate, but negligable, that this does a |QueryInterface| even
						when constructed from a |T*| but we can't tell the difference between a |T*|
						and a pointer to some object derived from |class T|.
					*/
      nsCOMPtr()
          // : nsCOMPtr_base(0)
        {
      		nsresult status = NS_OK;
      		if ( !aRawPtr || !NS_SUCCEEDED( status = aRawPtr->QueryInterface(T::IID(), NSCAP_REINTERPRET_CAST(void**, &mRawPtr)) ) )
	      		mRawPtr = 0;	// ...in case they wrote |QueryInterface| wrong, and it returns an error _and_ a pointer

	      		// ...and |QueryInterface| does the |AddRef| for us (if it returned a pointer)
          // nothing else to do here
        }

	      	mImplicitQueryInterfaceResult = status;
      nsCOMPtr( const nsQueryInterface& aSmartPtr )
          // : nsCOMPtr_base(0)
        {
          assign_with_QueryInterface(aSmartPtr.mRawPtr, T::IID(), aSmartPtr.mErrorPtr);
        }

      nsCOMPtr( const nsDontAddRef<T>& aSmartPtr )
          : mRawPtr(aSmartPtr.mRawPtr),
            mImplicitQueryInterfaceResult(NS_OK)
          : nsCOMPtr_base(aSmartPtr.mRawPtr)
        {
          // nothing else to do here
        }

      nsCOMPtr( const nsDontQueryInterface<T>& aSmartPtr )
					: mRawPtr(aSmartPtr.mRawPtr),
						mImplicitQueryInterfaceResult(NS_OK)
          : nsCOMPtr_base(aSmartPtr.mRawPtr)
        {
          if ( mRawPtr )
						{
            NSCAP_ADDREF(mRawPtr);
        }
				}

      nsCOMPtr( const nsCOMPtr<T>& aSmartPtr )
          : mRawPtr(aSmartPtr.mRawPtr),
						mImplicitQueryInterfaceResult(NS_OK)
          : nsCOMPtr_base(aSmartPtr.mRawPtr)
        {
          if ( mRawPtr )
          	{
            NSCAP_ADDREF(mRawPtr);
        }
        }

     ~nsCOMPtr()
      nsCOMPtr<T>&
      operator=( const nsQueryInterface& rhs )
        {
          if ( mRawPtr && !mIsAwaitingAddRef )
          	{
            	NSCAP_RELEASE(mRawPtr);
            }
        }

			nsCOMPtr&
			operator=( nsISupports* rhs )
				{
      		T* rawPtr;
      		nsresult status = NS_OK;
      		if ( !rhs || !NS_SUCCEEDED( status = rhs->QueryInterface(T::IID(), NSCAP_REINTERPRET_CAST(void**, &rawPtr)) ) )
      			rawPtr = 0;

					if ( mRawPtr && !mIsAwaitingAddRef )
						{
							NSCAP_RELEASE(mRawPtr);
						}

      		mRawPtr = rawPtr;
					mImplicitQueryInterfaceResult = status;
          assign_with_QueryInterface(rhs.mRawPtr, T::IID(), rhs.mErrorPtr);
          return *this;
        }

      nsCOMPtr&
      nsCOMPtr<T>&
      operator=( const nsDontAddRef<T>& rhs )
        {
					if ( mRawPtr && !mIsAwaitingAddRef )
						{
          if ( mRawPtr )
            NSCAP_RELEASE(mRawPtr);
						}
          mRawPtr = rhs.mRawPtr;
					mImplicitQueryInterfaceResult = NS_OK;
          return *this;
        }

			nsCOMPtr&
      nsCOMPtr<T>&
      operator=( const nsDontQueryInterface<T>& rhs )
        {
					T* rawPtr = rhs.mRawPtr;

					if ( rawPtr )
						{
							NSCAP_ADDREF(rawPtr);
						}

					if ( mRawPtr && !mIsAwaitingAddRef )
						{
							NSCAP_RELEASE(mRawPtr);
						}

					mRawPtr = rawPtr;
					mImplicitQueryInterfaceResult = NS_OK;
          assign_with_AddRef(rhs.mRawPtr);
          return *this;
        }

			nsCOMPtr&
      nsCOMPtr<T>&
      operator=( const nsCOMPtr& rhs )
        {
					T* rawPtr = rhs.mRawPtr;

					if ( rawPtr )
						{
							NSCAP_ADDREF(rawPtr);
          assign_with_AddRef(rhs.mRawPtr);
          return *this;
        }

					if ( mRawPtr && !mIsAwaitingAddRef )
      nsDerivedSafe<T>*
      get() const
          // returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
        {
							NSCAP_RELEASE(mRawPtr);
						}

					mRawPtr = rawPtr;
					mImplicitQueryInterfaceResult = NS_OK;
					return *this;
          return NSCAP_REINTERPRET_CAST(nsDerivedSafe<T>*, mRawPtr);
        }

      nsDerivedSafe<T>*
@@ -587,110 +568,29 @@ class nsCOMPtr
          return get();
        }

      nsDerivedSafe<T>*
      get() const
          // returns a |nsDerivedSafe<T>*| to deny clients the use of |AddRef| and |Release|
        {
          return NSCAP_REINTERPRET_CAST(nsDerivedSafe<T>*, mRawPtr);
        }

			nsresult
			assignment_error() const
				{
					return mRawPtr ? NS_OK : mImplicitQueryInterfaceResult;
				}

#if 0
    private:
      friend class nsGetterAddRefs<T>;
      friend class nsGetterDoesntAddRef<T>;

      /*
        In a perfect world, the following two member functions, |StartAssignment| and
        |FinishAssignment|, would be private.  They are and should be only accessed by
        the closely related classes |nsGetterAddRefs<T>| and |nsGetterDoesntAddRef<T>|.
        In a perfect world, the following member function, |StartAssignment|, would be private.
        It is and should be only accessed by the closely related class |nsGetterAddRefs<T>|.

        Unfortunately, some compilers---most notably VC++5.0---fail to grok the
        friend declarations above or in any alternate acceptable form.  So, physically
        they will be public (until our compilers get smarter); but they are not to be
        friend declaration above or in any alternate acceptable form.  So, physically
        it will be public (until our compilers get smarter); but it is not to be
        considered part of the logical public interface.
      */
#endif

      T**
      StartAssignment( NSCAP_BOOL awaiting_AddRef )
        {
          if ( mRawPtr && !mIsAwaitingAddRef )
          	{
            	NSCAP_RELEASE(mRawPtr);
            }
          mIsAwaitingAddRef = awaiting_AddRef;
          mRawPtr = 0;
          return &mRawPtr;
        }

      void
      FinishAssignment()
        {
          if ( mRawPtr && mIsAwaitingAddRef )
      StartAssignment()
        {
              NSCAP_ADDREF(mRawPtr);
            }
         mImplicitQueryInterfaceResult = NS_OK;
          return NSCAP_REINTERPRET_CAST(T**, begin_assignment());
        }

    private:
      T* mRawPtr;

			union
				{
          NSCAP_BOOL mIsAwaitingAddRef;
          nsresult   mImplicitQueryInterfaceResult;
      	};
  };



  /*
    The following functions make comparing |nsCOMPtr|s and raw pointers
    more convenient.
  */

template <class T>
inline
NSCAP_BOOL
operator==( const nsCOMPtr<T>& lhs, const T*const rhs )
  {
    return lhs.get() == rhs;
  }

template <class T>
inline
NSCAP_BOOL
operator!=( const nsCOMPtr<T>& lhs, const T*const rhs )
  {
    return lhs.get() != rhs;
  }

template <class T>
inline
NSCAP_BOOL
operator==( const T*const lhs, const nsCOMPtr<T>& rhs )
  {
    return lhs == rhs.get();
  }

template <class T>
inline
NSCAP_BOOL
operator!=( const T*const lhs, const nsCOMPtr<T>& rhs )
  {
    return lhs != rhs.get();
  }




template <class T>
class nsGetterAddRefs
    /*
@@ -715,32 +615,32 @@ class nsGetterAddRefs
    public:
      explicit
      nsGetterAddRefs( nsCOMPtr<T>& aSmartPtr )
          : mTargetSmartPtr(&aSmartPtr)
          : mTargetSmartPtr(aSmartPtr)
        {
          // nothing else to do
        }

      operator void**()
        {
          NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
          return NSCAP_REINTERPRET_CAST(void**, mTargetSmartPtr->StartAssignment(0));
          // NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
          return NSCAP_REINTERPRET_CAST(void**, mTargetSmartPtr.StartAssignment());
        }

      T*&
      operator*()
        {
          NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
          return *(mTargetSmartPtr->StartAssignment(0));
          // NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
          return *(mTargetSmartPtr.StartAssignment());
        }

      operator T**()
        {
          NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
          return mTargetSmartPtr->StartAssignment(0);
          // NS_PRECONDITION(mTargetSmartPtr != 0, "getter_AddRefs into no destination");
          return mTargetSmartPtr.StartAssignment();
        }

    private:
      nsCOMPtr<T>* mTargetSmartPtr;
      nsCOMPtr<T>& mTargetSmartPtr;
  };

template <class T>
@@ -758,65 +658,4 @@ getter_AddRefs( nsCOMPtr<T>& aSmartPtr )




template <class T>
class nsGetterDoesntAddRef
    /*
      ...
    */
  {
    public:
      explicit
      nsGetterDoesntAddRef( nsCOMPtr<T>& aSmartPtr )
          : mTargetSmartPtr(&aSmartPtr)
        {
          // nothing else to do
        }

      nsGetterDoesntAddRef( nsGetterDoesntAddRef<T>& F )
          : mTargetSmartPtr(F.mTargetSmartPtr)
        {
          F.mTargetSmartPtr = 0;
        }

     ~nsGetterDoesntAddRef()
        {
          if ( mTargetSmartPtr )
            mTargetSmartPtr->FinishAssignment();
        }

      operator void**()
        {
          NS_PRECONDITION(mTargetSmartPtr != 0, "getter_doesnt_AddRef into no destination");
          return NSCAP_REINTERPRET_CAST(void**, mTargetSmartPtr->StartAssignment(1));
        }

      T*&
      operator*()
        {
          NS_PRECONDITION(mTargetSmartPtr != 0, "getter_doesnt_AddRef into no destination");
          return *(mTargetSmartPtr->StartAssignment(1));
        }

      operator T**()
        {
          NS_PRECONDITION(mTargetSmartPtr != 0, "getter_doesnt_AddRef into no destination");
          return mTargetSmartPtr->StartAssignment(1);
        }

    private:
      nsGetterDoesntAddRef<T> operator=( const nsGetterDoesntAddRef<T>& ); // not to be implemented

    private:
      nsCOMPtr<T>* mTargetSmartPtr;
  };

template <class T>
inline
nsGetterDoesntAddRef<T>
getter_doesnt_AddRef( nsCOMPtr<T>& aSmartPtr )
  {
    return nsGetterDoesntAddRef<T>(aSmartPtr);
  }

#endif // !defined(nsCOMPtr_h___)
+170 −331

File changed.

Preview size limit exceeded, changes collapsed.

(87 KiB)

File changed.

No diff preview for this file type.

+170 −331

File changed.

Preview size limit exceeded, changes collapsed.

+99 −18
Original line number Diff line number Diff line
@@ -25,8 +25,10 @@

#ifndef NSCAP_NO_NEW_CASTS
  #define STATIC_CAST(T,x)  static_cast<T>(x)
  #define REINTERPRET_CAST(T,x) reinterpret_cast<T>(x)
#else
  #define STATIC_CAST(T,x)  ((T)(x))
  #define REINTERPRET_CAST(T,x) ((T)(x))
#endif


@@ -289,6 +291,87 @@ AVoidPtrPtrContext( void** )



static
nsresult
TestBloat_Raw()
	{
		IBar* barP = 0;
		nsresult result = CreateIBar(REINTERPRET_CAST(void**, &barP));

		if ( barP )
			{
				try
					{
						IFoo* fooP = 0;
						if ( NS_SUCCEEDED( result = barP->QueryInterface(IFoo::IID(), REINTERPRET_CAST(void**, &fooP)) ) )
							{
								try
									{
										fooP->print_totals();
									}
								catch( ... )
									{
										NS_RELEASE(fooP);
										throw;
									}

								NS_RELEASE(fooP);
							}
					}
				catch( ... )
					{
						NS_RELEASE(barP);
						throw;
					}

				NS_RELEASE(barP);
			}

		return result;
	}



static
nsresult
TestBloat_Raw_Unsafe()
	{
		IBar* barP = 0;
		nsresult result = CreateIBar(REINTERPRET_CAST(void**, &barP));

		if ( barP )
			{
				IFoo* fooP = 0;
				if ( NS_SUCCEEDED( result = barP->QueryInterface(IFoo::IID(), REINTERPRET_CAST(void**, &fooP)) ) )
					{
						fooP->print_totals();
						NS_RELEASE(fooP);
					}

				NS_RELEASE(barP);
			}

		return result;
	}


static
nsresult
TestBloat_Smart()
	{
		nsCOMPtr<IBar> barP;
		nsresult result = CreateIBar( getter_AddRefs(barP) );

		nsCOMPtr<IFoo> fooP( do_QueryInterface(barP, &result) );

		if ( fooP )
			fooP->print_totals();

		return result;
	}




nsCOMPtr<IFoo> gFoop;

@@ -299,6 +382,10 @@ main()

		cout << "sizeof(nsCOMPtr<IFoo>) --> " << sizeof(nsCOMPtr<IFoo>) << endl;

		TestBloat_Raw();
		TestBloat_Raw_Unsafe();
		TestBloat_Smart();


    {
      cout << endl << "### Test  1: will a |nsCOMPtr| call |AddRef| on a pointer assigned into it?" << endl;
@@ -348,7 +435,7 @@ main()
      IFoo* raw_foo2p = foo2p.get();

      cout << endl << "### Test  8: can you compare a |nsCOMPtr| with a raw interface pointer [!=]?" << endl;
      if ( foo1p != raw_foo2p )
      if ( foo1p.get() != raw_foo2p )
        cout << "foo1p != raw_foo2p" << endl;
      else
        cout << "foo1p == raw_foo2p" << endl;
@@ -364,11 +451,19 @@ main()
        cout << "foo1p != foo2p" << endl;

      cout << endl << "### Test 11: can you compare a |nsCOMPtr| with a raw interface pointer [==]?" << endl;
      if ( raw_foo2p == foo2p )
      if ( raw_foo2p == foo2p.get() )
        cout << "raw_foo2p == foo2p" << endl;
      else
        cout << "raw_foo2p != foo2p" << endl;

#if 1
      cout << endl << "### Test 11.5: can you compare a |nsCOMPtr| with a raw interface pointer [==]?" << endl;
      if ( nsCOMPtr<IFoo>( dont_QueryInterface(raw_foo2p) ) == foo2p )
        cout << "raw_foo2p == foo2p" << endl;
      else
        cout << "raw_foo2p != foo2p" << endl;
#endif

      cout << endl << "### Test 12: bare pointer test?" << endl;
      if ( foo1p )
        cout << "foo1p is not NULL" << endl;
@@ -463,7 +558,7 @@ main()

			cout << "### Test 23: is |QueryInterface| called when assigning in a smart-pointer of a different type?" << endl;

			nsCOMPtr<IFoo> fooP( barP );
			nsCOMPtr<IFoo> fooP( do_QueryInterface(barP) );
			if ( fooP )
				cout << "an IBar* is an IFoo*" << endl;
		}
@@ -482,21 +577,7 @@ main()
    cout << "### End Test 24" << endl;


		{
			cout << endl << "### setup for Test 25" << endl;
			nsCOMPtr<IFoo> fooP( new IFoo );
			nsCOMPtr<IBar> barP;
			
			cout << "### Test 25: will an assignment fail when the interface is not supported, is the error available?" << endl;
			barP = fooP;
			cout << "barP.assignment_error() --> " << barP.assignment_error() << endl;
			cout << "### cleanup for Test 25" << endl;
		}
		cout << "### End Test 25" << endl;



    cout << endl << "### Test 26: will a static |nsCOMPtr| |Release| before program termination?" << endl;
    cout << endl << "### Test 25: will a static |nsCOMPtr| |Release| before program termination?" << endl;
    gFoop = new IFoo;
    
    cout << "<<main()" << endl;
Loading