1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/pxr.h"
25 #include "pxr/base/tf/regTest.h"
26
27 #include "pxr/base/tf/declarePtrs.h"
28 #include "pxr/base/tf/refPtr.h"
29 #include "pxr/base/tf/weakPtr.h"
30 #include "pxr/base/tf/safeTypeCompare.h"
31 #include <iostream>
32
33 PXR_NAMESPACE_USING_DIRECTIVE
34
35 TF_DECLARE_WEAK_AND_REF_PTRS(Node);
36
37 class Node : public TfRefBase, public TfWeakBase {
38 public:
39
New()40 static NodeRefPtr New() {
41 return TfCreateRefPtr(new Node);
42 }
43
~Node()44 ~Node() {
45 _nNodes--;
46 }
47
GetTotalNodeCount()48 static size_t GetTotalNodeCount() {
49 return _nNodes;
50 }
51
SetChild(NodeRefPtr child)52 void SetChild(NodeRefPtr child) {
53 if ((_child = child))
54 _child->_parent = NodePtr(this);
55 }
56
GetChild()57 NodeRefPtr GetChild() {
58 return _child;
59 }
60
GetTail()61 NodeRefPtr GetTail() {
62 return _child ? _child->GetTail() : NodeRefPtr(this);
63 }
64
GetLength()65 size_t GetLength() {
66 return _child ? _child->GetLength() + 1 : 1;
67 }
68
GetRevLength()69 size_t GetRevLength() {
70 return _parent ? _parent->GetRevLength() + 1 : 1;
71 }
72
73 protected:
Node()74 Node() {
75 _nNodes++;
76 }
77 private:
78
79 NodeRefPtr _child;
80 NodePtr _parent;
81 static size_t _nNodes;
82 };
83
84
85 size_t Node::_nNodes = 0;
86
87 TF_DECLARE_WEAK_AND_REF_PTRS(SuperNode);
88
89 class SuperNode : public Node {
90 public:
New()91 static SuperNodeRefPtr New() {
92 return TfCreateRefPtr(new SuperNode);
93 }
94 private:
SuperNode()95 SuperNode() { }
96 };
97
98 static
MakeChain(size_t n)99 NodeRefPtr MakeChain(size_t n) {
100 if (n == 0)
101 return TfNullPtr;
102 else {
103 NodeRefPtr root = Node::New();
104 root->SetChild(MakeChain(n-1));
105 return root;
106 }
107 }
108
109
TakesNodePtr(NodePtr p)110 static void TakesNodePtr(NodePtr p) {}
TakesNodeConstPtr(NodeConstPtr p)111 static void TakesNodeConstPtr(NodeConstPtr p) {}
TakesNodeRefPtr(NodeRefPtr p)112 static void TakesNodeRefPtr(NodeRefPtr p) {}
TakesNodeConstRefPtr(NodeConstRefPtr p)113 static void TakesNodeConstRefPtr(NodeConstRefPtr p) {}
114
TakesSuperNodePtr(SuperNodePtr p)115 static void TakesSuperNodePtr(SuperNodePtr p) {}
TakesSuperNodeConstPtr(SuperNodeConstPtr p)116 static void TakesSuperNodeConstPtr(SuperNodeConstPtr p) {}
TakesSuperNodeRefPtr(SuperNodeRefPtr p)117 static void TakesSuperNodeRefPtr(SuperNodeRefPtr p) {}
TakesSuperNodeConstRefPtr(SuperNodeConstRefPtr p)118 static void TakesSuperNodeConstRefPtr(SuperNodeConstRefPtr p) {}
119
TestConversions()120 static void TestConversions() {
121
122 // Make a SuperNodeRefPtr and try passing to a function taking NodeWeakPtr
123 SuperNodeRefPtr snode = SuperNode::New();
124
125 TakesNodePtr(snode);
126 TakesNodeConstPtr(snode);
127 TakesNodeRefPtr(snode);
128 TakesNodeConstRefPtr(snode);
129
130 TakesSuperNodePtr(snode);
131 TakesSuperNodeConstPtr(snode);
132 TakesSuperNodeRefPtr(snode);
133 TakesSuperNodeConstRefPtr(snode);
134
135 // Make a SuperNodePtr
136 SuperNodePtr snodew = snode;
137
138 TakesNodePtr(snodew);
139 TakesNodeConstPtr(snodew);
140 TakesNodeRefPtr(snodew);
141 TakesNodeConstRefPtr(snodew);
142
143 TakesSuperNodePtr(snodew);
144 TakesSuperNodeConstPtr(snodew);
145 TakesSuperNodeRefPtr(snodew);
146 TakesSuperNodeConstRefPtr(snodew);
147 }
148
TestNullptrComparisons()149 static void TestNullptrComparisons()
150 {
151 NodeRefPtr p;
152
153 TF_AXIOM(p == nullptr);
154 TF_AXIOM(!(p != nullptr));
155 TF_AXIOM(!(p < nullptr));
156 TF_AXIOM(p <= nullptr);
157 TF_AXIOM(!(p > nullptr));
158 TF_AXIOM(p >= nullptr);
159
160 // These should be exactly the same as the above comparisons to nullptr,
161 // but are included to verify that the code compiles.
162 TF_AXIOM(p == NULL);
163 TF_AXIOM(NULL == p);
164 }
165
166 static bool
Test_TfRefPtr()167 Test_TfRefPtr()
168 {
169 TestConversions();
170 TestNullptrComparisons();
171
172 NodeRefPtr chain1 = MakeChain(10);
173 NodeRefPtr chain2 = MakeChain(5);
174
175 NodePtr gChain1 = chain1;
176 NodePtr gChain2 = chain2;
177
178 TF_AXIOM(chain1->GetLength() == 10);
179 TF_AXIOM(chain2->GetLength() == 5);
180 TF_AXIOM(gChain1->GetLength() == 10);
181 TF_AXIOM(gChain2->GetLength() == 5);
182
183 std::cout
184 << "total nodes (should be 15): "
185 << Node::GetTotalNodeCount() << std::endl;
186
187 NodeRefPtr start = Node::New();
188 start->SetChild(chain1);
189 chain1 = TfNullPtr;
190
191 TF_AXIOM(gChain1->GetLength() == 10);
192 TF_AXIOM(start->GetLength() == 11);
193
194 std::cout
195 << "total nodes (should be one more than previous): "
196 << Node::GetTotalNodeCount() << std::endl;
197
198 start->SetChild(gChain2);
199 chain2 = TfNullPtr;
200 TF_AXIOM(start->GetLength() == 6);
201 TF_AXIOM(!gChain1);
202 TF_AXIOM(gChain2);
203
204 TF_AXIOM(start->GetLength() == start->GetTail()->GetRevLength());
205
206 std::cout
207 << "total nodes (should be 10 less than last): "
208 << Node::GetTotalNodeCount() << std::endl;
209
210 start = TfNullPtr;
211
212 TF_AXIOM(!gChain1);
213 TF_AXIOM(!gChain2);
214
215 std::cout
216 << "total nodes (should be zero): "
217 << Node::GetTotalNodeCount() << std::endl;
218
219 TF_AXIOM(Node::GetTotalNodeCount() == 0);
220
221 chain1 = MakeChain(5);
222 gChain2 = chain2 = MakeChain(5);
223 chain1->GetTail()->SetChild(chain2);
224
225 TF_AXIOM(gChain2->GetRevLength() == 6);
226 chain1 = TfNullPtr;
227 TF_AXIOM(gChain2->GetRevLength() == 1);
228 chain2 = TfNullPtr;
229 TF_AXIOM(!gChain2);
230 TF_AXIOM(Node::GetTotalNodeCount() == 0);
231
232 SuperNodeRefPtr superPtr = SuperNode::New();
233 NodeRefPtr basePtr = superPtr;
234 NodePtr baseBackPtr = basePtr;
235
236 TF_AXIOM(TfDynamic_cast<SuperNodeRefPtr>(basePtr) == superPtr);
237 TF_AXIOM(TfSafeDynamic_cast<SuperNodeRefPtr>(basePtr) == superPtr);
238
239 TF_AXIOM(TfDynamic_cast<SuperNodePtr>(baseBackPtr) == superPtr);
240 TF_AXIOM(TfSafeDynamic_cast<SuperNodePtr>(baseBackPtr) == superPtr);
241
242 // Test swap
243 {
244 const NodeRefPtr n1 = Node::New();
245 const NodeRefPtr n2 = Node::New();
246
247 NodeRefPtr a = n1;
248 NodeRefPtr b = n2;
249 TF_AXIOM(a);
250 TF_AXIOM(b);
251 TF_AXIOM(a != b);
252
253 TF_AXIOM(a == n1);
254 TF_AXIOM(b == n2);
255 a.swap(b);
256 TF_AXIOM(a == n2);
257 TF_AXIOM(b == n1);
258
259 // Test self-swap
260 a.swap(a);
261 TF_AXIOM(a == n2);
262 b.swap(b);
263 TF_AXIOM(b == n1);
264 }
265
266 // Test move constructor and assignment operators
267 {
268 NodeRefPtr n1 = Node::New();
269 Node* n1Ptr = get_pointer(n1);
270 TF_AXIOM(n1);
271
272 NodeRefPtr n2(std::move(n1));
273 TF_AXIOM(n2);
274 TF_AXIOM(get_pointer(n2) == n1Ptr);
275 TF_AXIOM(!n1);
276
277 n1 = Node::New();
278 n1Ptr = get_pointer(n1);
279 TF_AXIOM(n1);
280
281 n2 = std::move(n1);
282 TF_AXIOM(n2);
283 TF_AXIOM(get_pointer(n2) == n1Ptr);
284 TF_AXIOM(!n1);
285 }
286
287 // Test move constructor and assignment operators on
288 // convertible pointer types.
289 {
290 SuperNodeRefPtr subNode = SuperNode::New();
291 SuperNode* subNodePtr = get_pointer(subNode);
292 TF_AXIOM(subNode);
293
294 NodeRefPtr baseNode(std::move(subNode));
295 TF_AXIOM(baseNode);
296 TF_AXIOM(get_pointer(baseNode) == subNodePtr);
297 TF_AXIOM(!subNode);
298
299 subNode = SuperNode::New();
300 subNodePtr = get_pointer(subNode);
301 TF_AXIOM(subNode);
302
303 baseNode = std::move(subNode);
304 TF_AXIOM(baseNode);
305 TF_AXIOM(get_pointer(baseNode) == subNodePtr);
306 TF_AXIOM(!subNode);
307 }
308
309 return true;
310 }
311
312 TF_ADD_REGTEST(TfRefPtr);
313
314