CrystalSpace

Public API Reference

csutil/scf_implementation.h
Go to the documentation of this file.
00001 /*
00002   Crystal Space Shared Class Facility (SCF)
00003   This header contains the parts of SCF that is needed when creating
00004   new classes which implements SCF interfaces.
00005 
00006   Copyright (C) 2005 by Marten Svanfeldt
00007             (C) 2005 by Michael Adams
00008 
00009   This library is free software; you can redistribute it and/or
00010   modify it under the terms of the GNU Library General Public
00011   License as published by the Free Software Foundation; either
00012   version 2 of the License, or (at your option) any later version.
00013 
00014   This library is distributed in the hope that it will be useful,
00015   but WITHOUT ANY WARRANTY; without even the implied warranty of
00016   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00017   Library General Public License for more details.
00018 
00019   You should have received a copy of the GNU Library General Public
00020   License along with this library; if not, write to the Free
00021   Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022 */
00023 
00024 #ifndef __CSUTIL_SCF_IMPLEMENTATION_H__
00025 #define __CSUTIL_SCF_IMPLEMENTATION_H__
00026 
00027 #include "csextern.h"
00028 
00029 #include "csutil/array.h"
00030 #include "csutil/customallocated.h"
00031 #include "csutil/reftrackeraccess.h"
00032 #include "csutil/threading/atomicops.h"
00033 #include "csutil/threading/mutex.h"
00034 
00035 // Needs to have iBase etc
00036 #include "csutil/scf_interface.h"
00037 
00038 // Control if we want to use preprocessed file or run generation each time
00039 #define SCF_IMPLGEN_PREPROCESSED
00040 // Track some simple SCF-related stats
00041 //#define SCF_TRACK_STATS
00042 
00043 #ifndef CS_TYPENAME
00044   #ifdef CS_REF_TRACKER
00045    #include <typeinfo>
00046    #define CS_TYPENAME(x)                   typeid(x).name()
00047   #else
00048    #define CS_TYPENAME(x)                   0
00049   #endif
00050 #endif
00051 
00113 template<class If>
00114 class scfFakeInterface
00115 {
00116 public:
00117   struct InterfaceTraits 
00118   {
00119     typedef If InterfaceType;
00120     CS_FORCEINLINE_TEMPLATEMETHOD 
00121     static scfInterfaceVersion GetVersion()
00122     { return If::InterfaceTraits::GetVersion(); }
00123     CS_FORCEINLINE_TEMPLATEMETHOD static char const * GetName() 
00124     { return If::InterfaceTraits::GetName(); }
00125   };
00126 };
00127 
00129 class CS_CRYSTALSPACE_EXPORT scfImplementationHelper
00130 {
00131 protected:
00132   enum
00133   {
00134     scfstatTotal,
00135     scfstatParented,
00136     scfstatWeakreffed,
00137     scfstatMetadata,
00138     scfstatIncRef,
00139     scfstatDecRef,
00140 
00141     scfstatsNum
00142   };
00143   static uint64 stats[scfstatsNum];
00144   static CS::Threading::Mutex statsLock;
00145 
00146   CS_FORCEINLINE void BumpStat (int stat)
00147   {
00148 #ifdef SCF_TRACK_STATS
00149     CS::Threading::ScopedLock<CS::Threading::Mutex> l (statsLock);
00150     stats[stat]++;
00151 #endif
00152   }
00153 
00154   typedef csArray<void**,
00155     csArrayElementHandler<void**>,
00156     CS::Memory::AllocatorMalloc,
00157     csArrayCapacityLinear<csArrayThresholdFixed<4> > > WeakRefOwnerArray;
00158   struct ScfImplAuxData : public CS::Memory::CustomAllocated
00159   {
00160     CS::Threading::Mutex lock;
00161     iBase *scfParent;
00162     WeakRefOwnerArray* scfWeakRefOwners;
00163     scfInterfaceMetadataList* metadataList;
00164 
00165     ScfImplAuxData () : scfParent (0), scfWeakRefOwners (0), metadataList (0) {}
00166   };
00167   ScfImplAuxData* scfAuxData;
00168 
00169   CS_FORCEINLINE bool HasAuxData()
00170   {
00171     // Double-cast to cheat strict-aliasing rules
00172     return CS::Threading::AtomicOperations::Read ((void**)(void*)&scfAuxData) != 0; 
00173   }
00174   void EnsureAuxData();
00175   void FreeAuxData();
00176 
00177   //-- Metadata handling
00178   void AllocMetadata (size_t numEntries);
00179   void CleanupMetadata ();
00180 
00181   void scfRemoveRefOwners ();
00182 
00183   iBase* GetSCFParent() { return HasAuxData() ? scfAuxData->scfParent : 0; }
00184 
00185   // Some virtual helpers for the metadata registry
00186   virtual size_t GetInterfaceMetadataCount () const;
00187 
00188   scfImplementationHelper() : scfAuxData (0) {}
00189   virtual ~scfImplementationHelper() { if (HasAuxData()) FreeAuxData(); }
00190 };
00191 
00197 template<class Class>
00198 class scfImplementation : public virtual iBase,
00199   public scfImplementationHelper,
00200   public CS::Memory::CustomAllocated
00201 {
00202 public:
00207   scfImplementation (Class *object, iBase *parent = 0) :
00208       scfRefCount (1)
00209   {
00210     BumpStat (scfstatTotal);
00211     if (parent) BumpStat (scfstatParented);
00212     csRefTrackerAccess::TrackConstruction (object);
00213     if (parent) 
00214     {
00215       EnsureAuxData();
00216       scfAuxData->scfParent = parent;
00217       parent->IncRef ();
00218     }
00219   }
00220 
00229   scfImplementation (const scfImplementation& /*other*/) : iBase()
00230   {
00231     CS_ASSERT_MSG ("To allow copying SCF classes, create a copy "
00232       "constructor in the derived class, and initialize scfImplementation "
00233       "like in the normal constructor, i.e. use "
00234       "\"scfImplementation (this)\".", false);
00235   }
00236 
00237   // Cleanup
00238   virtual ~scfImplementation()
00239   {
00240     csRefTrackerAccess::TrackDestruction (GetSCFObject(), scfRefCount);
00241     if (HasAuxData())
00242     {
00243       scfRemoveRefOwners ();
00244       CleanupMetadata ();
00245       iBase *scfParent = scfAuxData->scfParent;
00246       if (scfParent) scfParent->DecRef();
00247     }
00248   }
00249 
00255   scfImplementation& operator= (const scfImplementation& /*other*/)
00256   {
00257     return *this;
00258   }
00259 
00260   virtual void DecRef ()
00261   {
00262     CS_ASSERT_MSG("Refcount decremented for destroyed object", 
00263       scfRefCount != 0);
00264     csRefTrackerAccess::TrackDecRef (GetSCFObject(), scfRefCount);
00265     if (CS::Threading::AtomicOperations::Decrement (&scfRefCount) == 0)
00266     {
00267       delete GetSCFObject();
00268     }
00269     BumpStat (scfstatDecRef);
00270   }
00271 
00272   virtual void IncRef ()
00273   {
00274     CS_ASSERT_MSG("Refcount incremented from inside dtor", 
00275       scfRefCount != 0);
00276     csRefTrackerAccess::TrackIncRef (GetSCFObject(), scfRefCount);
00277     CS::Threading::AtomicOperations::Increment (&scfRefCount);
00278     BumpStat (scfstatIncRef);
00279   }
00280 
00281   virtual int GetRefCount ()
00282   {
00283     return CS::Threading::AtomicOperations::Read (&scfRefCount);
00284   }
00285 
00286   virtual void AddRefOwner (void** ref_owner)
00287   {
00288     EnsureAuxData();
00289     CS::Threading::ScopedLock<CS::Threading::Mutex> l (scfAuxData->lock);
00290     if (!scfAuxData->scfWeakRefOwners)
00291     {
00292       scfAuxData->scfWeakRefOwners = new WeakRefOwnerArray (0);
00293       BumpStat (scfstatWeakreffed);
00294     }
00295     scfAuxData->scfWeakRefOwners->InsertSorted (ref_owner);
00296   }
00297 
00298   virtual void RemoveRefOwner (void** ref_owner)
00299   {
00300     if (!HasAuxData()) return;
00301 
00302     CS::Threading::ScopedLock<CS::Threading::Mutex> l (scfAuxData->lock);
00303     WeakRefOwnerArray* scfWeakRefOwners = scfAuxData->scfWeakRefOwners;
00304     if (!scfWeakRefOwners)
00305       return;
00306 
00307     size_t index = scfWeakRefOwners->FindSortedKey (
00308       csArrayCmp<void**, void**>(ref_owner));
00309 
00310     if (index != csArrayItemNotFound)
00311       scfWeakRefOwners->DeleteIndex (index);
00312   }
00313 
00314   virtual scfInterfaceMetadataList* GetInterfaceMetadata ()
00315   {
00316     EnsureAuxData();
00317     CS::Threading::ScopedLock<CS::Threading::Mutex> l (scfAuxData->lock);
00318     if (!scfAuxData->metadataList)
00319     {
00320       BumpStat (scfstatMetadata);
00321       // Need to set it up, do so
00322       AllocMetadata (GetInterfaceMetadataCount ());
00323       FillInterfaceMetadata (0);
00324     }
00325 
00326     return scfAuxData->metadataList;
00327   }
00328 
00329 protected:
00330   Class* GetSCFObject() { return static_cast<Class*> (this); }
00331   const Class* GetSCFObject() const { return static_cast<const Class*> (this); }
00332 
00333   int32 scfRefCount;
00334 
00335   void *QueryInterface (scfInterfaceID iInterfaceID,
00336                         scfInterfaceVersion iVersion)
00337   {
00338     // Default, just check iBase.. all objects have iBase    
00339     if (iInterfaceID == scfInterfaceTraits<iBase>::GetID () &&
00340       scfCompatibleVersion (iVersion, scfInterfaceTraits<iBase>::GetVersion ()))
00341     {
00342       GetSCFObject()->IncRef ();
00343       return static_cast<iBase*> (GetSCFObject());
00344     }
00345 
00346     // For embedded interfaces
00347     if (HasAuxData() && scfAuxData->scfParent)
00348       return scfAuxData->scfParent->QueryInterface (iInterfaceID, iVersion);
00349 
00350     return 0;
00351   }
00352 
00353 
00354   // Fill in interface metadata in the metadata table, starting at offset N
00355   virtual void FillInterfaceMetadata (size_t n)
00356   {
00357     scfInterfaceMetadataList* metadataList = scfAuxData->metadataList;
00358     if (!metadataList)
00359       return;
00360 
00361     FillInterfaceMetadataIf<iBase> (metadataList->metadata, n);
00362   }
00363 
00364   template<typename IF>
00365   CS_FORCEINLINE_TEMPLATEMETHOD static void FillInterfaceMetadataIf (
00366     scfInterfaceMetadata* metadataArray, size_t pos)
00367   {
00368     metadataArray[pos].interfaceName = scfInterfaceTraits<IF>::GetName ();
00369     metadataArray[pos].interfaceID = scfInterfaceTraits<IF>::GetID ();
00370     metadataArray[pos].interfaceVersion = scfInterfaceTraits<IF>::GetVersion ();
00371   }
00372 
00373 };
00374 
00375 
00376 /* Here the magic happens: generate scfImplementationN and 
00377 * scfImplementationExtN classed */
00378 #define SCF_IN_IMPLEMENTATION_H 1
00379 #if defined(DOXYGEN_RUN) || !defined(SCF_IMPLGEN_PREPROCESSED)
00380   // Generation is in separate file mostly for documentation generation purposes.
00381   #include "scf_implgen.h"
00382 #else
00383   #include "scf_implgen_p.h"
00384 #endif
00385 
00386 #undef SCF_IN_IMPLEMENTATION_H
00387 #undef SCF_IMPLGEN_PREPROCESSED
00388 
00391 #endif

Generated for Crystal Space 2.0 by doxygen 1.7.6.1