Simbody
|
00001 #ifndef SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_ 00002 #define SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * SimTK Core: SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK Core biosimulation toolkit originating from * 00008 * Simbios, the NIH National Center for Physics-Based Simulation of * 00009 * Biological Structures at Stanford, funded under the NIH Roadmap for * 00010 * Medical Research, grant U54 GM072970. See https://simtk.org. * 00011 * * 00012 * Portions copyright (c) 2007 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: Chris Bruns and Peter Eastman * 00015 * * 00016 * Permission is hereby granted, free of charge, to any person obtaining a * 00017 * copy of this software and associated documentation files (the "Software"), * 00018 * to deal in the Software without restriction, including without limitation * 00019 * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 00020 * and/or sell copies of the Software, and to permit persons to whom the * 00021 * Software is furnished to do so, subject to the following conditions: * 00022 * * 00023 * The above copyright notice and this permission notice shall be included in * 00024 * all copies or substantial portions of the Software. * 00025 * * 00026 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * 00027 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * 00028 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * 00029 * THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 00030 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 00031 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * 00032 * USE OR OTHER DEALINGS IN THE SOFTWARE. * 00033 * -------------------------------------------------------------------------- */ 00034 00048 #include "SimTKcommon/internal/PrivateImplementation.h" 00049 00050 #include <cassert> 00051 #include <iostream> 00052 #include <typeinfo> 00053 00054 namespace SimTK { 00055 00057 // PIMPLImplementation definitions // 00059 00060 template <class HANDLE, class IMPL> 00061 PIMPLImplementation<HANDLE, IMPL>::PIMPLImplementation(HANDLE* h) : ownerHandle(h), handleCount(h ? 1 : 0) { 00062 } 00063 00064 template <class HANDLE, class IMPL> 00065 int PIMPLImplementation<HANDLE, IMPL>::getHandleCount() const { 00066 return handleCount; 00067 } 00068 00069 template <class HANDLE, class IMPL> 00070 void PIMPLImplementation<HANDLE, IMPL>::incrementHandleCount() const { 00071 handleCount++; 00072 } 00073 00074 template <class HANDLE, class IMPL> 00075 int PIMPLImplementation<HANDLE, IMPL>::decrementHandleCount() const { 00076 assert(handleCount>=1); return --handleCount; 00077 } 00078 00079 template <class HANDLE, class IMPL> 00080 PIMPLImplementation<HANDLE, IMPL>::~PIMPLImplementation() { 00081 assert(handleCount==0); ownerHandle=0; 00082 } 00083 00084 template <class HANDLE, class IMPL> 00085 PIMPLImplementation<HANDLE, IMPL>::PIMPLImplementation(const PIMPLImplementation&) : ownerHandle(0), handleCount(0) { 00086 } 00087 00088 template <class HANDLE, class IMPL> 00089 PIMPLImplementation<HANDLE, IMPL>& PIMPLImplementation<HANDLE, IMPL>::operator=(const PIMPLImplementation& src) { 00090 if (&src != this) 00091 ownerHandle=0, handleCount=0; 00092 return *this; 00093 } 00094 00095 template <class HANDLE, class IMPL> 00096 void PIMPLImplementation<HANDLE, IMPL>::setOwnerHandle(HANDLE& p) { 00097 assert(!hasOwnerHandle()); 00098 ownerHandle=&p; 00099 incrementHandleCount(); 00100 } 00101 00102 template <class HANDLE, class IMPL> 00103 int PIMPLImplementation<HANDLE, IMPL>::removeOwnerHandle() { 00104 assert(hasOwnerHandle()); 00105 ownerHandle=0; 00106 return decrementHandleCount(); 00107 } 00108 00109 template <class HANDLE, class IMPL> 00110 void PIMPLImplementation<HANDLE, IMPL>::replaceOwnerHandle(HANDLE& p) { 00111 assert(hasOwnerHandle()); 00112 ownerHandle=&p; 00113 } 00114 00115 template <class HANDLE, class IMPL> 00116 bool PIMPLImplementation<HANDLE, IMPL>::hasOwnerHandle() const { 00117 return ownerHandle != 0; 00118 } 00119 00120 template <class HANDLE, class IMPL> 00121 bool PIMPLImplementation<HANDLE, IMPL>::isOwnerHandle(const HANDLE& p) const { 00122 return hasOwnerHandle() && ownerHandle==&p; 00123 } 00124 00125 template <class HANDLE, class IMPL> 00126 const HANDLE& PIMPLImplementation<HANDLE, IMPL>::getOwnerHandle() const { 00127 assert(hasOwnerHandle()); 00128 return *ownerHandle; 00129 } 00130 00132 // PIMPLHandle definitions // 00134 00135 // serves as default constructor 00136 template <class HANDLE, class IMPL, bool PTR> 00137 /*explicit*/ PIMPLHandle<HANDLE,IMPL,PTR>:: 00138 PIMPLHandle(IMPL* p) : impl(p) { 00139 // this bumps the reference count in the implementation 00140 if (impl) impl->setOwnerHandle(updDowncastToHandle()); 00141 } 00142 00143 // destructor 00144 template <class HANDLE, class IMPL, bool PTR> 00145 PIMPLHandle<HANDLE,IMPL,PTR>::~PIMPLHandle() { 00146 // reduces the implementation reference count and deletes it if it hits 0 00147 clearHandle(); 00148 } 00149 00150 // copy constructor 00151 template <class HANDLE, class IMPL, bool PTR> 00152 PIMPLHandle<HANDLE,IMPL,PTR>::PIMPLHandle(const PIMPLHandle& src) : impl(0) { 00153 if (PTR) referenceAssign(src.downcastToHandle()); 00154 else copyAssign(src.downcastToHandle()); 00155 } 00156 00157 // copy assignment 00158 template <class HANDLE, class IMPL, bool PTR> 00159 PIMPLHandle<HANDLE,IMPL,PTR>& PIMPLHandle<HANDLE,IMPL,PTR>:: 00160 operator=(const PIMPLHandle& src) { 00161 if (PTR) referenceAssign(src.downcastToHandle()); 00162 else copyAssign(src.downcastToHandle()); 00163 return *this; 00164 } 00165 00166 template <class HANDLE, class IMPL, bool PTR> 00167 bool PIMPLHandle<HANDLE,IMPL,PTR>::isOwnerHandle() const { 00168 return impl && impl->hasOwnerHandle() && 00169 static_cast<const PIMPLHandle*>(&impl->getOwnerHandle()) == this; 00170 } 00171 00172 template <class HANDLE, class IMPL, bool PTR> 00173 bool PIMPLHandle<HANDLE,IMPL,PTR>::isSameHandle(const HANDLE& other) const { 00174 return static_cast<const PIMPLHandle*>(&other) == this; 00175 } 00176 00177 00178 template <class HANDLE, class IMPL, bool PTR> 00179 bool PIMPLHandle<HANDLE,IMPL,PTR>::hasSameImplementation(const HANDLE& other) const { 00180 return impl && (impl==other.impl); 00181 } 00182 00183 // The current (this) handle is an owner. Here it transfers ownership to the supplied 00184 // new empty handle, while retaining a reference to the implementation. 00185 template <class HANDLE, class IMPL, bool PTR> 00186 void PIMPLHandle<HANDLE,IMPL,PTR>:: 00187 disown(HANDLE& newOwner) { 00188 assert(!isSameHandle(newOwner)); 00189 assert(!this->isEmptyHandle() && newOwner.isEmptyHandle()); 00190 newOwner.impl = impl; 00191 impl->replaceOwnerHandle(newOwner); 00192 // since the old handle retains a reference, there is now one more handle 00193 impl->incrementHandleCount(); 00194 } 00195 00196 // Reference assignment: 00197 // - if target (this) is an owner handle, throw an exception; we don't allow that 00198 // - if source and target have same implementation, there is nothing to do 00199 // - otherwise, clear the handle, then set implementation and bump handle count 00200 template <class HANDLE, class IMPL, bool PTR> 00201 PIMPLHandle<HANDLE,IMPL,PTR>& PIMPLHandle<HANDLE,IMPL,PTR>:: 00202 referenceAssign(const HANDLE& src) { 00203 assert(!isOwnerHandle()); // owner can't be target of a reference assign 00204 if (!hasSameImplementation(src)) { 00205 clearHandle(); 00206 impl = src.impl; 00207 if (impl) 00208 impl->incrementHandleCount(); 00209 } 00210 return *this; 00211 } 00212 00213 // Copy assignment: 00214 // - if same handle, nothing to do 00215 // - clear this handle, decrementing ref count and deleting implementation if necessary 00216 // - clone the source implementation, then reference the copy in this target handle 00217 template <class HANDLE, class IMPL, bool PTR> 00218 PIMPLHandle<HANDLE,IMPL,PTR>& PIMPLHandle<HANDLE,IMPL,PTR>:: 00219 copyAssign(const HANDLE& src) { 00220 if (isSameHandle(src)) return *this; // that was easy! 00221 clearHandle(); 00222 if (src.impl) { 00223 impl = src.impl->clone(); // NOTE: instantiation requires definition of IMPL class 00224 impl->setOwnerHandle(updDowncastToHandle()); // bumps ref count (to 1) 00225 assert(impl->getHandleCount() == 1); 00226 } 00227 return *this; 00228 } 00229 00230 // Provide an implementation for this empty handle, bumping the handle count. 00231 // We do not assume this handle is the owner of the implementation; the caller 00232 // must handle that separately. 00233 template <class HANDLE, class IMPL, bool PTR> 00234 void PIMPLHandle<HANDLE,IMPL,PTR>:: 00235 setImpl(IMPL* p){ 00236 assert(isEmptyHandle()); 00237 impl=p; 00238 impl->incrementHandleCount(); 00239 } 00240 00241 // Remove this handle from its current implementation (if any). If this was the 00242 // owner handle, we clear the owner reference in the implementation. We decrement 00243 // the implementation's handle count and delete the implementation if this 00244 // was the last handle referencing it. 00245 template <class HANDLE, class IMPL, bool PTR> 00246 void PIMPLHandle<HANDLE,IMPL,PTR>:: 00247 clearHandle() { 00248 if (isEmptyHandle()) return; // handle is already clear 00249 const int nHandlesLeft = 00250 isOwnerHandle() ? impl->removeOwnerHandle() 00251 : impl->decrementHandleCount(); 00252 if (nHandlesLeft == 0) 00253 delete impl; 00254 impl=0; 00255 } 00256 00257 template <class HANDLE, class IMPL, bool PTR> 00258 int PIMPLHandle<HANDLE,IMPL,PTR>:: 00259 getImplHandleCount() const { 00260 assert(!isEmptyHandle()); 00261 return impl->getHandleCount(); 00262 } 00263 00265 // TEMPLATIZED GLOBAL METHODS // 00267 00268 template <class HANDLE, class IMPL, bool PTR> 00269 std::ostream& operator<<(std::ostream& o, const PIMPLHandle<HANDLE,IMPL,PTR>& h) { 00270 o << "PIMPLHandle<" << typeid(HANDLE).name() << "," << typeid(IMPL).name() << "> @" << &h; 00271 if (h.isEmptyHandle()) 00272 return o << " is EMPTY." << std::endl; 00273 00274 if (h.isOwnerHandle()) o << " is OWNER of"; 00275 else o << " is REFERENCE to"; 00276 00277 return o << " Implementation @" << &h.getImpl() << " (handle count=" << h.getImpl().getHandleCount() << ")" << std::endl; 00278 } 00279 00280 00281 } // namespace SimTK 00282 00283 #endif // SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_