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
231// Declare basic arrayEdit instantiations as extern templates. They are
232// explicitly instantiated in arrayEdit.cpp.
233#define VT_ARRAY_EDIT_EXTERN_TMPL(unused, elem) \
234 VT_API_TEMPLATE_CLASS(VtArrayEdit< VT_TYPE(elem) >);
235TF_PP_SEQ_FOR_EACH(VT_ARRAY_EDIT_EXTERN_TMPL, ~, VT_SCALAR_VALUE_TYPES)
236#undef VT_ARRAY_EDIT_EXTERN_TMPL
237
238struct Vt_ArrayEditHashAccess
239{
240 template <class HashState, class Edit>
241 static void Append(HashState &h, Edit const &edit) {
242 h.Append(edit._literals, edit._ops);
243 }
244};
245
246template <class HashState, class ELEM>
247std::enable_if_t<VtIsHashable<ELEM>()>
248TfHashAppend(HashState &h, VtArrayEdit<ELEM> const &edit) {
249 Vt_ArrayEditHashAccess::Append(h, edit);
250}
251
252template <class ELEM>
254VtArrayEdit<ELEM>::_ApplyEdits(Array &&weaker) const
255{
256 TRACE_FUNCTION();
257
258 // weaker is an array that we edit.
259 Array result = std::move(weaker);
260 Array const &cresult = result;
261
262 Array const &literals = _literals;
263 const auto numLiterals = literals.size();
264
265 // XXX: Note that this does not handle certain sequences of inserts and
266 // erases (specifically those that insert or erase contiguous ranges of
267 // elements) optimally. This could be improved by detecting these cases and
268 // doing a single batch insert or erase instead, to minimize shuffling the
269 // other elements.
270
271 _ops.ForEachValid(numLiterals, cresult.size(),
272 [&](_Ops::Op op, int64_t a1, int64_t a2) {
273 switch (op) {
274 case _Ops::OpWriteLiteral:
275 result[a2] = literals[a1];
276 break;
277 case _Ops::OpWriteRef: // a1: result index -> a2: result index.
278 result[a2] = cresult[a1];
279 break;
280 case _Ops::OpInsertLiteral: // a1: literal index -> a2: result index.
281 result.insert(result.cbegin() + a2, literals[a1]);
282 break;
283 case _Ops::OpInsertRef: // a1: result index -> a2: result index.
284 result.insert(result.cbegin() + a2, cresult[a1]);
285 break;
286 case _Ops::OpEraseRef: // a1: result index, (a2: unused)
287 result.erase(result.cbegin() + a1);
288 break;
289 case _Ops::OpMinSize: // a1: minimum size, (a2: unused)
290 if (result.size() < static_cast<size_t>(a1)) {
291 result.resize(a1);
292 }
293 break;
294 case _Ops::OpMinSizeFill: // a1: minimum size, a2: literal index.
295 if (result.size() < static_cast<size_t>(a1)) {
296 result.resize(a1, literals[a2]);
297 }
298 break;
299 case _Ops::OpSetSize: // a1: explicit size, (a2: unused)
300 result.resize(a1);
301 break;
302 case _Ops::OpSetSizeFill: // a1: explicit size, a2: literal index.
303 result.resize(a1, literals[a2]);
304 break;
305 case _Ops::OpMaxSize: // a1: maximum size, a2: unused
306 if (result.size() > static_cast<size_t>(a1)) {
307 result.resize(a1);
308 }
309 break;
310 };
311 });
312 return result;
313}
314
315template <class ELEM>
318{
319 TRACE_FUNCTION();
320
321 // Both this and weaker consist of edits. We compose the edits and we can
322 // steal our resources.
323
324 // For now we just append the stronger literals, and update all the stronger
325 // literal indexes with the offset. We can do more in-depth analysis and
326 // things like dead store elimination and deduplicating literals in the
327 // future.
328
329 VtArrayEdit result = std::move(*this);
330
331 // Append the stronger literals to weaker.
332 // result._literals =
333 // weaker._literals + result._literals;
334 result._literals.insert(
335 result._literals.begin(),
336 weaker._literals.begin(), weaker._literals.end());
337
338 // Bump the literal indexes in result._ops to account for weaker's
339 // literals.
340 const auto numWeakerLiterals = weaker._literals.size();
341 result._ops.ModifyEach([&](_Ops::Op op, int64_t &a1, int64_t) {
342 switch (op) {
343 case _Ops::OpWriteLiteral: // a1: literal index -> a2: result index.
344 case _Ops::OpInsertLiteral:
345 a1 += numWeakerLiterals;
346 default:
347 break;
348 };
349 });
350
351 result._ops._ins.insert(result._ops._ins.begin(),
352 weaker._ops._ins.begin(),
353 weaker._ops._ins.end());
354
355 return result;
356}
357
358template <class ELEM>
361{
362 TRACE_FUNCTION();
363
364 // Both this and weaker consist of edits. We compose the edits and we can
365 // steal both our resources and weaker's.
366
367 // For now we just append the stronger literals and stronger ops, and update
368 // all the stronger literal indexes with the offset. We can do more
369 // in-depth analysis and things like dead store elimination and
370 // deduplicating literals in the future.
371
372 VtArrayEdit result = std::move(*this);
373
374 const auto numWeakerLiterals = weaker._literals.size();
375
376 // Append the stronger literals to weaker.
377 weaker._literals.insert(
378 weaker._literals.end(),
379 std::make_move_iterator(result._literals.begin()),
380 std::make_move_iterator(result._literals.end()));
381
382 // Bump the literal indexes in the stronger _ops to account for weaker's
383 // literals.
384 result._ops.ModifyEach([&](_Ops::Op op, int64_t &a1, int64_t) {
385 switch (op) {
386 case _Ops::OpWriteLiteral: // a1: literal index -> a2: result index.
387 case _Ops::OpInsertLiteral:
388 a1 += numWeakerLiterals;
389 default:
390 break;
391 };
392 });
393
394 // Append the stronger ops to weaker.
395 weaker._ops._ins.insert(
396 weaker._ops._ins.end(),
397 std::make_move_iterator(result._ops._ins.begin()),
398 std::make_move_iterator(result._ops._ins.end()));
399
400 return std::move(weaker);
401}
402
403// Specialize traits for VtArrayEdit.
404template <typename T>
405struct VtIsArrayEdit<VtArrayEdit<T>> : public std::true_type {};
406
407// VtArrayEdit can transform if the underlying element type can.
408template <class ELEM>
411
412// VtArrayEdit can compose over itself, VtArray, and the VtBackground.
413template <class T>
414struct VtValueTypeCanCompose<VtArrayEdit<T>> : std::true_type {};
415
416PXR_NAMESPACE_CLOSE_SCOPE
417
418#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