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.6.1