Simbody  3.4 (development)
PrivateImplementation_Defs.h
Go to the documentation of this file.
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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines