/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* * The contents of this file are subject to the Netscape Public License * Version 1.0 (the "NPL"); you may not use this file except in * compliance with the NPL. You may obtain a copy of the NPL at * http://www.mozilla.org/NPL/ * * Software distributed under the NPL is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL * for the specific language governing rights and limitations under the * NPL. * * The Initial Developer of this code under the NPL is Netscape * Communications Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All Rights * Reserved. */ #ifndef nsIPtr_h___ #define nsIPtr_h___ #include "nsISupports.h" /* * nsIPtr is an "auto-release pointer" class for nsISupports based interfaces * * It's intent is to be a "set and forget" pointer to help with managing * active references to nsISupports bases objects. * * The pointer object ensures that the underlying pointer is always * released whenever the value is changed or when the object leaves scope. * * Proper care needs to be taken when assigning pointers to a nsIPtr. * When asigning from a C pointer (nsISupports*), the pointer presumes * an active reference and subsumes it. When assigning from another nsIPtr, * a new reference is established. * * There are 3 ways to assign a value to a nsIPtr. * 1) Direct construction or assignment from a C pointer. * 2) Direct construction or assignment form another nsIPtr. * 3) Usage of an "out parameter" method. * a) AssignRef() releases the underlying pointer and returns a reference to it. * Useful for pointer reference out paramaters. * b) AssignPtr() releases the underlying pointer and returns a pointer to it. * c) Query() releases the underlying pointer and returns a (void**) pointer to it. * Useful for calls to QueryInterface() * 4) The SetAddRef() method. This is equivalent to an assignment followed by an AddRef(). * * examples: * * class It { * void NS_NewFoo(nsIFoo** aFoo); * nsIFoo* GetFoo(void); * void GetBar(nsIBar*& aBar); * }; * * nsIFooPtr foo = it->GetFoo(); * nsIBarPtr bar; * * it->NS_NewFoo(foo.AssignPtr()); * it->GetBar(bar.AssignRef()); * it->QueryInterface(kIFooIID, foo.Query()); * bar.SetAddRef(new Bar()); * * Advantages: * Set and forget. Once a pointer is assigned to a nsIPtr, it is impossible * to forget to release it. * Always pre-initialized. You can't forget to initialize the pointer. * * Disadvantages: * Usage of this class doesn't eliminate the need to think about ref counts * and assign values properly, AddRef'ing as needed. * The nsIPtr doesn't typecast exactly like a C pointer. In order to achieve * typecasting, it may be necessary to first cast to a C pointer of the * underlying type. * */ #define NS_DEF_PTR(cls) \ class cls##Ptr { \ public: \ cls##Ptr(void) : mPtr(0) {} \ cls##Ptr(const cls##Ptr& aCopy) : mPtr(aCopy.mPtr) \ { NS_IF_ADDREF(mPtr); } \ cls##Ptr(cls* aInterface) : mPtr(aInterface) {} \ ~cls##Ptr(void) { NS_IF_RELEASE(mPtr); } \ cls##Ptr& operator=(const cls##Ptr& aCopy) \ { if(mPtr == aCopy.mPtr) return *this; \ NS_IF_ADDREF(aCopy.mPtr); \ NS_IF_RELEASE(mPtr); \ mPtr = aCopy.mPtr; return *this; } \ cls##Ptr& operator=(cls* aInterface) \ { if(mPtr == aInterface) return *this; \ NS_IF_RELEASE(mPtr); mPtr = aInterface; \ return *this; } \ cls##Ptr& operator=(PRInt32 aInt) \ { NS_IF_RELEASE(mPtr); \ return *this; } \ void SetAddRef(cls* aInterface) \ { if(aInterface == mPtr) return; \ NS_IF_ADDREF(aInterface); \ NS_IF_RELEASE(mPtr); mPtr = aInterface; } \ cls* AddRef(void) { NS_ADDREF(mPtr); return mPtr; } \ cls* IfAddRef(void) \ { NS_IF_ADDREF(mPtr); return mPtr; } \ cls*& AssignRef(void) \ { NS_IF_RELEASE(mPtr); return mPtr; } \ cls** AssignPtr(void) \ { NS_IF_RELEASE(mPtr); return &mPtr; } \ void** Query(void) \ { NS_IF_RELEASE(mPtr); return (void**)&mPtr; } \ PRBool IsNull() const \ { return PRBool(0 == mPtr); } \ PRBool IsNotNull() const \ { return PRBool(0 != mPtr); } \ PRBool operator==(const cls##Ptr& aCopy) const \ { return PRBool(mPtr == aCopy.mPtr); } \ PRBool operator==(cls* aInterface) const \ { return PRBool(mPtr == aInterface); } \ PRBool operator!=(const cls##Ptr& aCopy) const \ { return PRBool(mPtr != aCopy.mPtr); } \ PRBool operator!=(cls* aInterface) const \ { return PRBool(mPtr != aInterface); } \ cls* operator->(void) { return mPtr; } \ cls& operator*(void) { return *mPtr; } \ operator cls*(void) { return mPtr; } \ const cls* operator->(void) const { return mPtr; } \ const cls& operator*(void) const { return *mPtr; } \ operator const cls* (void) const { return mPtr; } \ private: \ void* operator new(size_t size) { return 0; } \ void operator delete(void* aPtr) {} \ cls* mPtr; \ public: \ friend inline PRBool operator==(const cls* aInterface, const cls##Ptr& aPtr) \ { return PRBool(aInterface == aPtr.mPtr); } \ friend inline PRBool operator!=(const cls* aInterface, const cls##Ptr& aPtr) \ { return PRBool(aInterface != aPtr.mPtr); } \ } #endif // nsIPtr_h___