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 #ifndef PXR_USD_SDF_CHANGE_LIST_H 25 #define PXR_USD_SDF_CHANGE_LIST_H 26 27 /// \file sdf/changeList.h 28 29 #include "pxr/pxr.h" 30 #include "pxr/usd/sdf/api.h" 31 #include "pxr/usd/sdf/path.h" 32 #include "pxr/usd/sdf/types.h" 33 #include "pxr/base/tf/smallVector.h" 34 35 #include <set> 36 #include <map> 37 #include <unordered_map> 38 #include <iosfwd> 39 40 PXR_NAMESPACE_OPEN_SCOPE 41 42 class SdfChangeList; 43 typedef std::vector< 44 std::pair<SdfLayerHandle, SdfChangeList> 45 > SdfLayerChangeListVec; 46 47 /// \class SdfChangeList 48 /// 49 /// A list of scene description modifications, organized by the namespace 50 /// paths where the changes occur. 51 /// 52 class SdfChangeList 53 { 54 public: 55 56 SdfChangeList() = default; 57 SDF_API SdfChangeList(SdfChangeList const &); 58 SdfChangeList(SdfChangeList &&) = default; 59 SDF_API SdfChangeList &operator=(SdfChangeList const &); 60 SdfChangeList &operator=(SdfChangeList &&) = default; 61 62 enum SubLayerChangeType { 63 SubLayerAdded, 64 SubLayerRemoved, 65 SubLayerOffset 66 }; 67 68 void DidReplaceLayerContent(); 69 void DidReloadLayerContent(); 70 void DidChangeLayerResolvedPath(); 71 void DidChangeLayerIdentifier(const std::string &oldIdentifier); 72 void DidChangeSublayerPaths(const std::string &subLayerPath, 73 SubLayerChangeType changeType); 74 75 void DidAddPrim(const SdfPath &primPath, bool inert); 76 void DidRemovePrim(const SdfPath &primPath, bool inert); 77 void DidReorderPrims(const SdfPath &parentPath); 78 void DidChangePrimName(const SdfPath &oldPath, const SdfPath &newPath); 79 void DidChangePrimVariantSets(const SdfPath &primPath); 80 void DidChangePrimInheritPaths(const SdfPath &primPath); 81 void DidChangePrimReferences(const SdfPath &primPath); 82 void DidChangePrimSpecializes(const SdfPath &primPath); 83 84 void DidAddProperty(const SdfPath &propPath, bool hasOnlyRequiredFields); 85 void DidRemoveProperty(const SdfPath &propPath, bool hasOnlyRequiredFields); 86 void DidReorderProperties(const SdfPath &propPath); 87 void DidChangePropertyName(const SdfPath &oldPath, const SdfPath &newPath); 88 89 void DidChangeAttributeTimeSamples(const SdfPath &attrPath); 90 void DidChangeAttributeConnection(const SdfPath &attrPath); 91 void DidChangeRelationshipTargets(const SdfPath &relPath); 92 void DidAddTarget(const SdfPath &targetPath); 93 void DidRemoveTarget(const SdfPath &targetPath); 94 95 void DidChangeInfo(const SdfPath &path, const TfToken &key, 96 const VtValue &oldValue, const VtValue &newValue); 97 98 /// \struct Entry 99 /// 100 /// Entry of changes at a single path in namespace. 101 /// 102 /// If the path is SdfPath::AbsoluteRootPath(), that indicates a change 103 /// to the root of namespace (that is, a layer or stage). 104 /// 105 /// Note: Our language for invalidation used to be more precise 106 /// about items added, removed, or reordered. It might seem that 107 /// this would afford more opportunities for efficient updates, 108 /// but in practice it does not. Because our derived data typically 109 /// must recompose or reinstantiate based on the underlying data, 110 /// the particular delta might be ignored, overridden, or invalid. 111 /// It is simpler to treat all changes identically, and focus on 112 /// making the common base case fast, rather than have complicated 113 /// differential update logic. It also vastly simplifies the 114 /// language of invalidation. 115 /// 116 struct Entry { 117 // Map of info keys that have changed to (old, new) value pairs. 118 typedef std::pair<VtValue, VtValue> InfoChange; 119 // We usually change just a few fields on a spec in one go, so we store 120 // up to three locally (e.g. typeName, variability, default). 121 typedef TfSmallVector<std::pair<TfToken, InfoChange>, 3> InfoChangeVec; 122 InfoChangeVec infoChanged; 123 124 /// Return the iterator in infoChanged whose first element is \p key, or 125 /// infoChanged.end() if there is no such element. 126 InfoChangeVec::const_iterator FindInfoChangeEntry127 FindInfoChange(TfToken const &key) const { 128 InfoChangeVec::const_iterator iter = infoChanged.begin(); 129 for (InfoChangeVec::const_iterator end = infoChanged.end(); 130 iter != end; ++iter) { 131 if (iter->first == key) { 132 break; 133 } 134 } 135 return iter; 136 } 137 138 /// Return true if this entry has an info change for \p key, false 139 /// otherwise. HasInfoChangeEntry140 bool HasInfoChange(TfToken const &key) const { 141 return FindInfoChange(key) != infoChanged.end(); 142 } 143 144 typedef std::pair<std::string, SubLayerChangeType> SubLayerChange; 145 std::vector<SubLayerChange> subLayerChanges; 146 147 // Empty if didRename is not set 148 SdfPath oldPath; 149 150 // Empty if didChangeIdentifier is not set 151 std::string oldIdentifier; 152 153 // Most changes are stored as simple bits. 154 struct _Flags { _FlagsEntry::_Flags155 _Flags() { 156 memset(this, 0, sizeof(*this)); 157 } 158 159 // SdfLayer 160 bool didChangeIdentifier:1; 161 bool didChangeResolvedPath:1; 162 bool didReplaceContent:1; 163 bool didReloadContent:1; 164 165 // SdfLayer, SdfPrimSpec, SdfRelationshipTarget. 166 bool didReorderChildren:1; 167 bool didReorderProperties:1; 168 169 // SdfPrimSpec, SdfPropertySpec 170 bool didRename:1; 171 172 // SdfPrimSpec 173 bool didChangePrimVariantSets:1; 174 bool didChangePrimInheritPaths:1; 175 bool didChangePrimSpecializes:1; 176 bool didChangePrimReferences:1; 177 178 // SdfPropertySpec 179 bool didChangeAttributeTimeSamples:1; 180 bool didChangeAttributeConnection:1; 181 bool didChangeRelationshipTargets:1; 182 bool didAddTarget:1; 183 bool didRemoveTarget:1; 184 185 // SdfPrimSpec add/remove 186 bool didAddInertPrim:1; 187 bool didAddNonInertPrim:1; 188 bool didRemoveInertPrim:1; 189 bool didRemoveNonInertPrim:1; 190 191 // Property add/remove 192 bool didAddPropertyWithOnlyRequiredFields:1; 193 bool didAddProperty:1; 194 bool didRemovePropertyWithOnlyRequiredFields:1; 195 bool didRemoveProperty:1; 196 }; 197 198 _Flags flags; 199 }; 200 201 /// Map of change entries at various paths in a layer. We store one entry 202 /// in local space, since it's very common to edit just a single spec in a 203 /// single round of changes. 204 using EntryList = TfSmallVector<std::pair<SdfPath, Entry>, 1>; 205 206 public: GetEntryList()207 const EntryList & GetEntryList() const { return _entries; } 208 209 // Change accessors/mutators 210 SDF_API 211 Entry const &GetEntry( const SdfPath & ) const; 212 213 using const_iterator = EntryList::const_iterator; 214 215 SDF_API 216 const_iterator FindEntry(SdfPath const &) const; 217 begin()218 const_iterator begin() const { 219 return _entries.begin(); 220 } 221 cbegin()222 const_iterator cbegin() const { 223 return _entries.cbegin(); 224 } 225 end()226 const_iterator end() const { 227 return _entries.end(); 228 } 229 cend()230 const_iterator cend() const { 231 return _entries.cend(); 232 } 233 234 private: swap(SdfChangeList & a,SdfChangeList & b)235 friend void swap(SdfChangeList &a, SdfChangeList &b) { 236 a._entries.swap(b._entries); 237 a._entriesAccel.swap(b._entriesAccel); 238 } 239 240 Entry &_GetEntry(SdfPath const &); 241 242 // If no entry with `newPath` exists, create one. If an entry with 243 // `oldPath` exists, move its contents over `newPath`'s and erase it. 244 // Return a reference to `newPath`'s entry. 245 Entry &_MoveEntry(SdfPath const &oldPath, SdfPath const &newPath); 246 247 EntryList::iterator _MakeNonConstIterator(EntryList::const_iterator i); 248 249 Entry &_AddNewEntry(SdfPath const &path); 250 251 void _EraseEntry(SdfPath const &); 252 253 void _RebuildAccel(); 254 255 EntryList _entries; 256 using _AccelTable = std::unordered_map<SdfPath, size_t, SdfPath::Hash>; 257 std::unique_ptr<_AccelTable> _entriesAccel; 258 static constexpr size_t _AccelThreshold = 64; 259 }; 260 261 // Stream-output operator 262 SDF_API std::ostream& operator<<(std::ostream&, const SdfChangeList &); 263 264 PXR_NAMESPACE_CLOSE_SCOPE 265 266 #endif // PXR_USD_SDF_CHANGE_LIST_H 267