Open3D (C++ API)  0.19.0
Loading...
Searching...
No Matches
Indexer.h
Go to the documentation of this file.
1// ----------------------------------------------------------------------------
2// - Open3D: www.open3d.org -
3// ----------------------------------------------------------------------------
4// Copyright (c) 2018-2024 www.open3d.org
5// SPDX-License-Identifier: MIT
6// ----------------------------------------------------------------------------
7
8#pragma once
9
10#include <sstream>
11
13#include "open3d/core/Dtype.h"
16#include "open3d/core/Tensor.h"
19
20// The generated "Indexer_ispc.h" header will not be available outside the
21// library. Therefore, forward declare all exported ISPC classes.
22#ifdef BUILD_ISPC_MODULE
23namespace ispc {
24struct TensorRef;
25struct Indexer;
26} // namespace ispc
27#endif
28
29namespace open3d {
30namespace core {
31
32class Indexer;
33
34class IndexerIterator;
35
36// Maximum number of dimensions of TensorRef.
37static constexpr int64_t MAX_DIMS = 5;
38
39// Maximum number of inputs of an op.
40// MAX_INPUTS shall be >= MAX_DIMS to support advanced indexing.
41static constexpr int64_t MAX_INPUTS = 5;
42
43// Maximum number of outputs of an op. This number can be increased when
44// necessary.
45static constexpr int64_t MAX_OUTPUTS = 2;
46
47template <int NARGS, typename index_t = uint32_t>
50 const int64_t* sizes,
51 const int64_t* const* strides)
52 : dims_(dims) {
53 if (dims_ > MAX_DIMS) {
54 utility::LogError("tensor has too many (>{}) dims_", MAX_DIMS);
55 }
56
57 for (int i = 0; i < MAX_DIMS; ++i) {
58 if (i < dims_) {
59 sizes_[i] = sizes[i];
60 } else {
61 sizes_[i] = 1;
62 }
63 for (int arg = 0; arg < NARGS; arg++) {
64 strides_[i][arg] = i < dims_ ? strides[arg][i] : 0;
65 }
66 }
67 }
68
70 index_t linear_idx) const {
72#if defined(__CUDA_ARCH__)
73#pragma unroll
74#endif
75 for (int arg = 0; arg < NARGS; arg++) {
76 offsets[arg] = 0;
77 }
78
79#if defined(__CUDA_ARCH__)
80#pragma unroll
81#endif
82 for (int dim = 0; dim < MAX_DIMS; ++dim) {
83 if (dim == dims_) {
84 break;
85 }
86 index_t mod = linear_idx % sizes_[dim];
87 linear_idx = linear_idx / sizes_[dim];
88
89#if defined(__CUDA_ARCH__)
90#pragma unroll
91#endif
92 for (int arg = 0; arg < NARGS; arg++) {
93 offsets[arg] += mod * strides_[dim][arg];
94 }
95 }
96 return offsets;
97 }
98
99 int dims_;
100 index_t sizes_[MAX_DIMS];
101 index_t strides_[MAX_DIMS][NARGS];
102};
103
105struct TensorRef {
106 // The default copy constructor works on __device__ as well so we don't
107 // define it explicitly. shape_[MAX_DIMS] and strides[MAX_DIMS] will be
108 // copied fully.
110
111 TensorRef(const Tensor& t) {
112 if (t.NumDims() > MAX_DIMS) {
113 utility::LogError("Tensor has too many dimensions {} > {}.",
114 t.NumDims(), MAX_DIMS);
115 }
116 data_ptr_ = const_cast<void*>(t.GetDataPtr());
117 ndims_ = t.NumDims();
118 dtype_byte_size_ = t.GetDtype().ByteSize();
119 for (int64_t i = 0; i < ndims_; ++i) {
120 shape_[i] = t.GetShape(i);
121 byte_strides_[i] = t.GetStride(i) * dtype_byte_size_;
122 }
123 }
124
131 void Permute(const SizeVector& dims) {
132 // Check dims are permuntation of [0, 1, 2, ..., n-1]
133 if (static_cast<int64_t>(dims.size()) != ndims_) {
134 utility::LogError("Number of dimensions mismatch {} != {}.",
135 dims.size(), ndims_);
136 }
137 std::vector<bool> seen_dims(ndims_, false);
138 for (const int64_t& dim : dims) {
139 seen_dims[dim] = true;
140 }
141 if (!std::all_of(seen_dims.begin(), seen_dims.end(),
142 [](bool seen) { return seen; })) {
143 utility::LogError(
144 "Permute dims must be a permuntation from 0 to {}.",
145 dims.size() - 1);
146 }
147
148 // Map to new shape and strides
149 SizeVector new_shape(ndims_);
150 SizeVector new_byte_strides(ndims_);
151 for (int64_t i = 0; i < ndims_; ++i) {
152 int64_t old_dim = shape_util::WrapDim(dims[i], ndims_);
153 new_shape[i] = shape_[old_dim];
154 new_byte_strides[i] = byte_strides_[old_dim];
155 }
156 for (int64_t i = 0; i < ndims_; ++i) {
157 shape_[i] = new_shape[i];
158 byte_strides_[i] = new_byte_strides[i];
159 }
160 }
161
163 inline bool IsContiguous() const {
164 SizeVector shape(ndims_);
165 SizeVector strides(ndims_);
166 for (int64_t i = 0; i < ndims_; ++i) {
167 shape[i] = shape_[i];
168 strides[i] = byte_strides_[i] / dtype_byte_size_;
169 }
170 return shape_util::DefaultStrides(shape) == strides;
171 }
172
173 bool operator==(const TensorRef& other) const {
174 bool rc = true;
175 rc = rc && (data_ptr_ == other.data_ptr_);
176 rc = rc && (ndims_ == other.ndims_);
177 rc = rc && (dtype_byte_size_ == other.dtype_byte_size_);
178 for (int64_t i = 0; i < ndims_; ++i) {
179 rc = rc && (shape_[i] == other.shape_[i]);
180 rc = rc && (byte_strides_[i] == other.byte_strides_[i]);
181 }
182 return rc;
183 }
184
185 bool operator!=(const TensorRef& other) const { return !(*this == other); }
186
187#ifdef BUILD_ISPC_MODULE
189 ispc::TensorRef ToISPC() const;
190#endif
191
193 int64_t ndims_ = 0;
194 int64_t dtype_byte_size_ = 0;
195 int64_t shape_[MAX_DIMS];
196 int64_t byte_strides_[MAX_DIMS];
197};
198
199enum class DtypePolicy {
200 NONE, // Do not check. Expects the kernel to handle the conversion.
201 // E.g. in Copy kernel with type casting.
202 ALL_SAME, // All inputs and outputs to to have the same dtype.
203 INPUT_SAME, // All inputs have the same dtype.
204 INPUT_SAME_OUTPUT_BOOL // All inputs have the same dtype. Outputs
205 // have bool dtype.
206};
207
226public:
227 TensorIterator(const Tensor& tensor)
228 : input_(TensorRef(tensor)), ndims_(tensor.NumDims()) {
229 is_contiguous_ = true;
230 int64_t expected_byte_stride = input_.dtype_byte_size_;
231 for (int64_t d = ndims_ - 1; d >= 0; --d) {
232 if (input_.byte_strides_[d] != expected_byte_stride) {
233 is_contiguous_ = false;
234 break;
235 }
236 expected_byte_stride *= input_.shape_[d];
237 }
238 }
239
241 int64_t num_workloads = 1;
242 for (int64_t i = 0; i < ndims_; ++i) {
243 num_workloads *= input_.shape_[i];
244 }
245 return num_workloads;
246 }
247
249 OPEN3D_HOST_DEVICE void* GetPtr(int64_t workload_idx) const {
250 if (workload_idx < 0 || workload_idx >= NumWorkloads()) {
251 return nullptr;
252 }
253 if (is_contiguous_) {
254 return static_cast<char*>(input_.data_ptr_) +
255 workload_idx * input_.dtype_byte_size_;
256 }
257 int64_t offset = 0;
258 int64_t remaining = workload_idx;
259 for (int64_t d = ndims_ - 1; d >= 0; --d) {
260 const int64_t coord = remaining % input_.shape_[d];
261 remaining /= input_.shape_[d];
262 offset += coord * input_.byte_strides_[d];
263 }
264 return static_cast<char*>(input_.data_ptr_) + offset;
265 }
266
267protected:
269 int64_t ndims_;
271};
272
280class Indexer {
281public:
283 Indexer(const Indexer&) = default;
284 Indexer& operator=(const Indexer&) = default;
285
289 Indexer(const std::vector<Tensor>& input_tensors,
290 const Tensor& output_tensor,
291 DtypePolicy dtype_policy = DtypePolicy::ALL_SAME,
292 const SizeVector& reduction_dims = {});
293
294 Indexer(const std::vector<Tensor>& input_tensors,
295 const std::vector<Tensor>& output_tensors,
296 DtypePolicy dtype_policy = DtypePolicy::ALL_SAME,
297 const SizeVector& reduction_dims = {});
298
300 bool CanUse32BitIndexing() const;
301
304 IndexerIterator SplitTo32BitIndexing() const;
305
309 std::unique_ptr<Indexer> SplitLargestDim();
310
313 Indexer GetPerOutputIndexer(int64_t output_idx) const;
314
315 bool ShouldAccumulate() const { return accumulate_; }
316
317 bool IsFinalOutput() const { return final_output_; }
318
324 void ShrinkDim(int64_t dim, int64_t start, int64_t size);
325
327 int64_t NumReductionDims() const;
328
330 int64_t NumDims() const { return ndims_; }
331
334 const int64_t* GetPrimaryShape() const { return primary_shape_; }
335 int64_t* GetPrimaryShape() { return primary_shape_; }
336
339 const int64_t* GetPrimaryStrides() const { return primary_strides_; }
340
351 int64_t NumWorkloads() const;
352
354 int64_t NumOutputElements() const;
355
357 int64_t NumInputs() const { return num_inputs_; }
358
360 int64_t NumOutputs() const { return num_outputs_; }
361
363 TensorRef& GetInput(int64_t i) {
364 if (i >= num_inputs_ || i < 0) {
365 utility::LogError("0 <= i < {} required, however, i = {}.",
366 num_inputs_, i);
367 }
368 return inputs_[i];
369 }
370 const TensorRef& GetInput(int64_t i) const {
371 if (i >= num_inputs_ || i < 0) {
372 utility::LogError("0 <= i < {} required, however, i = {}.",
373 num_inputs_, i);
374 }
375 return inputs_[i];
376 }
377
379 TensorRef& GetOutput(int64_t i) {
380 if (i >= num_outputs_ || i < 0) {
381 utility::LogError("0 <= i < {} required, however, i = {}.",
382 num_outputs_, i);
383 }
384 return outputs_[i];
385 }
386 const TensorRef& GetOutput(int64_t i) const {
387 if (i >= num_outputs_ || i < 0) {
388 utility::LogError("0 <= i < {} required, however, i = {}.",
389 num_outputs_, i);
390 }
391 return outputs_[i];
392 }
393
397 if (num_outputs_ > 1) {
398 utility::LogError("num_outputs_ == {} > 0, use GetOutput(i)",
400 }
401 return GetOutput(0);
402 }
403 const TensorRef& GetOutput() const {
404 if (num_outputs_ > 1) {
405 utility::LogError("num_outputs_ == {} > 0, use GetOutput(i)",
407 }
408 return GetOutput(0);
409 }
410
412 bool IsReductionDim(int64_t dim) const {
413 // All outputs have the same shape and reduction dims. Even if they
414 // don't have the same initial strides, the reduced strides are always
415 // set to 0. Thus it is okay to use outputs_[0].
416 return outputs_[0].byte_strides_[dim] == 0 && primary_shape_[dim] > 1;
417 }
418
424 OPEN3D_HOST_DEVICE char* GetInputPtr(int64_t input_idx,
425 int64_t workload_idx) const {
426 if (input_idx < 0 || input_idx >= num_inputs_) {
427 return nullptr;
428 }
429 return GetWorkloadDataPtr(inputs_[input_idx],
430 inputs_contiguous_[input_idx], workload_idx);
431 }
432
441 template <typename T>
442 OPEN3D_HOST_DEVICE T* GetInputPtr(int64_t input_idx,
443 int64_t workload_idx) const {
444 if (input_idx < 0 || input_idx >= num_inputs_) {
445 return nullptr;
446 }
447 return GetWorkloadDataPtr<T>(inputs_[input_idx],
448 inputs_contiguous_[input_idx],
449 workload_idx);
450 }
451
456 OPEN3D_HOST_DEVICE char* GetOutputPtr(int64_t workload_idx) const {
458 workload_idx);
459 }
460
468 template <typename T>
469 OPEN3D_HOST_DEVICE T* GetOutputPtr(int64_t workload_idx) const {
470 return GetWorkloadDataPtr<T>(outputs_[0], outputs_contiguous_[0],
471 workload_idx);
472 }
473
479 OPEN3D_HOST_DEVICE char* GetOutputPtr(int64_t output_idx,
480 int64_t workload_idx) const {
481 return GetWorkloadDataPtr(outputs_[output_idx],
482 outputs_contiguous_[output_idx],
483 workload_idx);
484 }
485
491 template <typename T>
492 OPEN3D_HOST_DEVICE T* GetOutputPtr(int64_t output_idx,
493 int64_t workload_idx) const {
494 return GetWorkloadDataPtr<T>(outputs_[output_idx],
495 outputs_contiguous_[output_idx],
496 workload_idx);
497 }
498
499#ifdef BUILD_ISPC_MODULE
501 ispc::Indexer ToISPC() const;
502#endif
503
504protected:
507 void CoalesceDimensions();
508
509 // Permute reduction dimensions to front.
510 // TODO: Sort the dimensions based on strides in ascending orderto improve
511 // thread coalescing.
512 void ReorderDimensions(const SizeVector& reduction_dims);
513
516
519
546 static void BroadcastRestride(TensorRef& src,
547 int64_t dst_ndims,
548 const int64_t* dst_shape);
549
552 static void ReductionRestride(TensorRef& dst,
553 int64_t src_ndims,
554 const int64_t* src_shape,
555 const SizeVector& reduction_dims);
556
561 bool tr_contiguous,
562 int64_t workload_idx) const {
563 // For 0-sized input reduction op, the output Tensor
564 // workload_idx == 1 > NumWorkloads() == 0.
565 if (workload_idx < 0) {
566 return nullptr;
567 }
568 if (tr_contiguous) {
569 return static_cast<char*>(tr.data_ptr_) +
570 workload_idx * tr.dtype_byte_size_;
571 } else {
572 int64_t offset = 0;
573 for (int64_t i = 0; i < ndims_; ++i) {
574 offset += workload_idx / primary_strides_[i] *
575 tr.byte_strides_[i];
576 workload_idx = workload_idx % primary_strides_[i];
577 }
578 return static_cast<char*>(tr.data_ptr_) + offset;
579 }
580 }
581
588 template <typename T>
590 bool tr_contiguous,
591 int64_t workload_idx) const {
592 // For 0-sized input reduction op, the output Tensor
593 // workload_idx == 1 > NumWorkloads() == 0.
594 if (workload_idx < 0) {
595 return nullptr;
596 }
597 if (tr_contiguous) {
598 return static_cast<T*>(tr.data_ptr_) + workload_idx;
599 } else {
600 int64_t offset = 0;
601 for (int64_t i = 0; i < ndims_; ++i) {
602 offset += workload_idx / primary_strides_[i] *
603 tr.byte_strides_[i];
604 workload_idx = workload_idx % primary_strides_[i];
605 }
606 return static_cast<T*>(static_cast<void*>(
607 static_cast<char*>(tr.data_ptr_) + offset));
608 }
609 }
610
612 int64_t num_inputs_ = 0;
613 int64_t num_outputs_ = 0;
614
616 TensorRef inputs_[MAX_INPUTS];
617
619 TensorRef outputs_[MAX_OUTPUTS];
620
622 bool inputs_contiguous_[MAX_INPUTS];
623
625 bool outputs_contiguous_[MAX_OUTPUTS];
626
638 int64_t primary_shape_[MAX_DIMS];
639
642 int64_t primary_strides_[MAX_DIMS];
643
645 int64_t ndims_ = 0;
646
650 bool final_output_ = true;
651
654 bool accumulate_ = false;
655};
656
658public:
659 struct Iterator {
661 Iterator(const Indexer& indexer);
662 Iterator(Iterator&& other) = default;
663
664 Indexer& operator*() const;
666 bool operator==(const Iterator& other) const;
667 bool operator!=(const Iterator& other) const;
668
669 std::vector<std::unique_ptr<Indexer>> vec_;
670 };
671
673
674 Iterator begin() const;
675 Iterator end() const;
676
677private:
678 const Indexer& indexer_;
679};
680
681} // namespace core
682} // namespace open3d
Common CUDA utilities.
#define OPEN3D_HOST_DEVICE
Definition CUDAUtils.h:43
double t
Definition SurfaceReconstructionPoisson.cpp:172
Indexer indexer
Definition UnaryEWSYCL.cpp:34
Definition Indexer.h:280
const TensorRef & GetInput(int64_t i) const
Definition Indexer.h:370
void UpdatePrimaryStrides()
Update primary_strides_ based on primary_shape_.
Definition Indexer.cpp:556
void UpdateContiguousFlags()
Update input_contiguous_ and output_contiguous_.
Definition Indexer.cpp:565
bool inputs_contiguous_[MAX_INPUTS]
Array of contiguous flags for all input TensorRefs.
Definition Indexer.h:622
bool outputs_contiguous_[MAX_OUTPUTS]
Array of contiguous flags for all output TensorRefs.
Definition Indexer.h:625
Indexer()
Definition Indexer.h:282
OPEN3D_HOST_DEVICE T * GetOutputPtr(int64_t output_idx, int64_t workload_idx) const
Definition Indexer.h:492
int64_t num_outputs_
Definition Indexer.h:613
OPEN3D_HOST_DEVICE char * GetOutputPtr(int64_t output_idx, int64_t workload_idx) const
Definition Indexer.h:479
TensorRef & GetOutput(int64_t i)
Returns output TensorRef.
Definition Indexer.h:379
static void ReductionRestride(TensorRef &dst, int64_t src_ndims, const int64_t *src_shape, const SizeVector &reduction_dims)
Definition Indexer.cpp:602
TensorRef outputs_[MAX_OUTPUTS]
Array of output TensorRefs.
Definition Indexer.h:619
bool IsReductionDim(int64_t dim) const
Returns true if the dim -th dimension is reduced.
Definition Indexer.h:412
int64_t NumReductionDims() const
Returns the number of reduction dimensions.
Definition Indexer.cpp:395
int64_t NumInputs() const
Number of input Tensors.
Definition Indexer.h:357
int64_t primary_strides_[MAX_DIMS]
Definition Indexer.h:642
const TensorRef & GetOutput() const
Definition Indexer.h:403
Indexer(const Indexer &)=default
bool IsFinalOutput() const
Definition Indexer.h:317
void ReorderDimensions(const SizeVector &reduction_dims)
Definition Indexer.cpp:491
void CoalesceDimensions()
Definition Indexer.cpp:425
Indexer & operator=(const Indexer &)=default
int64_t NumOutputElements() const
Returns the number of output elements.
Definition Indexer.cpp:414
int64_t num_inputs_
Number of input and output Tensors.
Definition Indexer.h:612
bool accumulate_
Definition Indexer.h:654
bool CanUse32BitIndexing() const
Returns true iff the maximum_offsets in bytes are smaller than 2^31 - 1.
Definition Indexer.cpp:198
TensorRef inputs_[MAX_INPUTS]
Array of input TensorRefs.
Definition Indexer.h:616
OPEN3D_HOST_DEVICE char * GetWorkloadDataPtr(const TensorRef &tr, bool tr_contiguous, int64_t workload_idx) const
Definition Indexer.h:560
OPEN3D_HOST_DEVICE T * GetOutputPtr(int64_t workload_idx) const
Definition Indexer.h:469
bool ShouldAccumulate() const
Definition Indexer.h:315
const int64_t * GetPrimaryStrides() const
Definition Indexer.h:339
Indexer GetPerOutputIndexer(int64_t output_idx) const
Definition Indexer.cpp:303
std::unique_ptr< Indexer > SplitLargestDim()
Definition Indexer.cpp:238
OPEN3D_HOST_DEVICE T * GetWorkloadDataPtr(const TensorRef &tr, bool tr_contiguous, int64_t workload_idx) const
Definition Indexer.h:589
OPEN3D_HOST_DEVICE char * GetOutputPtr(int64_t workload_idx) const
Definition Indexer.h:456
OPEN3D_HOST_DEVICE T * GetInputPtr(int64_t input_idx, int64_t workload_idx) const
Definition Indexer.h:442
int64_t NumWorkloads() const
Definition Indexer.cpp:406
OPEN3D_HOST_DEVICE char * GetInputPtr(int64_t input_idx, int64_t workload_idx) const
Definition Indexer.h:424
IndexerIterator SplitTo32BitIndexing() const
Definition Indexer.cpp:234
const int64_t * GetPrimaryShape() const
Definition Indexer.h:334
TensorRef & GetInput(int64_t i)
Returns input TensorRef.
Definition Indexer.h:363
TensorRef & GetOutput()
Definition Indexer.h:396
static void BroadcastRestride(TensorRef &src, int64_t dst_ndims, const int64_t *dst_shape)
Definition Indexer.cpp:575
bool final_output_
Definition Indexer.h:650
const TensorRef & GetOutput(int64_t i) const
Definition Indexer.h:386
int64_t ndims_
Indexer's global number of dimensions.
Definition Indexer.h:645
void ShrinkDim(int64_t dim, int64_t start, int64_t size)
Definition Indexer.cpp:364
int64_t NumDims() const
Returns number of dimensions of the Indexer.
Definition Indexer.h:330
int64_t NumOutputs() const
Number of output Tensors.
Definition Indexer.h:360
int64_t * GetPrimaryShape()
Definition Indexer.h:335
int64_t primary_shape_[MAX_DIMS]
Definition Indexer.h:638
Definition Indexer.h:657
Iterator end() const
Definition Indexer.cpp:671
Iterator begin() const
Definition Indexer.cpp:667
Definition SizeVector.h:69
size_t size() const
Definition SmallVector.h:120
Definition Tensor.h:32
Definition Indexer.h:225
OPEN3D_HOST_DEVICE int64_t NumWorkloads() const
Definition Indexer.h:240
TensorRef input_
Definition Indexer.h:268
TensorIterator(const Tensor &tensor)
Definition Indexer.h:227
bool is_contiguous_
Definition Indexer.h:270
OPEN3D_HOST_DEVICE void * GetPtr(int64_t workload_idx) const
Pointer to the element at linear index workload_idx, or nullptr.
Definition Indexer.h:249
int64_t ndims_
Definition Indexer.h:269
int size
Definition FilePCD.cpp:41
int offset
Definition FilePCD.cpp:46
int64_t WrapDim(int64_t dim, int64_t max_dim, bool inclusive)
Wrap around negative dim.
Definition ShapeUtil.cpp:131
SizeVector DefaultStrides(const SizeVector &shape)
Compute default strides for a shape when a tensor is contiguous.
Definition ShapeUtil.cpp:214
DtypePolicy
Definition Indexer.h:199
Definition PinholeCameraIntrinsic.cpp:16
bool operator!=(const Iterator &other) const
Definition Indexer.cpp:663
Iterator()
Definition Indexer.h:660
std::vector< std::unique_ptr< Indexer > > vec_
Definition Indexer.h:669
Iterator(Iterator &&other)=default
Indexer & operator*() const
Definition Indexer.cpp:649
bool operator==(const Iterator &other) const
Definition Indexer.cpp:660
Iterator & operator++()
Definition Indexer.cpp:651
Definition Indexer.h:48
index_t sizes_[MAX_DIMS]
Definition Indexer.h:100
OPEN3D_HOST_DEVICE utility::MiniVec< index_t, NARGS > get(index_t linear_idx) const
Definition Indexer.h:69
int dims_
Definition Indexer.h:99
OffsetCalculator(int dims, const int64_t *sizes, const int64_t *const *strides)
Definition Indexer.h:49
index_t strides_[MAX_DIMS][NARGS]
Definition Indexer.h:101
A minimalistic class that reference a Tensor.
Definition Indexer.h:105
int64_t dtype_byte_size_
Definition Indexer.h:194
void Permute(const SizeVector &dims)
Permute (dimension shuffle) the reference to a Tensor.
Definition Indexer.h:131
int64_t ndims_
Definition Indexer.h:193
bool operator!=(const TensorRef &other) const
Definition Indexer.h:185
TensorRef(const Tensor &t)
Definition Indexer.h:111
TensorRef()
Definition Indexer.h:109
int64_t shape_[MAX_DIMS]
Definition Indexer.h:195
bool IsContiguous() const
Returns True if the underlying memory buffer is contiguous.
Definition Indexer.h:163
void * data_ptr_
Definition Indexer.h:192
bool operator==(const TensorRef &other) const
Definition Indexer.h:173
int64_t byte_strides_[MAX_DIMS]
Definition Indexer.h:196
Definition MiniVec.h:24