Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
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
00036 #include "csutil/scf_interface.h"
00037
00038
00039 #define SCF_IMPLGEN_PREPROCESSED
00040
00041
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
00172 return CS::Threading::AtomicOperations::Read ((void**)(void*)&scfAuxData) != 0;
00173 }
00174 void EnsureAuxData();
00175 void FreeAuxData();
00176
00177
00178 void AllocMetadata (size_t numEntries);
00179 void CleanupMetadata ();
00180
00181 void scfRemoveRefOwners ();
00182
00183 iBase* GetSCFParent() { return HasAuxData() ? scfAuxData->scfParent : 0; }
00184
00185
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& ) : 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
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& )
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
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
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
00347 if (HasAuxData() && scfAuxData->scfParent)
00348 return scfAuxData->scfParent->QueryInterface (iInterfaceID, iVersion);
00349
00350 return 0;
00351 }
00352
00353
00354
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
00377
00378 #define SCF_IN_IMPLEMENTATION_H 1
00379 #if defined(DOXYGEN_RUN) || !defined(SCF_IMPLGEN_PREPROCESSED)
00380
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