Loading...
Searching...
No Matches
arrayEditBuilder.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_BUILDER_H
9#define PXR_BASE_VT_ARRAY_EDIT_BUILDER_H
10
12
13#include "pxr/pxr.h"
14#include "pxr/base/vt/api.h"
15#include "pxr/base/vt/array.h"
18#include "pxr/base/vt/hash.h"
19#include "pxr/base/vt/streamOut.h"
20
22#include "pxr/base/tf/span.h"
23
24#include <unordered_map>
25
26PXR_NAMESPACE_OPEN_SCOPE
27
28// Non-template helper class for VtArrayEditBuilder.
29class Vt_ArrayEditOpsBuilder
30{
31public:
32 using Ops = Vt_ArrayEditOps;
33
34 VT_API
35 void AddOp(Ops::Op op, int64_t a1, int64_t a2);
36
37 VT_API
38 void AddOp(Ops::Op op, int64_t a1);
39
40private:
41 template <class ELEM>
42 friend class VtArrayEditBuilder;
43
44 void _AddOp(Ops::Op op);
45
46 static void _IssueArityError(Ops::Op op, int count);
47 static void _IssueNegativeSizeError(Ops::Op op, int64_t size);
48
49 static inline bool _CheckArity(Ops::Op op, int count);
50
51 std::vector<int64_t> _ins;
52 int64_t _lastOpIdx = 0;
53};
54
64template <class ELEM>
66{
67public:
68 using Ops = Vt_ArrayEditOps;
69 using Edit = VtArrayEdit<ELEM>;
70 using Array = typename Edit::Array;
71 using ElementType = typename Edit::ElementType;
73
76 static constexpr auto EndIndex = Vt_ArrayEditOps::EndIndex;
77
79 VtArrayEditBuilder() = default;
80
85 Self &Write(ElementType const &elem, int64_t index) {
86 _opsBuilder.AddOp(Ops::OpWriteLiteral, _FindOrAddLiteral(elem), index);
87 return *this;
88 }
89
94 Self &WriteRef(int64_t srcIndex, int64_t dstIndex) {
95 _opsBuilder.AddOp(Ops::OpWriteRef, srcIndex, dstIndex);
96 return *this;
97 }
98
104 Self &Insert(ElementType const &elem, int64_t index) {
105 _opsBuilder.AddOp(Ops::OpInsertLiteral, _FindOrAddLiteral(elem), index);
106 return *this;
107 }
108
115 Self &InsertRef(int64_t srcIndex, int64_t dstIndex) {
116 _opsBuilder.AddOp(Ops::OpInsertRef, srcIndex, dstIndex);
117 return *this;
118 }
119
121 Self &Prepend(ElementType const &elem) {
122 _opsBuilder.AddOp(Ops::OpInsertLiteral, _FindOrAddLiteral(elem), 0);
123 return *this;
124 }
125
127 Self &PrependRef(int64_t srcIndex) {
128 _opsBuilder.AddOp(Ops::OpInsertRef, srcIndex, 0);
129 return *this;
130 }
131
133 Self &Append(ElementType const &elem) {
134 _opsBuilder.AddOp(
135 Ops::OpInsertLiteral, _FindOrAddLiteral(elem), EndIndex);
136 return *this;
137 }
138
140 Self &AppendRef(int64_t srcIndex) {
141 _opsBuilder.AddOp(Ops::OpInsertRef, srcIndex, EndIndex);
142 return *this;
143 }
144
149 Self &EraseRef(int64_t index) {
150 _opsBuilder.AddOp(Ops::OpEraseRef, index);
151 return *this;
152 }
153
156 Self &MinSize(int64_t size) {
157 _opsBuilder.AddOp(Ops::OpMinSize, size);
158 return *this;
159 }
160
163 Self &MinSize(int64_t size, ElementType const &fill) {
164 _opsBuilder.AddOp(Ops::OpMinSizeFill, size, _FindOrAddLiteral(fill));
165 return *this;
166 }
167
170 Self &MaxSize(int64_t size) {
171 _opsBuilder.AddOp(Ops::OpMaxSize, size);
172 return *this;
173 }
174
178 Self &SetSize(int64_t size) {
179 _opsBuilder.AddOp(Ops::OpSetSize, size);
180 return *this;
181 }
182
187 Self &SetSize(int64_t size, ElementType const &fill) {
188 _opsBuilder.AddOp(Ops::OpSetSizeFill, size, _FindOrAddLiteral(fill));
189 return *this;
190 }
191
196 VtArrayEdit<ELEM> result;
197 result._literals = std::move(_literals);
198 result._ops._ins = std::move(_opsBuilder._ins);
199 *this = {};
200 return result;
201 }
202
207
208 // Return data for serializing `edit`, so it can be reconstructed later by
209 // CreateFromSerializationData().
210 //
211 // This API is intended to be called only by storage/transmission
212 // implementations.
213 static void
214 GetSerializationData(VtArrayEdit<ELEM> const &edit,
215 VtArray<ELEM> *valuesOut,
216 std::vector<int64_t> *indexesOut) {
217 if (TF_VERIFY(valuesOut) && TF_VERIFY(indexesOut)) {
218 *valuesOut = edit._literals;
219 *indexesOut = edit._ops._ins;
220 }
221 }
222
223 // Construct an array edit using serialization data previously obtained from
224 // GetSerializationData().
225 //
226 // This API is intended to be called only by storage/transmission
227 // implementations.
228 static VtArrayEdit<ELEM>
229 CreateFromSerializationData(VtArray<ELEM> const &values,
230 TfSpan<int64_t> indexes) {
231 VtArrayEdit<ELEM> result;
232 result._literals = values;
233 result._ops._ins = std::vector<int64_t>(indexes.begin(), indexes.end());
234 return result;
235 }
236
237private:
238 int64_t _FindOrAddLiteral(ElementType const &elem) {
239 auto iresult = _literalToIndex.emplace(elem, _literals.size());
240 if (iresult.second) {
241 _literals.push_back(elem);
242 }
243 return iresult.first->second;
244 }
245
246 Array _literals;
247 Vt_ArrayEditOpsBuilder _opsBuilder;
248 std::unordered_map<ElementType, int64_t, TfHash> _literalToIndex;
249
250};
251
252template <class ELEM>
255{
256 if (in.IsIdentity()) {
257 return std::move(in);
258 }
259
260 VtArrayEditBuilder builder;
261
262 // Walk all the instructions and rebuild.
263 const Array literals = std::move(in._literals);
264 const auto numLiterals = literals.size();
265 Ops ops = std::move(in._ops);
266
267 in._literals.clear();
268 in._ops = {};
269
270 ops.ForEach([&](Ops::Op op, int64_t a1, int64_t a2) {
271 switch (op) {
272 case Ops::OpWriteLiteral:
273 // Ignore out-of-range literal indexes.
274 if (a1 >= 0 && static_cast<size_t>(a1) < numLiterals) {
275 builder.Write(literals[a1], a2);
276 }
277 break;
278 case Ops::OpInsertLiteral:
279 // Ignore out-of-range literal indexes.
280 if (a1 >= 0 && static_cast<size_t>(a1) < numLiterals) {
281 builder.Insert(literals[a1], a2);
282 }
283 break;
284 case Ops::OpWriteRef: builder.WriteRef(a1, a2); break;
285 case Ops::OpInsertRef: builder.InsertRef(a1, a2); break;
286 case Ops::OpEraseRef: builder.EraseRef(a1); break;
287 case Ops::OpMinSize: builder.MinSize(a1); break;
288 case Ops::OpSetSize: builder.SetSize(a1); break;
289 case Ops::OpMaxSize: builder.MaxSize(a1); break;
290 case Ops::OpMinSizeFill:
291 // Ignore out-of-range literal indexes.
292 if (a1 >= 0 && static_cast<size_t>(a1) < numLiterals) {
293 builder.MinSize(a1, literals[a2]);
294 }
295 break;
296 case Ops::OpSetSizeFill:
297 // Ignore out-of-range literal indexes.
298 if (a1 >= 0 && static_cast<size_t>(a1) < numLiterals) {
299 builder.SetSize(a1, literals[a2]);
300 }
301 break;
302 };
303 });
304
305 return builder.FinalizeAndReset();
306}
307
308PXR_NAMESPACE_CLOSE_SCOPE
309
310#endif // PXR_BASE_VT_ARRAY_EDIT_BUILDER_H
Low-level utilities for informing users of various internal and external diagnostic conditions.
Represents a range of contiguous elements.
Definition: span.h:71
iterator end() const noexcept
Returns a non-const iterator to the end of the span.
Definition: span.h:168
iterator begin() const noexcept
Returns a non-const iterator the start of the span.
Definition: span.h:162
A builder type that produces instances of VtArrayEdit representing sequences of array edit operations...
Self & Prepend(ElementType const &elem)
Equivalent to Insert(elem, 0)
Self & MinSize(int64_t size)
Add an instruction that, if the array's size is less than size, appends value-initialized elements to...
Self & Append(ElementType const &elem)
Equivalent to Insert(elem, EndIndex)
Self & MinSize(int64_t size, ElementType const &fill)
Add an instruction that, if the array's size is less than size, appends copies of fill to the array u...
Self & EraseRef(int64_t index)
Add an instruction that erases the element at index.
VtArrayEdit< ELEM > FinalizeAndReset()
Return a VtArrayEdit that performs the edits as specified by prior calls to this class's other member...
Self & AppendRef(int64_t srcIndex)
Equivalent to InsertRef(srcIndex, EndIndex)
Self & SetSize(int64_t size, ElementType const &fill)
Add an instruction that, if the array's size is not equal to size, then items are either appended or ...
Self & InsertRef(int64_t srcIndex, int64_t dstIndex)
Add an instruction that inserts a copy of the element at srcIndex at dstIndex.
static VtArrayEdit< ELEM > Optimize(VtArrayEdit< ELEM > &&in)
Given a VtArrayEdit that may have been composed from several, attempt to produce a smaller,...
Self & PrependRef(int64_t srcIndex)
Equivalent to InsertRef(srcIndex, 0)
Self & SetSize(int64_t size)
Add an instruction that, if the array's size is not equal to size, then items are either appended or ...
Self & Write(ElementType const &elem, int64_t index)
Add an instruction that writes elem to index.
Self & WriteRef(int64_t srcIndex, int64_t dstIndex)
Add an instruction that writes the element at srcIndex to dstIndex.
Self & Insert(ElementType const &elem, int64_t index)
Add an instruction that inserts elem at index.
static constexpr auto EndIndex
A special index value meaning one-past-the-end of the array, for use in Insert() instructions.
Self & MaxSize(int64_t size)
Add an instruction that, if the array's size is greater than size erases trailing elements until it h...
VtArrayEditBuilder()=default
Default construct a builder with no instructions.
An array edit represents a sequence of per-element modifications to a VtArray.
Definition: arrayEdit.h:51
VtArray< ELEM > Array
Shorthand for the corresponding VtArray type.
Definition: arrayEdit.h:54
Represents an arbitrary dimensional rectangular container class.
Definition: array.h:213
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.
Definition: diagnostic.h:266