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