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, _ins,
78 std::forward<Fn>(fn));
84 void ForEach(Fn &&fn)
const {
85 return _ForEachImpl(-1, -1, _ins, std::forward<Fn>(fn));
92 void ModifyEach(Fn &&fn) {
93 return _ForEachImpl(-1, -1, _ins, std::forward<Fn>(fn));
97 bool IsEmpty()
const {
102 template <
class ELEM>
105 template <
class ELEM>
108 friend class Vt_ArrayEditOpsBuilder;
110 template <
class HashState>
111 friend void TfHashAppend(HashState &h, Vt_ArrayEditOps
const &self) {
116 operator==(Vt_ArrayEditOps
const &l, Vt_ArrayEditOps
const &r) {
117 return l._ins == r._ins;
120 operator!=(Vt_ArrayEditOps
const &l, Vt_ArrayEditOps
const &r) {
124 static OpAndCount _ToOpAndCount(int64_t i64) {
126 memcpy(&oc, &i64,
sizeof(oc));
130 static int64_t _ToInt64(OpAndCount oc) {
132 memcpy(&i64, &oc,
sizeof(i64));
136 static constexpr size_t _DisableBoundsCheck = size_t(-1);
139 void _IssueInvalidInsError(
140 OpAndCount oc,
size_t offset,
size_t required,
size_t actual)
const;
143 void _IssueInvalidOpError(OpAndCount oc,
size_t offset)
const;
145 VT_API
static void _LiteralOutOfBounds(int64_t idx,
size_t size);
146 VT_API
static void _ReferenceOutOfBounds(int64_t idx,
size_t size);
147 VT_API
static void _InsertOutOfBounds(int64_t idx,
size_t size);
148 VT_API
static void _NegativeSizeArg(Op op, int64_t idx);
150 static bool _CheckLiteralIndex(int64_t idx,
size_t size) {
151 if (size == _DisableBoundsCheck ||
152 (idx >= 0 &&
static_cast<size_t>(idx) < size)) {
155 _LiteralOutOfBounds(idx, size);
159 static bool _NormalizeAndCheckRefIndex(int64_t &idx,
size_t size) {
160 if (size == _DisableBoundsCheck) {
166 if (idx >= 0 &&
static_cast<size_t>(idx) < size) {
169 _ReferenceOutOfBounds(idx, size);
173 static bool _NormalizeAndCheckInsertIndex(int64_t &idx,
size_t size) {
174 if (size == _DisableBoundsCheck) {
177 if (idx == EndIndex) {
183 if (idx >= 0 &&
static_cast<size_t>(idx) <= size) {
186 _InsertOutOfBounds(idx, size);
190 static bool _CheckSizeArg(Op op, int64_t arg) {
192 _NegativeSizeArg(op, arg);
198 static void _UpdateWorkingSize(
size_t &workingSize,
size_t newSize) {
199 if (workingSize == _DisableBoundsCheck) {
202 workingSize = newSize;
205 template <
class Ins,
class Fn>
206 void _ForEachImpl(
size_t numLiterals,
size_t initialSize,
207 Ins &&ins, Fn &&fn)
const {
210 const auto begin = std::begin(std::forward<Ins>(ins));
211 auto iter = std::begin(std::forward<Ins>(ins));
212 const auto end = std::end(std::forward<Ins>(ins));
214 while (iter != end) {
215 OpAndCount oc = _ToOpAndCount(*iter);
217 if (!IsValidOp(oc.op)) {
218 _IssueInvalidOpError(oc, std::distance(begin, iter));
222 const int arity = GetArity(oc.op);
225 if (std::distance(++iter, end) < oc.count * arity) {
226 _IssueInvalidInsError(
227 oc, std::distance(begin, iter),
228 oc.count * arity, std::distance(iter, end));
232 for (; oc.count--; iter += arity) {
233 int64_t a1 = iter[0];
234 int64_t a2 = arity > 1 ? iter[1] : -1;
239 _IssueInvalidOpError(oc, std::distance(begin, iter));
242 if (!_CheckLiteralIndex(a1, numLiterals) ||
243 !_NormalizeAndCheckRefIndex(a2, initialSize)) {
248 if (!_NormalizeAndCheckRefIndex(a1, initialSize) ||
249 !_NormalizeAndCheckRefIndex(a2, initialSize)) {
253 case OpInsertLiteral:
254 if (!_CheckLiteralIndex(a1, numLiterals) ||
255 !_NormalizeAndCheckInsertIndex(a2, initialSize)) {
258 _UpdateWorkingSize(initialSize, initialSize + 1);
261 if (!_NormalizeAndCheckRefIndex(a1, initialSize) ||
262 !_NormalizeAndCheckInsertIndex(a2, initialSize)) {
265 _UpdateWorkingSize(initialSize, initialSize + 1);
268 if (!_NormalizeAndCheckRefIndex(a1, initialSize)) {
271 _UpdateWorkingSize(initialSize, initialSize - 1);
275 if (!_CheckLiteralIndex(a2, numLiterals)) {
279 if (!_CheckSizeArg(oc.op, a1)) {
284 std::max(initialSize,
static_cast<size_t>(a1)));
288 if (!_CheckLiteralIndex(a2, numLiterals)) {
292 if (!_CheckSizeArg(oc.op, a1)) {
295 _UpdateWorkingSize(initialSize, a1);
299 if (!_CheckSizeArg(oc.op, a1)) {
304 std::min(initialSize,
static_cast<size_t>(a1)));
310 std::forward<Fn>(fn)(oc.op, a1, a2);
335 std::vector<int64_t> _ins;
339PXR_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.