csutil/scf_implementation.h Source File (Crystal Space 2.0 Public API Reference)

| ## Public API Reference

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

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