Simbody

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  *                      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_
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines