8#ifndef PXR_BASE_VT_ARRAY_EDIT_OPS_H
9#define PXR_BASE_VT_ARRAY_EDIT_OPS_H
14#include "pxr/base/vt/api.h"
24PXR_NAMESPACE_OPEN_SCOPE
30 static constexpr int64_t EndIndex = std::numeric_limits<int64_t>::min();
50 static constexpr uint8_t NumOps = OpMaxSize + 1;
52 static constexpr bool IsValidOp(Op op) {
53 return op >=
static_cast<Op
>(0) && op < NumOps;
56 static constexpr int GetArity(Op op) {
57 if (op == OpWriteLiteral || op == OpWriteRef ||
58 op == OpInsertLiteral || op == OpInsertRef ||
59 op == OpMinSizeFill || op == OpSetSizeFill) {
70 static_assert(
sizeof(OpAndCount) ==
sizeof(int64_t));
76 void ForEachValid(
size_t numLiterals,
size_t initialSize, Fn &&fn)
const {
77 return _ForEachImpl(numLiterals, initialSize, std::forward<Fn>(fn));
83 void ForEach(Fn &&fn)
const {
84 return _ForEachImpl(-1, -1, std::forward<Fn>(fn));
95 void OffsetLiteralIndexes(int64_t offset) {
96 _ModifyImpl([offset](Op op, int64_t &a1, int64_t &a2) {
118 bool IsEmpty()
const {
123 template <
class ELEM>
126 template <
class ELEM>
129 friend class Vt_ArrayEditOpsBuilder;
131 template <
class HashState>
132 friend void TfHashAppend(HashState &h, Vt_ArrayEditOps
const &self) {
137 operator==(Vt_ArrayEditOps
const &l, Vt_ArrayEditOps
const &r) {
138 return l._ins == r._ins;
141 operator!=(Vt_ArrayEditOps
const &l, Vt_ArrayEditOps
const &r) {
145 static OpAndCount _ToOpAndCount(int64_t i64) {
147 memcpy(&oc, &i64,
sizeof(oc));
151 static int64_t _ToInt64(OpAndCount oc) {
153 memcpy(&i64, &oc,
sizeof(i64));
157 static constexpr size_t _DisableBoundsCheck = size_t(-1);
160 void _IssueInvalidInsError(
161 OpAndCount oc,
size_t offset,
size_t required,
size_t actual)
const;
164 void _IssueInvalidOpError(OpAndCount oc,
size_t offset)
const;
166 VT_API
static void _LiteralOutOfBounds(int64_t idx,
size_t size);
167 VT_API
static void _ReferenceOutOfBounds(int64_t idx,
size_t size);
168 VT_API
static void _InsertOutOfBounds(int64_t idx,
size_t size);
169 VT_API
static void _NegativeSizeArg(Op op, int64_t idx);
171 static bool _CheckLiteralIndex(int64_t idx,
size_t size) {
172 if (size == _DisableBoundsCheck ||
173 (idx >= 0 &&
static_cast<size_t>(idx) < size)) {
176 _LiteralOutOfBounds(idx, size);
180 static bool _NormalizeAndCheckRefIndex(int64_t &idx,
size_t size) {
181 if (size == _DisableBoundsCheck) {
187 if (idx >= 0 &&
static_cast<size_t>(idx) < size) {
190 _ReferenceOutOfBounds(idx, size);
194 static bool _NormalizeAndCheckInsertIndex(int64_t &idx,
size_t size) {
195 if (size == _DisableBoundsCheck) {
198 if (idx == EndIndex) {
204 if (idx >= 0 &&
static_cast<size_t>(idx) <= size) {
207 _InsertOutOfBounds(idx, size);
211 static bool _CheckSizeArg(Op op, int64_t arg) {
213 _NegativeSizeArg(op, arg);
219 static void _UpdateWorkingSize(
size_t &workingSize,
size_t newSize) {
220 if (workingSize == _DisableBoundsCheck) {
223 workingSize = newSize;
227 void _ForEachImpl(
size_t numLiterals,
size_t initialSize, Fn &&fn)
const {
230 const auto begin = std::begin(_ins);
231 auto iter = std::begin(_ins);
232 const auto end = std::end(_ins);
234 while (iter != end) {
235 OpAndCount oc = _ToOpAndCount(*iter);
237 if (!IsValidOp(oc.op)) {
238 _IssueInvalidOpError(oc, std::distance(begin, iter));
242 const int arity = GetArity(oc.op);
245 if (std::distance(++iter, end) < oc.count * arity) {
246 _IssueInvalidInsError(
247 oc, std::distance(begin, iter),
248 oc.count * arity, std::distance(iter, end));
252 for (; oc.count--; iter += arity) {
253 int64_t a1 = iter[0];
254 int64_t a2 = arity > 1 ? iter[1] : -1;
259 _IssueInvalidOpError(oc, std::distance(begin, iter));
262 if (!_CheckLiteralIndex(a1, numLiterals) ||
263 !_NormalizeAndCheckRefIndex(a2, initialSize)) {
268 if (!_NormalizeAndCheckRefIndex(a1, initialSize) ||
269 !_NormalizeAndCheckRefIndex(a2, initialSize)) {
273 case OpInsertLiteral:
274 if (!_CheckLiteralIndex(a1, numLiterals) ||
275 !_NormalizeAndCheckInsertIndex(a2, initialSize)) {
278 _UpdateWorkingSize(initialSize, initialSize + 1);
281 if (!_NormalizeAndCheckRefIndex(a1, initialSize) ||
282 !_NormalizeAndCheckInsertIndex(a2, initialSize)) {
285 _UpdateWorkingSize(initialSize, initialSize + 1);
288 if (!_NormalizeAndCheckRefIndex(a1, initialSize)) {
291 _UpdateWorkingSize(initialSize, initialSize - 1);
295 if (!_CheckLiteralIndex(a2, numLiterals)) {
299 if (!_CheckSizeArg(oc.op, a1)) {
304 std::max(initialSize,
static_cast<size_t>(a1)));
308 if (!_CheckLiteralIndex(a2, numLiterals)) {
312 if (!_CheckSizeArg(oc.op, a1)) {
315 _UpdateWorkingSize(initialSize, a1);
319 if (!_CheckSizeArg(oc.op, a1)) {
324 std::min(initialSize,
static_cast<size_t>(a1)));
330 std::forward<Fn>(fn)(oc.op, a1, a2);
341 void _ModifyImpl(Fn &&fn) {
344 const auto begin = std::begin(_ins);
345 auto iter = std::begin(_ins);
346 const auto end = std::end(_ins);
348 while (iter != end) {
349 OpAndCount oc = _ToOpAndCount(*iter);
351 if (!IsValidOp(oc.op)) {
352 _IssueInvalidOpError(oc, std::distance(begin, iter));
356 const int arity = GetArity(oc.op);
359 if (std::distance(++iter, end) < oc.count * arity) {
360 _IssueInvalidInsError(
361 oc, std::distance(begin, iter),
362 oc.count * arity, std::distance(iter, end));
366 for (; oc.count--; iter += arity) {
367 int64_t invalid = -1;
368 int64_t &a1 = iter[0];
369 int64_t &a2 = arity > 1 ? iter[1] : invalid;
372 std::forward<Fn>(fn)(oc.op, a1, a2);
397 std::vector<int64_t> _ins;
401PXR_NAMESPACE_CLOSE_SCOPE
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.