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