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 
25 #include "pxr/pxr.h"
26 #include "pxr/usd/sdf/changeList.h"
27 #include "pxr/base/tf/enum.h"
28 #include "pxr/base/tf/instantiateSingleton.h"
29 #include "pxr/base/tf/type.h"
30 
31 #include <ostream>
32 
33 PXR_NAMESPACE_OPEN_SCOPE
34 
35 namespace {
36 struct _PathFastLessThan {
37     inline bool
operator ()__anonfd1fc49e0111::_PathFastLessThan38     operator()(SdfChangeList::EntryList::value_type const &a,
39                SdfChangeList::EntryList::value_type const &b) const {
40         return SdfPath::FastLessThan()(a.first, b.first);
41     }
42 };
43 } // anon
44 
45 TF_INSTANTIATE_SINGLETON(SdfChangeList);
46 
TF_REGISTRY_FUNCTION(TfType)47 TF_REGISTRY_FUNCTION(TfType)
48 {
49     TfType::Define<SdfChangeList::SubLayerChangeType>();
50 }
51 
TF_REGISTRY_FUNCTION(TfEnum)52 TF_REGISTRY_FUNCTION(TfEnum)
53 {
54     TF_ADD_ENUM_NAME(SdfChangeList::SubLayerAdded);
55     TF_ADD_ENUM_NAME(SdfChangeList::SubLayerRemoved);
56     TF_ADD_ENUM_NAME(SdfChangeList::SubLayerOffset);
57 }
58 
59 // CODE_COVERAGE_OFF_debug output
operator <<(std::ostream & os,const SdfChangeList & cl)60 std::ostream& operator<<(std::ostream &os, const SdfChangeList &cl)
61 {
62     TF_FOR_ALL(entryIter, cl.GetEntryList()) {
63         const SdfPath & path = entryIter->first;
64         const SdfChangeList::Entry & entry = entryIter->second;
65 
66         os << "  <" << path << ">\n";
67 
68         TF_FOR_ALL(it, entry.infoChanged) {
69             os << "   infoKey: " << it->first << "\n";
70             os << "     oldValue: "
71                << TfStringify(it->second.first) << "\n";
72             os << "     newValue: "
73                << TfStringify(it->second.second) << "\n";
74         }
75         TF_FOR_ALL(i, entry.subLayerChanges) {
76             os << "    sublayer " << i->first << " "
77                 << TfEnum::GetName(i->second) << "\n";
78         }
79         if (!entry.oldPath.IsEmpty()) {
80             os << "   oldPath: <" << entry.oldPath << ">\n";
81         }
82 
83         if (entry.flags.didRename)
84             os << "   didRename\n";
85         if (entry.flags.didChangeIdentifier)
86             os << "   didChangeIdentifier\n";
87         if (entry.flags.didChangeResolvedPath)
88             os << "   didChangeResolvedPath\n";
89         if (entry.flags.didReplaceContent)
90             os << "   didReplaceContent\n";
91         if (entry.flags.didReloadContent)
92             os << "   didReloadContent\n";
93         if (entry.flags.didReorderChildren)
94             os << "   didReorderChildren\n";
95         if (entry.flags.didReorderProperties)
96             os << "   didReorderProperties\n";
97         if (entry.flags.didChangePrimVariantSets)
98             os << "   didChangePrimVariantSets\n";
99         if (entry.flags.didChangePrimInheritPaths)
100             os << "   didChangePrimInheritPaths\n";
101         if (entry.flags.didChangePrimSpecializes)
102             os << "   didChangePrimSpecializes\n";
103         if (entry.flags.didChangePrimReferences)
104             os << "   didChangePrimReferences\n";
105         if (entry.flags.didChangeAttributeTimeSamples)
106             os << "   didChangeAttributeTimeSamples\n";
107         if (entry.flags.didChangeAttributeConnection)
108             os << "   didChangeAttributeConnection\n";
109         if (entry.flags.didChangeRelationshipTargets)
110             os << "   didChangeRelationshipTargets\n";
111         if (entry.flags.didAddTarget)
112             os << "   didAddTarget\n";
113         if (entry.flags.didRemoveTarget)
114             os << "   didRemoveTarget\n";
115         if (entry.flags.didAddInertPrim)
116             os << "   didAddInertPrim\n";
117         if (entry.flags.didAddNonInertPrim)
118             os << "   didAddNonInertPrim\n";
119         if (entry.flags.didRemoveInertPrim)
120             os << "   didRemoveInertPrim\n";
121         if (entry.flags.didRemoveNonInertPrim)
122             os << "   didRemoveNonInertPrim\n";
123         if (entry.flags.didAddPropertyWithOnlyRequiredFields)
124             os << "   didAddPropertyWithOnlyRequiredFields\n";
125         if (entry.flags.didAddProperty)
126             os << "   didAddProperty\n";
127         if (entry.flags.didRemovePropertyWithOnlyRequiredFields)
128             os << "   didRemovePropertyWithOnlyRequiredFields\n";
129         if (entry.flags.didRemoveProperty)
130             os << "   didRemoveProperty\n";
131     }
132     return os;
133 }
134 // CODE_COVERAGE_ON
135 
SdfChangeList(SdfChangeList const & o)136 SdfChangeList::SdfChangeList(SdfChangeList const &o)
137     : _entries(o._entries)
138     , _entriesAccel(o._entriesAccel ?
139                     new _AccelTable(*o._entriesAccel) : nullptr)
140 {
141 }
142 
143 SdfChangeList &
operator =(SdfChangeList const & o)144 SdfChangeList::operator=(SdfChangeList const &o)
145 {
146     if (this != std::addressof(o)) {
147         _entries = o._entries;
148         _entriesAccel.reset(
149             o._entriesAccel ?
150             new _AccelTable(*o._entriesAccel) : nullptr);
151     }
152     return *this;
153 }
154 
155 SdfChangeList::Entry const &
GetEntry(const SdfPath & path) const156 SdfChangeList::GetEntry( const SdfPath & path ) const
157 {
158     TF_AXIOM(!path.IsEmpty());
159     auto iter = FindEntry(path);
160     if (iter != _entries.end()) {
161         return iter->second;
162     }
163     static Entry defaultEntry;
164     return defaultEntry;
165 }
166 
167 SdfChangeList::Entry&
_GetEntry(const SdfPath & path)168 SdfChangeList::_GetEntry( const SdfPath & path )
169 {
170     TF_DEV_AXIOM(!path.IsEmpty());
171     auto iter = FindEntry(path);
172     return iter != _entries.end() ?
173         _MakeNonConstIterator(iter)->second : _AddNewEntry(path);
174 }
175 
176 SdfChangeList::Entry&
_MoveEntry(SdfPath const & oldPath,SdfPath const & newPath)177 SdfChangeList::_MoveEntry(SdfPath const &oldPath, SdfPath const &newPath)
178 {
179     TF_DEV_AXIOM(!oldPath.IsEmpty() && !newPath.IsEmpty());
180     Entry tmp;
181     auto constIter = FindEntry(oldPath);
182     if (constIter != _entries.end()) {
183         // Move the old entry to the tmp space, then erase.
184         auto iter = _MakeNonConstIterator(constIter);
185         tmp = std::move(iter->second);
186         // Erase the element and rebuild the accelerator if needed.
187         _entries.erase(iter);
188         _RebuildAccel();
189     }
190     // Find or create the new entry, and move tmp over it.  This either
191     // populates the new entry with the old entry (if one existed) or it clears
192     // out the new entry.
193     Entry &newEntry = _GetEntry(newPath);
194     newEntry = std::move(tmp);
195     return newEntry;
196 }
197 
198 SdfChangeList::EntryList::iterator
_MakeNonConstIterator(SdfChangeList::EntryList::const_iterator i)199 SdfChangeList::_MakeNonConstIterator(
200     SdfChangeList::EntryList::const_iterator i) {
201     // Invoking erase(i, i) is a noop, but returns i as non-const iterator.
202     return _entries.erase(i, i);
203 }
204 
205 SdfChangeList::EntryList::const_iterator
FindEntry(const SdfPath & path) const206 SdfChangeList::FindEntry(const SdfPath & path) const
207 {
208     auto iter = _entries.end();
209     if (_entries.empty()) {
210         return iter;
211     }
212     // Check to see if the last entry is for this path (this is common).  If not
213     // search for it.
214     if (_entries.back().first == path) {
215         --iter;
216         return iter;
217     }
218 
219     if (_entriesAccel) {
220         // Use the unordered map.
221         auto tableIter = _entriesAccel->find(path);
222         if (tableIter != _entriesAccel->end()) {
223             return _entries.begin() + tableIter->second;
224         }
225     }
226     else {
227         // Linear search the unsorted range.
228         iter = std::find_if(_entries.begin(), _entries.end(),
229                             [&path](EntryList::value_type const &e) {
230                                 return e.first == path;
231                             });
232     }
233     return iter;
234 }
235 
236 SdfChangeList::Entry &
_AddNewEntry(SdfPath const & path)237 SdfChangeList::_AddNewEntry(SdfPath const &path)
238 {
239     _entries.emplace_back(std::piecewise_construct,
240                           std::tie(path), std::tuple<>());
241     if (_entriesAccel) {
242         _entriesAccel->emplace(path, _entries.size()-1);
243     }
244     else if (ARCH_UNLIKELY(_entries.size() >= _AccelThreshold)) {
245         _RebuildAccel();
246     }
247     return _entries.back().second;
248 }
249 
250 void
_RebuildAccel()251 SdfChangeList::_RebuildAccel()
252 {
253     if (_entries.size() >= _AccelThreshold) {
254         _entriesAccel.reset(new std::unordered_map<
255                             SdfPath, size_t, SdfPath::Hash>(_entries.size()));
256         size_t idx = 0;
257         for (auto const &p: _entries) {
258             _entriesAccel->emplace(p.first, idx++);
259         }
260     }
261     else {
262         _entriesAccel.reset();
263     }
264 }
265 
266 void
_EraseEntry(SdfPath const & path)267 SdfChangeList::_EraseEntry(SdfPath const &path)
268 {
269     if (_entries.empty()) {
270         return;
271     }
272 
273     auto iter = _MakeNonConstIterator(FindEntry(path));
274     if (iter != _entries.end()) {
275         // Erase the element and rebuild the accelerator if needed.
276         _entries.erase(iter);
277         _RebuildAccel();
278     }
279 }
280 
281 void
DidReplaceLayerContent()282 SdfChangeList::DidReplaceLayerContent()
283 {
284     _GetEntry(SdfPath::AbsoluteRootPath()).flags.didReplaceContent = true;
285 }
286 
287 void
DidReloadLayerContent()288 SdfChangeList::DidReloadLayerContent()
289 {
290     _GetEntry(SdfPath::AbsoluteRootPath()).flags.didReloadContent = true;
291 }
292 
293 void
DidChangeLayerIdentifier(const std::string & oldIdentifier)294 SdfChangeList::DidChangeLayerIdentifier(const std::string &oldIdentifier)
295 {
296     SdfChangeList::Entry &entry = _GetEntry(SdfPath::AbsoluteRootPath());
297 
298     if (!entry.flags.didChangeIdentifier) {
299         entry.flags.didChangeIdentifier = true;
300         entry.oldIdentifier = oldIdentifier;
301     }
302 }
303 
304 void
DidChangeLayerResolvedPath()305 SdfChangeList::DidChangeLayerResolvedPath()
306 {
307     _GetEntry(SdfPath::AbsoluteRootPath()).flags.didChangeResolvedPath = true;
308 }
309 
310 void
DidChangeSublayerPaths(const std::string & subLayerPath,SubLayerChangeType changeType)311 SdfChangeList::DidChangeSublayerPaths( const std::string &subLayerPath,
312                                        SubLayerChangeType changeType )
313 {
314     _GetEntry(SdfPath::AbsoluteRootPath()).subLayerChanges.push_back(
315         std::make_pair(subLayerPath, changeType) );
316 }
317 
318 void
DidChangeInfo(const SdfPath & path,const TfToken & key,const VtValue & oldVal,const VtValue & newVal)319 SdfChangeList::DidChangeInfo(const SdfPath & path, const TfToken & key,
320                              const VtValue & oldVal, const VtValue & newVal)
321 {
322     Entry &entry = _GetEntry(path);
323 
324     auto iter = entry.FindInfoChange(key);
325     if (iter == entry.infoChanged.end()) {
326         entry.infoChanged.emplace_back(
327             key, std::pair<VtValue const &, VtValue const &>(oldVal, newVal));
328     }
329     else {
330         // Update new val, but retain old val from previous change.
331         // Produce a non-const iterator using the erase(i, i) trick.
332         auto nonConstIter = entry.infoChanged.erase(iter, iter);
333         nonConstIter->second.second = newVal;
334     }
335 }
336 
337 void
DidChangePrimName(const SdfPath & oldPath,const SdfPath & newPath)338 SdfChangeList::DidChangePrimName(const SdfPath & oldPath,
339                                  const SdfPath & newPath)
340 {
341     Entry &newEntry = _GetEntry(newPath);
342 
343     if (newEntry.flags.didRemoveNonInertPrim) {
344         // We've already removed a spec at the target, so we can't simply
345         // overwrite the newPath entries with the ones from oldPath.
346         // Nor is it clear how to best merge the edits, while retaining
347         // the didRename hints. Instead, we simply fall back to treating
348         // this case as though newPath and oldPath were both removed,
349         // and a new spec added at newPath.
350         newEntry = Entry();
351         newEntry.flags.didRemoveNonInertPrim = true;
352         newEntry.flags.didAddNonInertPrim = true;
353 
354         // Fetch oldEntry -- note that this can invalidate 'newEntry'!
355         Entry &oldEntry = _GetEntry(oldPath);
356         // Clear out existing edits.
357         oldEntry = Entry();
358         oldEntry.flags.didRemoveNonInertPrim = true;
359     } else {
360         // Transfer accumulated changes about oldPath to apply to newPath.
361         Entry &moved = _MoveEntry(oldPath, newPath);
362 
363         // Indicate that a rename occurred.
364         moved.flags.didRename = true;
365 
366         // Record the source path, but only if it has not already been set
367         // by a prior rename during this round of change processing.
368         if (moved.oldPath.IsEmpty())
369             moved.oldPath = oldPath;
370     }
371 }
372 
373 void
DidChangePrimVariantSets(const SdfPath & primPath)374 SdfChangeList::DidChangePrimVariantSets(const SdfPath & primPath)
375 {
376     _GetEntry(primPath).flags.didChangePrimVariantSets = true;
377 }
378 
379 void
DidChangePrimInheritPaths(const SdfPath & primPath)380 SdfChangeList::DidChangePrimInheritPaths(const SdfPath & primPath)
381 {
382     _GetEntry(primPath).flags.didChangePrimInheritPaths = true;
383 }
384 
385 void
DidChangePrimSpecializes(const SdfPath & primPath)386 SdfChangeList::DidChangePrimSpecializes(const SdfPath & primPath)
387 {
388     _GetEntry(primPath).flags.didChangePrimSpecializes = true;
389 }
390 
391 void
DidChangePrimReferences(const SdfPath & primPath)392 SdfChangeList::DidChangePrimReferences(const SdfPath & primPath)
393 {
394     _GetEntry(primPath).flags.didChangePrimReferences = true;
395 }
396 
397 void
DidReorderPrims(const SdfPath & parentPath)398 SdfChangeList::DidReorderPrims(const SdfPath & parentPath)
399 {
400     _GetEntry(parentPath).flags.didReorderChildren = true;
401 }
402 
403 void
DidAddPrim(const SdfPath & path,bool inert)404 SdfChangeList::DidAddPrim(const SdfPath &path, bool inert)
405 {
406     if (inert)
407         _GetEntry(path).flags.didAddInertPrim = true;
408     else
409         _GetEntry(path).flags.didAddNonInertPrim = true;
410 }
411 
412 void
DidRemovePrim(const SdfPath & path,bool inert)413 SdfChangeList::DidRemovePrim(const SdfPath &path, bool inert)
414 {
415     if (inert)
416         _GetEntry(path).flags.didRemoveInertPrim = true;
417     else
418         _GetEntry(path).flags.didRemoveNonInertPrim = true;
419 }
420 
421 void
DidChangePropertyName(const SdfPath & oldPath,const SdfPath & newPath)422 SdfChangeList::DidChangePropertyName(const SdfPath & oldPath,
423                                      const SdfPath & newPath)
424 {
425     Entry &newEntry = _GetEntry(newPath);
426 
427     if (newEntry.flags.didRemoveProperty) {
428         // We've already removed a spec at the target, so we can't simply
429         // overrwrite the newPath entries with the ones from oldPath.
430         // Nor is it clear how to best merge the edits, while retaining
431         // the didRename hints. Instead, we simply fall back to treating
432         // this case as though newPath and oldPath were both removed,
433         // and a new spec added at newPath.
434         newEntry = Entry();
435         newEntry.flags.didRemoveProperty = true;
436         newEntry.flags.didAddProperty = true;
437 
438         // Note that fetching oldEntry may create its entry and invalidate
439         // 'newEntry'!
440         Entry &oldEntry = _GetEntry(oldPath);
441         oldEntry = Entry();
442         _GetEntry(oldPath).flags.didRemoveProperty = true;
443     } else {
444         // Transfer accumulated changes about oldPath to apply to newPath.
445         Entry &moved = _MoveEntry(oldPath, newPath);
446 
447         // Indicate that ac rename occurred.
448         moved.flags.didRename = true;
449 
450         // Record the source path, but only if it has not already been set
451         // by a prior rename during this round of change processing.
452         if (moved.oldPath.IsEmpty())
453             moved.oldPath = oldPath;
454     }
455 }
456 
457 void
DidReorderProperties(const SdfPath & parentPath)458 SdfChangeList::DidReorderProperties(const SdfPath & parentPath)
459 {
460     _GetEntry(parentPath).flags.didReorderProperties = true;
461 }
462 
463 void
DidAddProperty(const SdfPath & path,bool hasOnlyRequiredFields)464 SdfChangeList::DidAddProperty(const SdfPath &path, bool hasOnlyRequiredFields)
465 {
466     if (hasOnlyRequiredFields)
467         _GetEntry(path).flags.didAddPropertyWithOnlyRequiredFields = true;
468     else
469         _GetEntry(path).flags.didAddProperty = true;
470 }
471 
472 void
DidRemoveProperty(const SdfPath & path,bool hasOnlyRequiredFields)473 SdfChangeList::DidRemoveProperty(const SdfPath &path, bool hasOnlyRequiredFields)
474 {
475     if (hasOnlyRequiredFields)
476         _GetEntry(path).flags.didRemovePropertyWithOnlyRequiredFields = true;
477     else
478         _GetEntry(path).flags.didRemoveProperty = true;
479 }
480 
481 void
DidChangeAttributeTimeSamples(const SdfPath & attrPath)482 SdfChangeList::DidChangeAttributeTimeSamples(const SdfPath &attrPath)
483 {
484     _GetEntry(attrPath).flags.didChangeAttributeTimeSamples = true;
485 }
486 
487 void
DidChangeAttributeConnection(const SdfPath & attrPath)488 SdfChangeList::DidChangeAttributeConnection(const SdfPath &attrPath)
489 {
490     _GetEntry(attrPath).flags.didChangeAttributeConnection = true;
491 }
492 
493 void
DidChangeRelationshipTargets(const SdfPath & relPath)494 SdfChangeList::DidChangeRelationshipTargets(const SdfPath &relPath)
495 {
496     _GetEntry(relPath).flags.didChangeRelationshipTargets = true;
497 }
498 
499 void
DidAddTarget(const SdfPath & targetPath)500 SdfChangeList::DidAddTarget(const SdfPath &targetPath)
501 {
502     _GetEntry(targetPath).flags.didAddTarget = true;
503 }
504 
505 void
DidRemoveTarget(const SdfPath & targetPath)506 SdfChangeList::DidRemoveTarget(const SdfPath &targetPath)
507 {
508     _GetEntry(targetPath).flags.didRemoveTarget = true;
509 }
510 
511 PXR_NAMESPACE_CLOSE_SCOPE
512