Loading...
Searching...
No Matches
arrayEdit.h
Go to the documentation of this file.
1//
2// Copyright 2025 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7
8#ifndef PXR_BASE_VT_ARRAY_EDIT_H
9#define PXR_BASE_VT_ARRAY_EDIT_H
10
12
13#include "pxr/pxr.h"
14#include "pxr/base/vt/api.h"
15#include "pxr/base/vt/array.h"
17#include "pxr/base/vt/streamOut.h"
18#include "pxr/base/vt/traits.h"
19
21#include "pxr/base/tf/functionRef.h"
22#include "pxr/base/tf/hash.h"
24
25#include <iosfwd>
26#include <type_traits>
27
28PXR_NAMESPACE_OPEN_SCOPE
29
30template <class ELEM>
31class VtArrayEditBuilder; // fwd
32
49template <class ELEM>
51{
52public:
55
56 using ElementType = typename Array::ElementType;
57
60 VtArrayEdit() = default;
61
63 friend bool operator==(VtArrayEdit const &x, VtArrayEdit const &y) {
64 return std::tie(x._literals, x._ops) == std::tie(y._literals, y._ops);
65 }
67 friend bool operator!=(VtArrayEdit const &x, VtArrayEdit const &y) {
68 return !(x == y);
69 }
70
74 bool IsIdentity() const {
75 return _ops.IsEmpty();
76 }
77
84 if (IsIdentity()) {
85 return weaker;
86 }
87 return _ComposeEdits(weaker);
88 }
89
92 if (IsIdentity()) {
93 return std::move(weaker);
94 }
95 return _ComposeEdits(std::move(weaker));
96 }
97
99 VtArrayEdit ComposeOver(VtArrayEdit const &weaker) const & {
100 if (IsIdentity()) {
101 return weaker;
102 }
103 return _ComposeEdits(weaker);
104 };
105
108 if (IsIdentity()) {
109 return std::move(weaker);
110 }
111 return _ComposeEdits(std::move(weaker));
112 }
113
115 Array ComposeOver(Array const &weaker) const {
116 if (IsIdentity()) {
117 return weaker;
118 }
119 return _ApplyEdits(weaker);
120 }
121
123 Array ComposeOver(Array &&weaker) const {
124 if (IsIdentity()) {
125 return std::move(weaker);
126 }
127 return _ApplyEdits(weaker);
128 }
129
156 friend std::ostream &
157 operator<<(std::ostream &out, const VtArrayEdit self) {
158 auto streamElem = [&](int64_t index) -> std::ostream & {
159 return VtStreamOut(self._literals[index], out);
160 };
161 return Vt_ArrayEditStreamImpl(
162 self._ops, self._literals.size(), streamElem, out);
163 }
164
170 template <class UnaryOp>
171 std::ostream &
172 StreamCustom(std::ostream &out, UnaryOp &&unaryOp) const {
173 auto streamElem = [&](int64_t index) -> std::ostream & {
174 return VtStreamOut(
175 std::forward<UnaryOp>(unaryOp)(_literals[index]),
176 out);
177 };
178 return Vt_ArrayEditStreamImpl(_ops, _literals.size(), streamElem, out);
179 }
180
181private:
182 friend class VtArrayEditBuilder<ELEM>;
183 friend struct Vt_ArrayEditHashAccess;
184
185 friend
186 std::ostream &Vt_ArrayEditStreamImpl(
187 Vt_ArrayEditOps const &ops, size_t literalsSize,
188 TfFunctionRef<std::ostream &(int64_t index)> elemToStr,
189 std::ostream &out);
190
191 using _Ops = Vt_ArrayEditOps;
192
193 Array _ApplyEdits(Array &&weaker) const;
194 Array _ApplyEdits(Array const &weaker) const {
195 return _ApplyEdits(Array {weaker});
196 }
197
198 VtArrayEdit _ComposeEdits(VtArrayEdit &&weaker) &&;
199 VtArrayEdit _ComposeEdits(VtArrayEdit const &weaker) &&;
200
201 VtArrayEdit _ComposeEdits(VtArrayEdit &&weaker) const & {
202 return VtArrayEdit(*this)._ComposeEdits(std::move(weaker));
203 }
204 VtArrayEdit _ComposeEdits(VtArrayEdit const &weaker) const & {
205 return VtArrayEdit(*this)._ComposeEdits(weaker);
206 }
207
208 Array _literals;
209 _Ops _ops;
210};
211
212VT_API
213std::ostream &Vt_ArrayEditStreamImpl(
214 Vt_ArrayEditOps const &ops, size_t literalsSize,
215 TfFunctionRef<std::ostream &(int64_t index)> streamElem,
216 std::ostream &out);
217
218// Declare basic arrayEdit instantiations as extern templates. They are
219// explicitly instantiated in arrayEdit.cpp.
220#define VT_ARRAY_EDIT_EXTERN_TMPL(unused, elem) \
221 VT_API_TEMPLATE_CLASS(VtArrayEdit< VT_TYPE(elem) >);
222TF_PP_SEQ_FOR_EACH(VT_ARRAY_EDIT_EXTERN_TMPL, ~, VT_SCALAR_VALUE_TYPES)
223#undef VT_ARRAY_EDIT_EXTERN_TMPL
224
225struct Vt_ArrayEditHashAccess
226{
227 template <class HashState, class Edit>
228 static void Append(HashState &h, Edit const &edit) {
229 h.Append(edit._literals, edit._ops);
230 }
231};
232
233template <class HashState, class ELEM>
234std::enable_if_t<VtIsHashable<ELEM>()>
235TfHashAppend(HashState &h, VtArrayEdit<ELEM> const &edit) {
236 Vt_ArrayEditHashAccess::Append(h, edit);
237}
238
239template <class ELEM>
241VtArrayEdit<ELEM>::_ApplyEdits(Array &&weaker) const
242{
243 TRACE_FUNCTION();
244
245 // weaker is an array that we edit.
246 Array result = std::move(weaker);
247 Array const &cresult = result;
248
249 Array const &literals = _literals;
250 const auto numLiterals = literals.size();
251
252 // XXX: Note that this does not handle certain sequences of inserts and
253 // erases (specifically those that insert or erase contiguous ranges of
254 // elements) optimally. This could be improved by detecting these cases and
255 // doing a single batch insert or erase instead, to minimize shuffling the
256 // other elements.
257
258 _ops.ForEachValid(numLiterals, cresult.size(),
259 [&](_Ops::Op op, int64_t a1, int64_t a2) {
260 switch (op) {
261 case _Ops::OpWriteLiteral:
262 result[a2] = literals[a1];
263 break;
264 case _Ops::OpWriteRef: // a1: result index -> a2: result index.
265 result[a2] = cresult[a1];
266 break;
267 case _Ops::OpInsertLiteral: // a1: literal index -> a2: result index.
268 result.insert(result.cbegin() + a2, literals[a1]);
269 break;
270 case _Ops::OpInsertRef: // a1: result index -> a2: result index.
271 result.insert(result.cbegin() + a2, cresult[a1]);
272 break;
273 case _Ops::OpEraseRef: // a1: result index, (a2: unused)
274 result.erase(result.cbegin() + a1);
275 break;
276 case _Ops::OpMinSize: // a1: minimum size, (a2: unused)
277 if (result.size() < static_cast<size_t>(a1)) {
278 result.resize(a1);
279 }
280 break;
281 case _Ops::OpMinSizeFill: // a1: minimum size, a2: literal index.
282 if (result.size() < static_cast<size_t>(a1)) {
283 result.resize(a1, literals[a2]);
284 }
285 break;
286 case _Ops::OpSetSize: // a1: explicit size, (a2: unused)
287 result.resize(a1);
288 break;
289 case _Ops::OpSetSizeFill: // a1: explicit size, a2: literal index.
290 result.resize(a1, literals[a2]);
291 break;
292 case _Ops::OpMaxSize: // a1: maximum size, a2: unused
293 if (result.size() > static_cast<size_t>(a1)) {
294 result.resize(a1);
295 }
296 break;
297 };
298 });
299 return result;
300}
301
302template <class ELEM>
305{
306 TRACE_FUNCTION();
307
308 // Both this and weaker consist of edits. We compose the edits and we can
309 // steal our resources.
310
311 // For now we just append the stronger literals, and update all the stronger
312 // literal indexes with the offset. We can do more in-depth analysis and
313 // things like dead store elimination and deduplicating literals in the
314 // future.
315
316 VtArrayEdit result = std::move(*this);
317
318 // Append the stronger literals to weaker.
319 // result._literals =
320 // weaker._literals + result._literals;
321 result._literals.insert(
322 result._literals.begin(),
323 weaker._literals.begin(), weaker._literals.end());
324
325 // Bump the literal indexes in result._ops to account for weaker's
326 // literals.
327 const auto numWeakerLiterals = weaker._literals.size();
328 result._ops.ModifyEach([&](_Ops::Op op, int64_t &a1, int64_t) {
329 switch (op) {
330 case _Ops::OpWriteLiteral: // a1: literal index -> a2: result index.
331 case _Ops::OpInsertLiteral:
332 a1 += numWeakerLiterals;
333 default:
334 break;
335 };
336 });
337
338 result._ops._ins.insert(result._ops._ins.begin(),
339 weaker._ops._ins.begin(),
340 weaker._ops._ins.end());
341
342 return result;
343}
344
345template <class ELEM>
348{
349 TRACE_FUNCTION();
350
351 // Both this and weaker consist of edits. We compose the edits and we can
352 // steal both our resources and weaker's.
353
354 // For now we just append the stronger literals and stronger ops, and update
355 // all the stronger literal indexes with the offset. We can do more
356 // in-depth analysis and things like dead store elimination and
357 // deduplicating literals in the future.
358
359 VtArrayEdit result = std::move(*this);
360
361 const auto numWeakerLiterals = weaker._literals.size();
362
363 // Append the stronger literals to weaker.
364 weaker._literals.insert(
365 weaker._literals.end(),
366 std::make_move_iterator(result._literals.begin()),
367 std::make_move_iterator(result._literals.end()));
368
369 // Bump the literal indexes in the stronger _ops to account for weaker's
370 // literals.
371 result._ops.ModifyEach([&](_Ops::Op op, int64_t &a1, int64_t) {
372 switch (op) {
373 case _Ops::OpWriteLiteral: // a1: literal index -> a2: result index.
374 case _Ops::OpInsertLiteral:
375 a1 += numWeakerLiterals;
376 default:
377 break;
378 };
379 });
380
381 // Append the stronger ops to weaker.
382 weaker._ops._ins.insert(
383 weaker._ops._ins.end(),
384 std::make_move_iterator(result._ops._ins.begin()),
385 std::make_move_iterator(result._ops._ins.end()));
386
387 return std::move(weaker);
388}
389
390// Specialize traits for VtArrayEdit.
391template <typename T>
392struct VtIsArrayEdit<VtArrayEdit<T>> : public std::true_type {};
393
394PXR_NAMESPACE_CLOSE_SCOPE
395
396#endif // PXR_BASE_VT_ARRAY_EDIT_H
Low-level utilities for informing users of various internal and external diagnostic conditions.
This class provides a non-owning reference to a type-erased callable object with a specified signatur...
Definition: functionRef.h:19
A builder type that produces instances of VtArrayEdit representing sequences of array edit operations...
An array edit represents a sequence of per-element modifications to a VtArray.
Definition: arrayEdit.h:51
bool IsIdentity() const
Return true if this edit is the identity edit.
Definition: arrayEdit.h:74
friend bool operator!=(VtArrayEdit const &x, VtArrayEdit const &y)
Inequality comparison.
Definition: arrayEdit.h:67
friend bool operator==(VtArrayEdit const &x, VtArrayEdit const &y)
Equality comparison.
Definition: arrayEdit.h:63
Array ComposeOver(Array &&weaker) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: arrayEdit.h:123
VtArray< ELEM > Array
Shorthand for the corresponding VtArray type.
Definition: arrayEdit.h:54
std::ostream & StreamCustom(std::ostream &out, UnaryOp &&unaryOp) const
Insert self to the stream out, but call unaryOp on each contained value-type element and pass the res...
Definition: arrayEdit.h:172
VtArrayEdit ComposeOver(VtArrayEdit &&weaker) &&
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: arrayEdit.h:91
friend std::ostream & operator<<(std::ostream &out, const VtArrayEdit self)
Insert self to the stream out using the following format:
Definition: arrayEdit.h:157
Array ComposeOver(Array const &weaker) const
Apply the edits in *this to weaker and return the resulting array.
Definition: arrayEdit.h:115
VtArrayEdit()=default
Construct an identity array edit that performs no edits.
VtArrayEdit ComposeOver(VtArrayEdit const &weaker) &&
Compose this edit over weaker and return a new result representing the function composition,...
Definition: arrayEdit.h:83
VtArrayEdit ComposeOver(VtArrayEdit const &weaker) const &
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: arrayEdit.h:99
VtArrayEdit ComposeOver(VtArrayEdit &&weaker) const &
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: arrayEdit.h:107
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:213
ELEM ElementType
Type this array holds.
Definition: array.h:218
size_t size() const
Return the total number of elements in this array.
Definition: array.h:474
iterator insert(const_iterator pos, value_type const &value)
Insert a copy of a single element at pos into the array.
Definition: array.h:648
iterator end()
Returns a non-const iterator to the end of the array.
Definition: array.h:368
iterator begin()
Return a non-const iterator to the start of the array.
Definition: array.h:365
A trait to detect instantiations of VtArrayEdit, specialized in arrayEdit.h.
Definition: traits.h:26