forked from PixarAnimationStudios/OpenUSD
-
Notifications
You must be signed in to change notification settings - Fork 0
/
namespaceEdit.h
301 lines (262 loc) · 11.3 KB
/
namespaceEdit.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
//
// Copyright 2016 Pixar
//
// Licensed under the Apache License, Version 2.0 (the "Apache License")
// with the following modification; you may not use this file except in
// compliance with the Apache License and the following modification to it:
// Section 6. Trademarks. is deleted and replaced with:
//
// 6. Trademarks. This License does not grant permission to use the trade
// names, trademarks, service marks, or product names of the Licensor
// and its affiliates, except as required to comply with Section 4(c) of
// the License and to reproduce the content of the NOTICE file.
//
// You may obtain a copy of the Apache License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the Apache License with the above modification is
// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the Apache License for the specific
// language governing permissions and limitations under the Apache License.
//
#ifndef PXR_USD_SDF_NAMESPACE_EDIT_H
#define PXR_USD_SDF_NAMESPACE_EDIT_H
/// \file sdf/namespaceEdit.h
#include "pxr/pxr.h"
#include "pxr/usd/sdf/api.h"
#include "pxr/usd/sdf/path.h"
#include <boost/operators.hpp>
#include <functional>
#include <iosfwd>
#include <string>
#include <vector>
PXR_NAMESPACE_OPEN_SCOPE
/// \class SdfNamespaceEdit
///
/// A single namespace edit. It supports renaming, reparenting, reparenting
/// with a rename, reordering, and removal.
///
struct SdfNamespaceEdit :
boost::equality_comparable<SdfNamespaceEdit> {
public:
typedef SdfNamespaceEdit This;
typedef SdfPath Path;
typedef int Index;
/// Special index that means at the end.
static const Index AtEnd = -1;
/// Special index that means don't move. It's only meaningful when
/// renaming. In other cases implementations may assume \c AtEnd.
static const Index Same = -2;
/// The default edit maps the empty path to the empty path.
SdfNamespaceEdit() : index(AtEnd) { }
/// The fully general edit.
SdfNamespaceEdit(const Path& currentPath_, const Path& newPath_,
Index index_ = AtEnd) :
currentPath(currentPath_), newPath(newPath_), index(index_) { }
/// Returns a namespace edit that removes the object at \p currentPath.
static This Remove(const Path& currentPath)
{
return This(currentPath, Path::EmptyPath());
}
/// Returns a namespace edit that renames the prim or property at
/// \p currentPath to \p name
static This Rename(const Path& currentPath, const TfToken& name)
{
return This(currentPath, currentPath.ReplaceName(name), Same);
}
/// Returns a namespace edit to reorder the prim or property at
/// \p currentPath to index \p index.
static This Reorder(const Path& currentPath, Index index)
{
return This(currentPath, currentPath, index);
}
/// Returns a namespace edit to reparent the prim or property at
/// \p currentPath to be under \p newParentPath at index \p index.
static This Reparent(const Path& currentPath,
const Path& newParentPath,
Index index)
{
return This(currentPath,
currentPath.ReplacePrefix(currentPath.GetParentPath(),
newParentPath),
index);
}
/// Returns a namespace edit to reparent the prim or property at
/// \p currentPath to be under \p newParentPath at index \p index
/// with the name \p name.
static This ReparentAndRename(const Path& currentPath,
const Path& newParentPath,
const TfToken& name,
Index index)
{
return This(currentPath,
currentPath.ReplacePrefix(currentPath.GetParentPath(),
newParentPath).
ReplaceName(name),
index);
}
SDF_API bool operator==(const This& rhs) const;
public:
Path currentPath; ///< Path of the object when this edit starts.
Path newPath; ///< Path of the object when this edit ends.
Index index; ///< Index for prim insertion.
};
/// A sequence of \c SdfNamespaceEdit.
typedef std::vector<SdfNamespaceEdit> SdfNamespaceEditVector;
SDF_API std::ostream& operator<<(std::ostream&, const SdfNamespaceEdit&);
SDF_API std::ostream& operator<<(std::ostream&, const SdfNamespaceEditVector&);
/// \struct SdfNamespaceEditDetail
///
/// Detailed information about a namespace edit.
///
struct SdfNamespaceEditDetail :
boost::equality_comparable<SdfNamespaceEditDetail> {
public:
/// Validity of an edit.
enum Result {
Error, ///< Edit will fail.
Unbatched, ///< Edit will succeed but not batched.
Okay, ///< Edit will succeed as a batch.
};
SDF_API SdfNamespaceEditDetail();
SDF_API SdfNamespaceEditDetail(Result, const SdfNamespaceEdit& edit,
const std::string& reason);
SDF_API bool operator==(const SdfNamespaceEditDetail& rhs) const;
public:
Result result; ///< Validity.
SdfNamespaceEdit edit; ///< The edit.
std::string reason; ///< The reason the edit will not succeed cleanly.
};
/// A sequence of \c SdfNamespaceEditDetail.
typedef std::vector<SdfNamespaceEditDetail> SdfNamespaceEditDetailVector;
SDF_API std::ostream& operator<<(std::ostream&, const SdfNamespaceEditDetail&);
SDF_API std::ostream& operator<<(std::ostream&, const SdfNamespaceEditDetailVector&);
/// Combine two results, yielding Error over Unbatched over Okay.
inline
SdfNamespaceEditDetail::Result
CombineResult(
SdfNamespaceEditDetail::Result lhs,
SdfNamespaceEditDetail::Result rhs)
{
return lhs < rhs ? lhs : rhs;
}
/// Combine a result with Error, yielding Error over Unbatched over Okay.
inline
SdfNamespaceEditDetail::Result
CombineError(SdfNamespaceEditDetail::Result)
{
return SdfNamespaceEditDetail::Error;
}
/// Combine a result with Unbatched, yielding Error over Unbatched over Okay.
inline
SdfNamespaceEditDetail::Result
CombineUnbatched(SdfNamespaceEditDetail::Result other)
{
return CombineResult(other, SdfNamespaceEditDetail::Unbatched);
}
/// \class SdfBatchNamespaceEdit
///
/// A description of an arbitrarily complex namespace edit.
///
/// A \c SdfBatchNamespaceEdit object describes zero or more namespace edits.
/// Various types providing a namespace will allow the edits to be applied
/// in a single operation and also allow testing if this will work.
///
/// Clients are encouraged to group several edits into one object because
/// that may allow more efficient processing of the edits. If, for example,
/// you need to reparent several prims it may be faster to add all of the
/// reparents to a single \c SdfBatchNamespaceEdit and apply them at once
/// than to apply each separately.
///
/// Objects that allow applying edits are free to apply the edits in any way
/// and any order they see fit but they should guarantee that the resulting
/// namespace will be as if each edit was applied one at a time in the order
/// they were added.
///
/// Note that the above rule permits skipping edits that have no effect or
/// generate a non-final state. For example, if renaming A to B then to C
/// we could just rename A to C. This means notices may be elided. However,
/// implementations must not elide notices that contain information about any
/// edit that clients must be able to know but otherwise cannot determine.
///
class SdfBatchNamespaceEdit {
public:
/// Create an empty sequence of edits.
SDF_API SdfBatchNamespaceEdit();
SDF_API SdfBatchNamespaceEdit(const SdfBatchNamespaceEdit&);
SDF_API SdfBatchNamespaceEdit(const SdfNamespaceEditVector&);
SDF_API ~SdfBatchNamespaceEdit();
SDF_API SdfBatchNamespaceEdit& operator=(const SdfBatchNamespaceEdit&);
/// Add a namespace edit.
void Add(const SdfNamespaceEdit& edit)
{
_edits.push_back(edit);
}
/// Add a namespace edit.
void Add(const SdfNamespaceEdit::Path& currentPath,
const SdfNamespaceEdit::Path& newPath,
SdfNamespaceEdit::Index index = SdfNamespaceEdit::AtEnd)
{
Add(SdfNamespaceEdit(currentPath, newPath, index));
}
/// Returns the edits.
const SdfNamespaceEditVector& GetEdits() const
{
return _edits;
}
/// Functor that returns \c true iff an object exists at the given path.
typedef std::function<bool(const SdfPath&)> HasObjectAtPath;
/// Functor that returns \c true iff the namespace edit will succeed.
/// If not it returns \c false and sets the string argument.
typedef std::function<bool(const SdfNamespaceEdit&,std::string*)> CanEdit;
/// Validate the edits and generate a possibly more efficient edit
/// sequence. Edits are treated as if they were performed one at time
/// in sequence, therefore each edit occurs in the namespace resulting
/// from all previous edits.
///
/// Editing the descendants of the object in each edit is implied. If
/// an object is removed then the new path will be empty. If an object
/// is removed after being otherwise edited, the other edits will be
/// processed and included in \p processedEdits followed by the removal.
/// This allows clients to fixup references to point to the object's
/// final location prior to removal.
///
/// This function needs help to determine if edits are allowed. The
/// callbacks provide that help. \p hasObjectAtPath returns \c true
/// iff there's an object at the given path. This path will be in the
/// original namespace not any intermediate or final namespace.
/// \p canEdit returns \c true iff the object at the current path can
/// be namespace edited to the new path, ignoring whether an object
/// already exists at the new path. Both paths are in the original
/// namespace. If it returns \c false it should set the string to the
/// reason why the edit isn't allowed. It should not write either path
/// to the string.
///
/// If \p hasObjectAtPath is invalid then this assumes objects exist
/// where they should and don't exist where they shouldn't. Use this
/// with care. If \p canEdit in invalid then it's assumed all edits
/// are valid.
///
/// If \p fixBackpointers is \c true then target/connection paths are
/// expected to be in the intermediate namespace resulting from all
/// previous edits. If \c false and any current or new path contains a
/// target or connection path that has been edited then this will
/// generate an error.
///
/// This method returns \c true if the edits are allowed and sets
/// \p processedEdits to a new edit sequence at least as efficient as
/// the input sequence. If not allowed it returns \c false and appends
/// reasons why not to \p details.
SDF_API
bool Process(SdfNamespaceEditVector* processedEdits,
const HasObjectAtPath& hasObjectAtPath,
const CanEdit& canEdit,
SdfNamespaceEditDetailVector* details = NULL,
bool fixBackpointers = true) const;
private:
SdfNamespaceEditVector _edits;
};
PXR_NAMESPACE_CLOSE_SCOPE
#endif // PXR_USD_SDF_NAMESPACE_EDIT_H