Simbody  3.3
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PrivateImplementation_Defs.h
Go to the documentation of this file.
1 #ifndef SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_
2 #define SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_
3 
4 /* -------------------------------------------------------------------------- *
5  * Simbody(tm): SimTKcommon *
6  * -------------------------------------------------------------------------- *
7  * This is part of the SimTK biosimulation toolkit originating from *
8  * Simbios, the NIH National Center for Physics-Based Simulation of *
9  * Biological Structures at Stanford, funded under the NIH Roadmap for *
10  * Medical Research, grant U54 GM072970. See https://simtk.org/home/simbody. *
11  * *
12  * Portions copyright (c) 2007-12 Stanford University and the Authors. *
13  * Authors: Michael Sherman *
14  * Contributors: Christopher Bruns, Peter Eastman *
15  * *
16  * Licensed under the Apache License, Version 2.0 (the "License"); you may *
17  * not use this file except in compliance with the License. You may obtain a *
18  * copy of the License at http://www.apache.org/licenses/LICENSE-2.0. *
19  * *
20  * Unless required by applicable law or agreed to in writing, software *
21  * distributed under the License is distributed on an "AS IS" BASIS, *
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
23  * See the License for the specific language governing permissions and *
24  * limitations under the License. *
25  * -------------------------------------------------------------------------- */
26 
41 
42 #include <cassert>
43 #include <iostream>
44 #include <typeinfo>
45 
46 namespace SimTK {
47 
49  // PIMPLImplementation definitions //
51 
52 template <class HANDLE, class IMPL>
53 PIMPLImplementation<HANDLE, IMPL>::PIMPLImplementation(HANDLE* h) : ownerHandle(h), handleCount(h ? 1 : 0) {
54 }
55 
56 template <class HANDLE, class IMPL>
58  return handleCount;
59 }
60 
61 template <class HANDLE, class IMPL>
63  handleCount++;
64 }
65 
66 template <class HANDLE, class IMPL>
68  assert(handleCount>=1); return --handleCount;
69 }
70 
71 template <class HANDLE, class IMPL>
73  assert(handleCount==0); ownerHandle=0;
74 }
75 
76 template <class HANDLE, class IMPL>
78 }
79 
80 template <class HANDLE, class IMPL>
82  if (&src != this)
83  ownerHandle=0, handleCount=0;
84  return *this;
85 }
86 
87 template <class HANDLE, class IMPL>
89  assert(!hasOwnerHandle());
90  ownerHandle=&p;
91  incrementHandleCount();
92 }
93 
94 template <class HANDLE, class IMPL>
96  assert(hasOwnerHandle());
97  ownerHandle=0;
98  return decrementHandleCount();
99 }
100 
101 template <class HANDLE, class IMPL>
103  assert(hasOwnerHandle());
104  ownerHandle=&p;
105 }
106 
107 template <class HANDLE, class IMPL>
109  return ownerHandle != 0;
110 }
111 
112 template <class HANDLE, class IMPL>
114  return hasOwnerHandle() && ownerHandle==&p;
115 }
116 
117 template <class HANDLE, class IMPL>
119  assert(hasOwnerHandle());
120  return *ownerHandle;
121 }
122 
124  // PIMPLHandle definitions //
126 
127 template <class HANDLE, class IMPL, bool PTR>
129 PIMPLHandle(IMPL* p) : impl(p) {
130  // this bumps the reference count in the implementation
131  if (impl) impl->setOwnerHandle(updDowncastToHandle());
132 }
133 
134 // destructor
135 template <class HANDLE, class IMPL, bool PTR>
137  // reduces the implementation reference count and deletes it if it hits 0
138  clearHandle();
139 }
140 
141 // copy constructor
142 template <class HANDLE, class IMPL, bool PTR>
144  if (PTR) referenceAssign(src.downcastToHandle());
145  else copyAssign(src.downcastToHandle());
146 }
147 
148 // copy assignment
149 template <class HANDLE, class IMPL, bool PTR>
151 operator=(const PIMPLHandle& src) {
152  if (PTR) referenceAssign(src.downcastToHandle());
153  else copyAssign(src.downcastToHandle());
154  return *this;
155 }
156 
157 template <class HANDLE, class IMPL, bool PTR>
159  return impl && impl->hasOwnerHandle() &&
160  static_cast<const PIMPLHandle*>(&impl->getOwnerHandle()) == this;
161 }
162 
163 template <class HANDLE, class IMPL, bool PTR>
164 bool PIMPLHandle<HANDLE,IMPL,PTR>::isSameHandle(const HANDLE& other) const {
165  return static_cast<const PIMPLHandle*>(&other) == this;
166 }
167 
168 
169 template <class HANDLE, class IMPL, bool PTR>
171  return impl && (impl==other.impl);
172 }
173 
174 // The current (this) handle is an owner. Here it transfers ownership to the supplied
175 // new empty handle, while retaining a reference to the implementation.
176 template <class HANDLE, class IMPL, bool PTR>
178 disown(HANDLE& newOwner) {
179  assert(!isSameHandle(newOwner));
180  assert(!this->isEmptyHandle() && newOwner.isEmptyHandle());
181  newOwner.impl = impl;
182  impl->replaceOwnerHandle(newOwner);
183  // since the old handle retains a reference, there is now one more handle
184  impl->incrementHandleCount();
185 }
186 
187 // Reference assignment:
188 // - if target (this) is an owner handle, throw an exception; we don't allow that
189 // - if source and target have same implementation, there is nothing to do
190 // - otherwise, clear the handle, then set implementation and bump handle count
191 template <class HANDLE, class IMPL, bool PTR>
193 referenceAssign(const HANDLE& src) {
194  assert(!isOwnerHandle()); // owner can't be target of a reference assign
195  if (!hasSameImplementation(src)) {
196  clearHandle();
197  impl = src.impl;
198  if (impl)
199  impl->incrementHandleCount();
200  }
201  return *this;
202 }
203 
204 // Copy assignment:
205 // - if same handle, nothing to do
206 // - clear this handle, decrementing ref count and deleting implementation if necessary
207 // - clone the source implementation, then reference the copy in this target handle
208 template <class HANDLE, class IMPL, bool PTR>
210 copyAssign(const HANDLE& src) {
211  if (isSameHandle(src)) return *this; // that was easy!
212  clearHandle();
213  if (src.impl) {
214  impl = src.impl->clone(); // NOTE: instantiation requires definition of IMPL class
215  impl->setOwnerHandle(updDowncastToHandle()); // bumps ref count (to 1)
216  assert(impl->getHandleCount() == 1);
217  }
218  return *this;
219 }
220 
221 // Provide an implementation for this empty handle, bumping the handle count.
222 // We do not assume this handle is the owner of the implementation; the caller
223 // must handle that separately.
224 template <class HANDLE, class IMPL, bool PTR>
226 setImpl(IMPL* p){
227  assert(isEmptyHandle());
228  impl=p;
229  impl->incrementHandleCount();
230 }
231 
232 // Remove this handle from its current implementation (if any). If this was the
233 // owner handle, we clear the owner reference in the implementation. We decrement
234 // the implementation's handle count and delete the implementation if this
235 // was the last handle referencing it.
236 template <class HANDLE, class IMPL, bool PTR>
239  if (isEmptyHandle()) return; // handle is already clear
240  const int nHandlesLeft =
241  isOwnerHandle() ? impl->removeOwnerHandle()
242  : impl->decrementHandleCount();
243  if (nHandlesLeft == 0)
244  delete impl;
245  impl=0;
246 }
247 
248 template <class HANDLE, class IMPL, bool PTR>
251  assert(!isEmptyHandle());
252  return impl->getHandleCount();
253 }
254 
256  // TEMPLATIZED GLOBAL METHODS //
258 
259 template <class HANDLE, class IMPL, bool PTR>
260 std::ostream& operator<<(std::ostream& o, const PIMPLHandle<HANDLE,IMPL,PTR>& h) {
261  o << "PIMPLHandle<" << typeid(HANDLE).name() << "," << typeid(IMPL).name() << "> @" << &h;
262  if (h.isEmptyHandle())
263  return o << " is EMPTY." << std::endl;
264 
265  if (h.isOwnerHandle()) o << " is OWNER of";
266  else o << " is REFERENCE to";
267 
268  return o << " Implementation @" << &h.getImpl() << " (handle count=" << h.getImpl().getHandleCount() << ")" << std::endl;
269 }
270 
271 
272 } // namespace SimTK
273 
274 #endif // SimTK_PRIVATE_IMPLEMENTATION_DEFS_H_
void clearHandle()
Make this an empty handle, deleting the implementation object if this handle is the owner of it...
Definition: PrivateImplementation_Defs.h:238
void setImpl(IMPL *p)
Set the implementation for this empty handle.
Definition: PrivateImplementation_Defs.h:226
void setOwnerHandle(HANDLE &p)
Provide an owner handle for an implementation which currently does not have one.
Definition: PrivateImplementation_Defs.h:88
int decrementHandleCount() const
Register the fact that one of the previously-referencing handles no longer references this implementa...
Definition: PrivateImplementation_Defs.h:67
PIMPLHandle()
The default constructor makes this an empty handle.
Definition: PrivateImplementation.h:187
int removeOwnerHandle()
Remove the owner reference from an implementation that currently has an owner.
Definition: PrivateImplementation_Defs.h:95
This class provides some infrastructure useful in making SimTK Private Implementation (PIMPL) classes...
Definition: PrivateImplementation.h:106
void incrementHandleCount() const
Register that a new handle is referencing this implementation so we won't delete the implementation p...
Definition: PrivateImplementation_Defs.h:62
void disown(HANDLE &newOwner)
Give up ownership of the implementation to an empty handle.
Definition: PrivateImplementation_Defs.h:178
This class provides some infrastructure useful in creating PIMPL Implementation classes (the ones ref...
Definition: PrivateImplementation.h:265
bool isOwnerHandle() const
Returns true if this handle is the owner of the implementation object to which it refers...
Definition: PrivateImplementation_Defs.h:158
bool isOwnerHandle(const HANDLE &p) const
Check whether a given Handle of the appropriate type is the owner of this implementation.
Definition: PrivateImplementation_Defs.h:113
int getImplHandleCount() const
Return the number of handles the implementation believes are referencing it.
Definition: PrivateImplementation_Defs.h:250
~PIMPLHandle()
Note that the destructor is non-virtual.
Definition: PrivateImplementation_Defs.h:136
PIMPLImplementation & operator=(const PIMPLImplementation &src)
Copy assignment for the base class just makes sure that the owner handle is not copied, and that the handle count is zero for the copy.
Definition: PrivateImplementation_Defs.h:81
~PIMPLImplementation()
Note that the base class destructor is non-virtual, although it is expected that derived classes will...
Definition: PrivateImplementation_Defs.h:72
bool hasOwnerHandle() const
Check whether this implementation currently has a reference to its owner handle.
Definition: PrivateImplementation_Defs.h:108
PIMPLHandle & operator=(const PIMPLHandle &source)
Copy assignment makes the current handle either a deep (value) or shallow (reference) copy of the sup...
Definition: PrivateImplementation_Defs.h:151
const HANDLE & getOwnerHandle() const
Return a reference to the owner handle of this implementation.
Definition: PrivateImplementation_Defs.h:118
bool isSameHandle(const HANDLE &other) const
Determine whether the supplied handle is the same object as "this" PIMPLHandle.
Definition: PrivateImplementation_Defs.h:164
void replaceOwnerHandle(HANDLE &p)
Replace the current owner handle with another one.
Definition: PrivateImplementation_Defs.h:102
PIMPLHandle & copyAssign(const HANDLE &source)
This is real copy assignment, with ordinary C++ object ("value") semantics.
Definition: PrivateImplementation_Defs.h:210
PIMPLImplementation(HANDLE *h=0)
This serves as a default constructor and as a way to construct an implementation class which already ...
Definition: PrivateImplementation_Defs.h:53
bool hasSameImplementation(const HANDLE &other) const
Determine whether the supplied handle is a reference to the same implementation object as is referenc...
Definition: PrivateImplementation_Defs.h:170
This header provides declarations of the user-visible portion of the PIMPLHandle template classes tha...
PIMPLHandle & referenceAssign(const HANDLE &source)
"Copy" assignment but with shallow (pointer) semantics.
Definition: PrivateImplementation_Defs.h:193
int getHandleCount() const
Get the number of handles known to be referencing this implementation.
Definition: PrivateImplementation_Defs.h:57