Simbody
3.4 (development)
|
00001 #ifndef SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_ 00002 #define SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_ 00003 00004 /* -------------------------------------------------------------------------- * 00005 * Simbody(tm): SimTKcommon * 00006 * -------------------------------------------------------------------------- * 00007 * This is part of the SimTK 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/home/simbody. * 00011 * * 00012 * Portions copyright (c) 2007-12 Stanford University and the Authors. * 00013 * Authors: Michael Sherman * 00014 * Contributors: Christopher Bruns, Peter Eastman * 00015 * * 00016 * Licensed under the Apache License, Version 2.0 (the "License"); you may * 00017 * not use this file except in compliance with the License. You may obtain a * 00018 * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. * 00019 * * 00020 * Unless required by applicable law or agreed to in writing, software * 00021 * distributed under the License is distributed on an "AS IS" BASIS, * 00022 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 00023 * See the License for the specific language governing permissions and * 00024 * limitations under the License. * 00025 * -------------------------------------------------------------------------- */ 00026 00040 #include "SimTKcommon/internal/PrivateImplementation.h" 00041 00042 #include <cassert> 00043 #include <iostream> 00044 #include <typeinfo> 00045 00046 namespace SimTK { 00047 00049 // PIMPLImplementation definitions // 00051 00052 template <class HANDLE, class IMPL> 00053 PIMPLImplementation<HANDLE, IMPL>::PIMPLImplementation(HANDLE* h) : ownerHandle(h), handleCount(h ? 1 : 0) { 00054 } 00055 00056 template <class HANDLE, class IMPL> 00057 int PIMPLImplementation<HANDLE, IMPL>::getHandleCount() const { 00058 return handleCount; 00059 } 00060 00061 template <class HANDLE, class IMPL> 00062 void PIMPLImplementation<HANDLE, IMPL>::incrementHandleCount() const { 00063 handleCount++; 00064 } 00065 00066 template <class HANDLE, class IMPL> 00067 int PIMPLImplementation<HANDLE, IMPL>::decrementHandleCount() const { 00068 assert(handleCount>=1); return --handleCount; 00069 } 00070 00071 template <class HANDLE, class IMPL> 00072 PIMPLImplementation<HANDLE, IMPL>::~PIMPLImplementation() { 00073 assert(handleCount==0); ownerHandle=0; 00074 } 00075 00076 template <class HANDLE, class IMPL> 00077 PIMPLImplementation<HANDLE, IMPL>::PIMPLImplementation(const PIMPLImplementation&) : ownerHandle(0), handleCount(0) { 00078 } 00079 00080 template <class HANDLE, class IMPL> 00081 PIMPLImplementation<HANDLE, IMPL>& PIMPLImplementation<HANDLE, IMPL>::operator=(const PIMPLImplementation& src) { 00082 if (&src != this) 00083 ownerHandle=0, handleCount=0; 00084 return *this; 00085 } 00086 00087 template <class HANDLE, class IMPL> 00088 void PIMPLImplementation<HANDLE, IMPL>::setOwnerHandle(HANDLE& p) { 00089 assert(!hasOwnerHandle()); 00090 ownerHandle=&p; 00091 incrementHandleCount(); 00092 } 00093 00094 template <class HANDLE, class IMPL> 00095 int PIMPLImplementation<HANDLE, IMPL>::removeOwnerHandle() { 00096 assert(hasOwnerHandle()); 00097 ownerHandle=0; 00098 return decrementHandleCount(); 00099 } 00100 00101 template <class HANDLE, class IMPL> 00102 void PIMPLImplementation<HANDLE, IMPL>::replaceOwnerHandle(HANDLE& p) { 00103 assert(hasOwnerHandle()); 00104 ownerHandle=&p; 00105 } 00106 00107 template <class HANDLE, class IMPL> 00108 bool PIMPLImplementation<HANDLE, IMPL>::hasOwnerHandle() const { 00109 return ownerHandle != 0; 00110 } 00111 00112 template <class HANDLE, class IMPL> 00113 bool PIMPLImplementation<HANDLE, IMPL>::isOwnerHandle(const HANDLE& p) const { 00114 return hasOwnerHandle() && ownerHandle==&p; 00115 } 00116 00117 template <class HANDLE, class IMPL> 00118 const HANDLE& PIMPLImplementation<HANDLE, IMPL>::getOwnerHandle() const { 00119 assert(hasOwnerHandle()); 00120 return *ownerHandle; 00121 } 00122 00124 // PIMPLHandle definitions // 00126 00127 template <class HANDLE, class IMPL, bool PTR> 00128 /*explicit*/ PIMPLHandle<HANDLE,IMPL,PTR>:: 00129 PIMPLHandle(IMPL* p) : impl(p) { 00130 // this bumps the reference count in the implementation 00131 if (impl) impl->setOwnerHandle(updDowncastToHandle()); 00132 } 00133 00134 // destructor 00135 template <class HANDLE, class IMPL, bool PTR> 00136 PIMPLHandle<HANDLE,IMPL,PTR>::~PIMPLHandle() { 00137 // reduces the implementation reference count and deletes it if it hits 0 00138 clearHandle(); 00139 } 00140 00141 // copy constructor 00142 template <class HANDLE, class IMPL, bool PTR> 00143 PIMPLHandle<HANDLE,IMPL,PTR>::PIMPLHandle(const PIMPLHandle& src) : impl(0) { 00144 if (PTR) referenceAssign(src.downcastToHandle()); 00145 else copyAssign(src.downcastToHandle()); 00146 } 00147 00148 // copy assignment 00149 template <class HANDLE, class IMPL, bool PTR> 00150 PIMPLHandle<HANDLE,IMPL,PTR>& PIMPLHandle<HANDLE,IMPL,PTR>:: 00151 operator=(const PIMPLHandle& src) { 00152 if (PTR) referenceAssign(src.downcastToHandle()); 00153 else copyAssign(src.downcastToHandle()); 00154 return *this; 00155 } 00156 00157 template <class HANDLE, class IMPL, bool PTR> 00158 bool PIMPLHandle<HANDLE,IMPL,PTR>::isOwnerHandle() const { 00159 return impl && impl->hasOwnerHandle() && 00160 static_cast<const PIMPLHandle*>(&impl->getOwnerHandle()) == this; 00161 } 00162 00163 template <class HANDLE, class IMPL, bool PTR> 00164 bool PIMPLHandle<HANDLE,IMPL,PTR>::isSameHandle(const HANDLE& other) const { 00165 return static_cast<const PIMPLHandle*>(&other) == this; 00166 } 00167 00168 00169 template <class HANDLE, class IMPL, bool PTR> 00170 bool PIMPLHandle<HANDLE,IMPL,PTR>::hasSameImplementation(const HANDLE& other) const { 00171 return impl && (impl==other.impl); 00172 } 00173 00174 // The current (this) handle is an owner. Here it transfers ownership to the supplied 00175 // new empty handle, while retaining a reference to the implementation. 00176 template <class HANDLE, class IMPL, bool PTR> 00177 void PIMPLHandle<HANDLE,IMPL,PTR>:: 00178 disown(HANDLE& newOwner) { 00179 assert(!isSameHandle(newOwner)); 00180 assert(!this->isEmptyHandle() && newOwner.isEmptyHandle()); 00181 newOwner.impl = impl; 00182 impl->replaceOwnerHandle(newOwner); 00183 // since the old handle retains a reference, there is now one more handle 00184 impl->incrementHandleCount(); 00185 } 00186 00187 // Reference assignment: 00188 // - if target (this) is an owner handle, throw an exception; we don't allow that 00189 // - if source and target have same implementation, there is nothing to do 00190 // - otherwise, clear the handle, then set implementation and bump handle count 00191 template <class HANDLE, class IMPL, bool PTR> 00192 PIMPLHandle<HANDLE,IMPL,PTR>& PIMPLHandle<HANDLE,IMPL,PTR>:: 00193 referenceAssign(const HANDLE& src) { 00194 assert(!isOwnerHandle()); // owner can't be target of a reference assign 00195 if (!hasSameImplementation(src)) { 00196 clearHandle(); 00197 impl = src.impl; 00198 if (impl) 00199 impl->incrementHandleCount(); 00200 } 00201 return *this; 00202 } 00203 00204 // Copy assignment: 00205 // - if same handle, nothing to do 00206 // - clear this handle, decrementing ref count and deleting implementation if necessary 00207 // - clone the source implementation, then reference the copy in this target handle 00208 template <class HANDLE, class IMPL, bool PTR> 00209 PIMPLHandle<HANDLE,IMPL,PTR>& PIMPLHandle<HANDLE,IMPL,PTR>:: 00210 copyAssign(const HANDLE& src) { 00211 if (isSameHandle(src)) return *this; // that was easy! 00212 clearHandle(); 00213 if (src.impl) { 00214 impl = src.impl->clone(); // NOTE: instantiation requires definition of IMPL class 00215 impl->setOwnerHandle(updDowncastToHandle()); // bumps ref count (to 1) 00216 assert(impl->getHandleCount() == 1); 00217 } 00218 return *this; 00219 } 00220 00221 // Provide an implementation for this empty handle, bumping the handle count. 00222 // We do not assume this handle is the owner of the implementation; the caller 00223 // must handle that separately. 00224 template <class HANDLE, class IMPL, bool PTR> 00225 void PIMPLHandle<HANDLE,IMPL,PTR>:: 00226 setImpl(IMPL* p){ 00227 assert(isEmptyHandle()); 00228 impl=p; 00229 impl->incrementHandleCount(); 00230 } 00231 00232 // Remove this handle from its current implementation (if any). If this was the 00233 // owner handle, we clear the owner reference in the implementation. We decrement 00234 // the implementation's handle count and delete the implementation if this 00235 // was the last handle referencing it. 00236 template <class HANDLE, class IMPL, bool PTR> 00237 void PIMPLHandle<HANDLE,IMPL,PTR>:: 00238 clearHandle() { 00239 if (isEmptyHandle()) return; // handle is already clear 00240 const int nHandlesLeft = 00241 isOwnerHandle() ? impl->removeOwnerHandle() 00242 : impl->decrementHandleCount(); 00243 if (nHandlesLeft == 0) 00244 delete impl; 00245 impl=0; 00246 } 00247 00248 template <class HANDLE, class IMPL, bool PTR> 00249 int PIMPLHandle<HANDLE,IMPL,PTR>:: 00250 getImplHandleCount() const { 00251 assert(!isEmptyHandle()); 00252 return impl->getHandleCount(); 00253 } 00254 00256 // TEMPLATIZED GLOBAL METHODS // 00258 00259 template <class HANDLE, class IMPL, bool PTR> 00260 std::ostream& operator<<(std::ostream& o, const PIMPLHandle<HANDLE,IMPL,PTR>& h) { 00261 o << "PIMPLHandle<" << typeid(HANDLE).name() << "," << typeid(IMPL).name() << "> @" << &h; 00262 if (h.isEmptyHandle()) 00263 return o << " is EMPTY." << std::endl; 00264 00265 if (h.isOwnerHandle()) o << " is OWNER of"; 00266 else o << " is REFERENCE to"; 00267 00268 return o << " Implementation @" << &h.getImpl() << " (handle count=" << h.getImpl().getHandleCount() << ")" << std::endl; 00269 } 00270 00271 00272 } // namespace SimTK 00273 00274 #endif // SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_