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"
23#include "pxr/base/tf/span.h"
25
26#include <iosfwd>
27#include <type_traits>
28
29PXR_NAMESPACE_OPEN_SCOPE
30
31template <class ELEM>
32class VtArrayEditBuilder; // fwd
33
50template <class ELEM>
52{
53public:
56
57 using ElementType = typename Array::ElementType;
58
61 VtArrayEdit() = default;
62
64 friend bool operator==(VtArrayEdit const &x, VtArrayEdit const &y) {
65 return std::tie(x._literals, x._ops) == std::tie(y._literals, y._ops);
66 }
68 friend bool operator!=(VtArrayEdit const &x, VtArrayEdit const &y) {
69 return !(x == y);
70 }
71
75 bool IsIdentity() const {
76 return _ops.IsEmpty();
77 }
78
81 return _literals;
82 }
83
88 return _literals;
89 }
90
97 if (IsIdentity()) {
98 return weaker;
99 }
100 return _ComposeEdits(weaker);
101 }
102
105 if (IsIdentity()) {
106 return std::move(weaker);
107 }
108 return _ComposeEdits(std::move(weaker));
109 }
110
112 VtArrayEdit ComposeOver(VtArrayEdit const &weaker) const & {
113 if (IsIdentity()) {
114 return weaker;
115 }
116 return _ComposeEdits(weaker);
117 };
118
121 if (IsIdentity()) {
122 return std::move(weaker);
123 }
124 return _ComposeEdits(std::move(weaker));
125 }
126
128 Array ComposeOver(Array const &weaker) const {
129 if (IsIdentity()) {
130 return weaker;
131 }
132 return _ApplyEdits(weaker);
133 }
134
136 Array ComposeOver(Array &&weaker) const {
137 if (IsIdentity()) {
138 return std::move(weaker);
139 }
140 return _ApplyEdits(weaker);
141 }
142
169 friend std::ostream &
170 operator<<(std::ostream &out, const VtArrayEdit self) {
171 auto streamElem = [&](int64_t index) -> std::ostream & {
172 return VtStreamOut(self._literals[index], out);
173 };
174 return Vt_ArrayEditStreamImpl(
175 self._ops, self._literals.size(), streamElem, out);
176 }
177
183 template <class UnaryOp>
184 std::ostream &
185 StreamCustom(std::ostream &out, UnaryOp &&unaryOp) const {
186 auto streamElem = [&](int64_t index) -> std::ostream & {
187 return VtStreamOut(
188 std::forward<UnaryOp>(unaryOp)(_literals[index]),
189 out);
190 };
191 return Vt_ArrayEditStreamImpl(_ops, _literals.size(), streamElem, out);
192 }
193
194private:
195 friend class VtArrayEditBuilder<ELEM>;
196 friend struct Vt_ArrayEditHashAccess;
197
198 friend
199 std::ostream &Vt_ArrayEditStreamImpl(
200 Vt_ArrayEditOps const &ops, size_t literalsSize,
201 TfFunctionRef<std::ostream &(int64_t index)> elemToStr,
202 std::ostream &out);
203
204 using _Ops = Vt_ArrayEditOps;
205
206 Array _ApplyEdits(Array &&weaker) const;
207 Array _ApplyEdits(Array const &weaker) const {
208 return _ApplyEdits(Array {weaker});
209 }
210
211 VtArrayEdit _ComposeEdits(VtArrayEdit &&weaker) &&;
212 VtArrayEdit _ComposeEdits(VtArrayEdit const &weaker) &&;
213
214 VtArrayEdit _ComposeEdits(VtArrayEdit &&weaker) const & {
215 return VtArrayEdit(*this)._ComposeEdits(std::move(weaker));
216 }
217 VtArrayEdit _ComposeEdits(VtArrayEdit const &weaker) const & {
218 return VtArrayEdit(*this)._ComposeEdits(weaker);
219 }
220
221 Array _literals;
222 _Ops _ops;
223};
224
225VT_API
226std::ostream &Vt_ArrayEditStreamImpl(
227 Vt_ArrayEditOps const &ops, size_t literalsSize,
228 TfFunctionRef<std::ostream &(int64_t index)> streamElem,
229 std::ostream &out);
230
231struct Vt_ArrayEditHashAccess
232{
233 template <class HashState, class Edit>
234 static void Append(HashState &h, Edit const &edit) {
235 h.Append(edit._literals, edit._ops);
236 }
237};
238
239template <class HashState, class ELEM>
240std::enable_if_t<VtIsHashable<ELEM>()>
241TfHashAppend(HashState &h, VtArrayEdit<ELEM> const &edit) {
242 Vt_ArrayEditHashAccess::Append(h, edit);
243}
244
245template <class ELEM>
247VtArrayEdit<ELEM>::_ApplyEdits(Array &&weaker) const
248{
249 TRACE_FUNCTION();
250
251 // weaker is an array that we edit.
252 Array result = std::move(weaker);
253 Array const &cresult = result;
254
255 Array const &literals = _literals;
256 const auto numLiterals = literals.size();
257
258 // XXX: Note that this does not handle certain sequences of inserts and
259 // erases (specifically those that insert or erase contiguous ranges of
260 // elements) optimally. This could be improved by detecting these cases and
261 // doing a single batch insert or erase instead, to minimize shuffling the
262 // other elements.
263
264 _ops.ForEachValid(numLiterals, cresult.size(),
265 [&](_Ops::Op op, int64_t a1, int64_t a2) {
266 switch (op) {
267 case _Ops::OpWriteLiteral:
268 result[a2] = literals[a1];
269 break;
270 case _Ops::OpWriteRef: // a1: result index -> a2: result index.
271 result[a2] = cresult[a1];
272 break;
273 case _Ops::OpInsertLiteral: // a1: literal index -> a2: result index.
274 result.insert(result.cbegin() + a2, literals[a1]);
275 break;
276 case _Ops::OpInsertRef: // a1: result index -> a2: result index.
277 result.insert(result.cbegin() + a2, cresult[a1]);
278 break;
279 case _Ops::OpEraseRef: // a1: result index, (a2: unused)
280 result.erase(result.cbegin() + a1);
281 break;
282 case _Ops::OpMinSize: // a1: minimum size, (a2: unused)
283 if (result.size() < static_cast<size_t>(a1)) {
284 result.resize(a1);
285 }
286 break;
287 case _Ops::OpMinSizeFill: // a1: minimum size, a2: literal index.
288 if (result.size() < static_cast<size_t>(a1)) {
289 result.resize(a1, literals[a2]);
290 }
291 break;
292 case _Ops::OpSetSize: // a1: explicit size, (a2: unused)
293 result.resize(a1);
294 break;
295 case _Ops::OpSetSizeFill: // a1: explicit size, a2: literal index.
296 result.resize(a1, literals[a2]);
297 break;
298 case _Ops::OpMaxSize: // a1: maximum size, a2: unused
299 if (result.size() > static_cast<size_t>(a1)) {
300 result.resize(a1);
301 }
302 break;
303 };
304 });
305 return result;
306}
307
308template <class ELEM>
311{
312 TRACE_FUNCTION();
313
314 // Both this and weaker consist of edits. We compose the edits and we can
315 // steal our resources.
316
317 // For now we just append the stronger literals, and update all the stronger
318 // literal indexes with the offset. We can do more in-depth analysis and
319 // things like dead store elimination and deduplicating literals in the
320 // future.
321
322 VtArrayEdit result = std::move(*this);
323
324 // Append the stronger literals to weaker.
325 // result._literals =
326 // weaker._literals + result._literals;
327 result._literals.insert(
328 result._literals.begin(),
329 weaker._literals.begin(), weaker._literals.end());
330
331 // Bump the literal indexes in result._ops to account for weaker's
332 // literals.
333 const auto numWeakerLiterals = weaker._literals.size();
334 result._ops.ModifyEach([&](_Ops::Op op, int64_t &a1, int64_t) {
335 switch (op) {
336 case _Ops::OpWriteLiteral: // a1: literal index -> a2: result index.
337 case _Ops::OpInsertLiteral:
338 a1 += numWeakerLiterals;
339 default:
340 break;
341 };
342 });
343
344 result._ops._ins.insert(result._ops._ins.begin(),
345 weaker._ops._ins.begin(),
346 weaker._ops._ins.end());
347
348 return result;
349}
350
351template <class ELEM>
354{
355 TRACE_FUNCTION();
356
357 // Both this and weaker consist of edits. We compose the edits and we can
358 // steal both our resources and weaker's.
359
360 // For now we just append the stronger literals and stronger ops, and update
361 // all the stronger literal indexes with the offset. We can do more
362 // in-depth analysis and things like dead store elimination and
363 // deduplicating literals in the future.
364
365 VtArrayEdit result = std::move(*this);
366
367 const auto numWeakerLiterals = weaker._literals.size();
368
369 // Append the stronger literals to weaker.
370 weaker._literals.insert(
371 weaker._literals.end(),
372 std::make_move_iterator(result._literals.begin()),
373 std::make_move_iterator(result._literals.end()));
374
375 // Bump the literal indexes in the stronger _ops to account for weaker's
376 // literals.
377 result._ops.ModifyEach([&](_Ops::Op op, int64_t &a1, int64_t) {
378 switch (op) {
379 case _Ops::OpWriteLiteral: // a1: literal index -> a2: result index.
380 case _Ops::OpInsertLiteral:
381 a1 += numWeakerLiterals;
382 default:
383 break;
384 };
385 });
386
387 // Append the stronger ops to weaker.
388 weaker._ops._ins.insert(
389 weaker._ops._ins.end(),
390 std::make_move_iterator(result._ops._ins.begin()),
391 std::make_move_iterator(result._ops._ins.end()));
392
393 return std::move(weaker);
394}
395
396// Specialize traits for VtArrayEdit.
397template <typename T>
398struct VtIsArrayEdit<VtArrayEdit<T>> : public std::true_type {};
399
400// VtArrayEdit can transform if the underlying element type can.
401template <class ELEM>
404
405// VtArrayEdit can compose over itself, VtArray, and the VtBackground.
406template <class T>
407struct VtValueTypeCanCompose<VtArrayEdit<T>> : std::true_type {};
408
409PXR_NAMESPACE_CLOSE_SCOPE
410
411#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
Represents a range of contiguous elements.
Definition: span.h:71
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:52
bool IsIdentity() const
Return true if this edit is the identity edit.
Definition: arrayEdit.h:75
friend bool operator!=(VtArrayEdit const &x, VtArrayEdit const &y)
Inequality comparison.
Definition: arrayEdit.h:68
friend bool operator==(VtArrayEdit const &x, VtArrayEdit const &y)
Equality comparison.
Definition: arrayEdit.h:64
TfSpan< const ElementType > GetLiterals() const
Return a view of the literal elements that this edit makes use of.
Definition: arrayEdit.h:80
TfSpan< ElementType > GetMutableLiterals()
Return a mutable view of the literal elements that this edit makes use of.
Definition: arrayEdit.h:87
Array ComposeOver(Array &&weaker) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: arrayEdit.h:136
VtArray< ELEM > Array
Shorthand for the corresponding VtArray type.
Definition: arrayEdit.h:55
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:185
VtArrayEdit ComposeOver(VtArrayEdit &&weaker) &&
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: arrayEdit.h:104
friend std::ostream & operator<<(std::ostream &out, const VtArrayEdit self)
Insert self to the stream out using the following format:
Definition: arrayEdit.h:170
Array ComposeOver(Array const &weaker) const
Apply the edits in *this to weaker and return the resulting array.
Definition: arrayEdit.h:128
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:96
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:112
VtArrayEdit ComposeOver(VtArrayEdit &&weaker) const &
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: arrayEdit.h:120
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
A trait indicating whether VtValue compose-over functionality can be registered for a type.
Definition: traits.h:137
A trait indicating whether VtValue transform functionality can be registered for a type.
Definition: traits.h:147