nk 1.0.0
C++ Numerical Computing Runtime
Loading...
Searching...
No Matches
dims.hpp
1// include/dims.hpp
2#pragma once
3
4#include <cstddef>
5#include <cstdint>
6
7namespace nk {
8
9// ============================================================
10// Dims — array dimensions, ND with SBO storage.
11//
12// Layout:
13// * inline_ holds dims [0, kInlineCap). Slots beyond ndim() are
14// always = 1 (so trailing-singleton equality semantics work
15// without per-call branching).
16// * For ndim() > kInlineCap, the extra dims live on heap_, indexed
17// as heap_[i - kInlineCap]. heap_ == nullptr when ndim() <= kInlineCap.
18//
19// The SBO threshold of 4 covers MATLAB's typical use (scalar / vector /
20// matrix / 3D-volume / 4D-batch tensor) without any allocation. Heap is
21// reserved for the genuinely ND case (5D+). Same pattern as
22// llvm::SmallVector / pytorch::DimVector.
23//
24// rows()/cols()/pages() are inline aliases on inline_[0/1/2] — no
25// branch on the hot accessor path. dim(i) branches on i < kInlineCap;
26// for compile-time-constant i (the common case in 2D/3D code) the
27// optimiser folds the branch away.
28// ============================================================
29struct Dims
30{
31 static constexpr int kInlineCap = 4;
32 // Maximum supported rank for any ND op. Used as a stack-buffer
33 // bound (e.g. `size_t coords[Dims::kMaxRank]`) and a sanity-check
34 // ceiling. 32 is well above any practical use.
35 static constexpr int kMaxRank = 32;
36
37 Dims();
38 Dims(size_t r, size_t c);
39 Dims(size_t r, size_t c, size_t p);
40 Dims(const size_t *dims, int nd);
41
42 Dims(const Dims &o);
43 Dims(Dims &&o) noexcept;
44 Dims &operator=(const Dims &o);
45 Dims &operator=(Dims &&o) noexcept;
46 ~Dims();
47
48 int ndims() const noexcept { return nd_; }
49 int ndim() const noexcept { return nd_; }
50 size_t rows() const noexcept { return inline_[0]; }
51 size_t cols() const noexcept { return inline_[1]; }
52 size_t pages() const noexcept { return inline_[2]; }
53
54 size_t dim(int i) const noexcept
55 {
56 if (i < 0) return 1;
57 if (i < kInlineCap) return inline_[i];
58 if (i < nd_) return heap_[i - kInlineCap];
59 return 1;
60 }
61
62 size_t dimSize(int i) const noexcept { return dim(i); }
63
64 size_t numel() const noexcept
65 {
66 size_t n = inline_[0] * inline_[1] * inline_[2] * inline_[3];
67 if (heap_) {
68 const int extra = nd_ - kInlineCap;
69 for (int i = 0; i < extra; ++i)
70 n *= heap_[i];
71 }
72 return n;
73 }
74
75 bool isScalar() const noexcept { return numel() == 1; }
76 bool isEmpty() const noexcept { return numel() == 0; }
77 bool isVector() const noexcept
78 {
79 return nd_ == 2 && (inline_[0] == 1 || inline_[1] == 1);
80 }
81 bool is3D() const noexcept { return nd_ == 3 && inline_[2] > 1; }
82
83 size_t sub2ind(size_t r, size_t c) const noexcept
84 {
85 return c * inline_[0] + r;
86 }
87 size_t sub2ind(size_t r, size_t c, size_t p) const noexcept
88 {
89 return p * inline_[0] * inline_[1] + c * inline_[0] + r;
90 }
91 size_t sub2indChecked(size_t r, size_t c) const;
92 size_t sub2indChecked(size_t r, size_t c, size_t p) const;
93
94 bool operator==(const Dims &o) const noexcept;
95 bool operator!=(const Dims &o) const noexcept { return !(*this == o); }
96
97private:
98 void setND(const size_t *dims, int nd);
99 void freeHeap() noexcept;
100
101 size_t inline_[kInlineCap];
102 size_t *heap_;
103 uint8_t nd_;
104};
105
106} // namespace nk