numkong 7.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +495 -0
  3. package/binding.gyp +540 -0
  4. package/c/dispatch.h +512 -0
  5. package/c/dispatch_bf16.c +389 -0
  6. package/c/dispatch_bf16c.c +52 -0
  7. package/c/dispatch_e2m3.c +263 -0
  8. package/c/dispatch_e3m2.c +243 -0
  9. package/c/dispatch_e4m3.c +276 -0
  10. package/c/dispatch_e5m2.c +272 -0
  11. package/c/dispatch_f16.c +376 -0
  12. package/c/dispatch_f16c.c +58 -0
  13. package/c/dispatch_f32.c +378 -0
  14. package/c/dispatch_f32c.c +99 -0
  15. package/c/dispatch_f64.c +296 -0
  16. package/c/dispatch_f64c.c +98 -0
  17. package/c/dispatch_i16.c +96 -0
  18. package/c/dispatch_i32.c +89 -0
  19. package/c/dispatch_i4.c +150 -0
  20. package/c/dispatch_i64.c +86 -0
  21. package/c/dispatch_i8.c +289 -0
  22. package/c/dispatch_other.c +330 -0
  23. package/c/dispatch_u1.c +148 -0
  24. package/c/dispatch_u16.c +124 -0
  25. package/c/dispatch_u32.c +118 -0
  26. package/c/dispatch_u4.c +150 -0
  27. package/c/dispatch_u64.c +102 -0
  28. package/c/dispatch_u8.c +303 -0
  29. package/c/numkong.c +950 -0
  30. package/include/README.md +573 -0
  31. package/include/module.modulemap +129 -0
  32. package/include/numkong/attention/sapphireamx.h +1361 -0
  33. package/include/numkong/attention/sme.h +2066 -0
  34. package/include/numkong/attention.h +49 -0
  35. package/include/numkong/capabilities.h +748 -0
  36. package/include/numkong/cast/README.md +262 -0
  37. package/include/numkong/cast/haswell.h +975 -0
  38. package/include/numkong/cast/icelake.h +470 -0
  39. package/include/numkong/cast/neon.h +1192 -0
  40. package/include/numkong/cast/rvv.h +1021 -0
  41. package/include/numkong/cast/sapphire.h +262 -0
  42. package/include/numkong/cast/serial.h +2262 -0
  43. package/include/numkong/cast/skylake.h +856 -0
  44. package/include/numkong/cast/v128relaxed.h +180 -0
  45. package/include/numkong/cast.h +230 -0
  46. package/include/numkong/curved/README.md +223 -0
  47. package/include/numkong/curved/genoa.h +182 -0
  48. package/include/numkong/curved/haswell.h +276 -0
  49. package/include/numkong/curved/neon.h +205 -0
  50. package/include/numkong/curved/neonbfdot.h +212 -0
  51. package/include/numkong/curved/neonhalf.h +212 -0
  52. package/include/numkong/curved/rvv.h +305 -0
  53. package/include/numkong/curved/serial.h +207 -0
  54. package/include/numkong/curved/skylake.h +457 -0
  55. package/include/numkong/curved/smef64.h +506 -0
  56. package/include/numkong/curved.h +517 -0
  57. package/include/numkong/curved.hpp +144 -0
  58. package/include/numkong/dot/README.md +425 -0
  59. package/include/numkong/dot/alder.h +563 -0
  60. package/include/numkong/dot/genoa.h +315 -0
  61. package/include/numkong/dot/haswell.h +1688 -0
  62. package/include/numkong/dot/icelake.h +883 -0
  63. package/include/numkong/dot/neon.h +818 -0
  64. package/include/numkong/dot/neonbfdot.h +244 -0
  65. package/include/numkong/dot/neonfhm.h +360 -0
  66. package/include/numkong/dot/neonhalf.h +198 -0
  67. package/include/numkong/dot/neonsdot.h +508 -0
  68. package/include/numkong/dot/rvv.h +714 -0
  69. package/include/numkong/dot/rvvbb.h +72 -0
  70. package/include/numkong/dot/rvvbf16.h +123 -0
  71. package/include/numkong/dot/rvvhalf.h +129 -0
  72. package/include/numkong/dot/sapphire.h +141 -0
  73. package/include/numkong/dot/serial.h +838 -0
  74. package/include/numkong/dot/sierra.h +405 -0
  75. package/include/numkong/dot/skylake.h +1084 -0
  76. package/include/numkong/dot/sve.h +379 -0
  77. package/include/numkong/dot/svebfdot.h +74 -0
  78. package/include/numkong/dot/svehalf.h +123 -0
  79. package/include/numkong/dot/v128relaxed.h +1258 -0
  80. package/include/numkong/dot.h +1070 -0
  81. package/include/numkong/dot.hpp +94 -0
  82. package/include/numkong/dots/README.md +496 -0
  83. package/include/numkong/dots/alder.h +114 -0
  84. package/include/numkong/dots/genoa.h +94 -0
  85. package/include/numkong/dots/haswell.h +295 -0
  86. package/include/numkong/dots/icelake.h +171 -0
  87. package/include/numkong/dots/neon.h +120 -0
  88. package/include/numkong/dots/neonbfdot.h +58 -0
  89. package/include/numkong/dots/neonfhm.h +94 -0
  90. package/include/numkong/dots/neonhalf.h +57 -0
  91. package/include/numkong/dots/neonsdot.h +108 -0
  92. package/include/numkong/dots/rvv.h +2486 -0
  93. package/include/numkong/dots/sapphireamx.h +3973 -0
  94. package/include/numkong/dots/serial.h +2844 -0
  95. package/include/numkong/dots/sierra.h +97 -0
  96. package/include/numkong/dots/skylake.h +196 -0
  97. package/include/numkong/dots/sme.h +5372 -0
  98. package/include/numkong/dots/smebi32.h +461 -0
  99. package/include/numkong/dots/smef64.h +1318 -0
  100. package/include/numkong/dots/smehalf.h +47 -0
  101. package/include/numkong/dots/v128relaxed.h +294 -0
  102. package/include/numkong/dots.h +2804 -0
  103. package/include/numkong/dots.hpp +639 -0
  104. package/include/numkong/each/README.md +469 -0
  105. package/include/numkong/each/haswell.h +1658 -0
  106. package/include/numkong/each/icelake.h +272 -0
  107. package/include/numkong/each/neon.h +1104 -0
  108. package/include/numkong/each/neonbfdot.h +212 -0
  109. package/include/numkong/each/neonhalf.h +410 -0
  110. package/include/numkong/each/rvv.h +1121 -0
  111. package/include/numkong/each/sapphire.h +477 -0
  112. package/include/numkong/each/serial.h +260 -0
  113. package/include/numkong/each/skylake.h +1562 -0
  114. package/include/numkong/each.h +2146 -0
  115. package/include/numkong/each.hpp +434 -0
  116. package/include/numkong/geospatial/README.md +147 -0
  117. package/include/numkong/geospatial/haswell.h +593 -0
  118. package/include/numkong/geospatial/neon.h +571 -0
  119. package/include/numkong/geospatial/rvv.h +701 -0
  120. package/include/numkong/geospatial/serial.h +309 -0
  121. package/include/numkong/geospatial/skylake.h +577 -0
  122. package/include/numkong/geospatial/v128relaxed.h +613 -0
  123. package/include/numkong/geospatial.h +453 -0
  124. package/include/numkong/geospatial.hpp +235 -0
  125. package/include/numkong/matrix.hpp +336 -0
  126. package/include/numkong/maxsim/README.md +187 -0
  127. package/include/numkong/maxsim/alder.h +511 -0
  128. package/include/numkong/maxsim/genoa.h +115 -0
  129. package/include/numkong/maxsim/haswell.h +553 -0
  130. package/include/numkong/maxsim/icelake.h +480 -0
  131. package/include/numkong/maxsim/neonsdot.h +394 -0
  132. package/include/numkong/maxsim/sapphireamx.h +877 -0
  133. package/include/numkong/maxsim/serial.h +490 -0
  134. package/include/numkong/maxsim/sme.h +929 -0
  135. package/include/numkong/maxsim/v128relaxed.h +280 -0
  136. package/include/numkong/maxsim.h +571 -0
  137. package/include/numkong/maxsim.hpp +133 -0
  138. package/include/numkong/mesh/README.md +227 -0
  139. package/include/numkong/mesh/haswell.h +2235 -0
  140. package/include/numkong/mesh/neon.h +1329 -0
  141. package/include/numkong/mesh/neonbfdot.h +842 -0
  142. package/include/numkong/mesh/neonhalf.h +616 -0
  143. package/include/numkong/mesh/rvv.h +916 -0
  144. package/include/numkong/mesh/serial.h +742 -0
  145. package/include/numkong/mesh/skylake.h +1135 -0
  146. package/include/numkong/mesh/v128relaxed.h +1052 -0
  147. package/include/numkong/mesh.h +652 -0
  148. package/include/numkong/mesh.hpp +762 -0
  149. package/include/numkong/numkong.h +78 -0
  150. package/include/numkong/numkong.hpp +57 -0
  151. package/include/numkong/probability/README.md +173 -0
  152. package/include/numkong/probability/haswell.h +267 -0
  153. package/include/numkong/probability/neon.h +225 -0
  154. package/include/numkong/probability/rvv.h +409 -0
  155. package/include/numkong/probability/serial.h +169 -0
  156. package/include/numkong/probability/skylake.h +324 -0
  157. package/include/numkong/probability.h +383 -0
  158. package/include/numkong/probability.hpp +120 -0
  159. package/include/numkong/random.h +50 -0
  160. package/include/numkong/random.hpp +285 -0
  161. package/include/numkong/reduce/README.md +547 -0
  162. package/include/numkong/reduce/alder.h +632 -0
  163. package/include/numkong/reduce/genoa.h +201 -0
  164. package/include/numkong/reduce/haswell.h +3783 -0
  165. package/include/numkong/reduce/icelake.h +549 -0
  166. package/include/numkong/reduce/neon.h +3841 -0
  167. package/include/numkong/reduce/neonbfdot.h +353 -0
  168. package/include/numkong/reduce/neonfhm.h +665 -0
  169. package/include/numkong/reduce/neonhalf.h +157 -0
  170. package/include/numkong/reduce/neonsdot.h +357 -0
  171. package/include/numkong/reduce/rvv.h +3407 -0
  172. package/include/numkong/reduce/serial.h +757 -0
  173. package/include/numkong/reduce/sierra.h +338 -0
  174. package/include/numkong/reduce/skylake.h +3792 -0
  175. package/include/numkong/reduce/v128relaxed.h +2302 -0
  176. package/include/numkong/reduce.h +1597 -0
  177. package/include/numkong/reduce.hpp +633 -0
  178. package/include/numkong/scalar/README.md +89 -0
  179. package/include/numkong/scalar/haswell.h +113 -0
  180. package/include/numkong/scalar/neon.h +122 -0
  181. package/include/numkong/scalar/neonhalf.h +70 -0
  182. package/include/numkong/scalar/rvv.h +211 -0
  183. package/include/numkong/scalar/sapphire.h +63 -0
  184. package/include/numkong/scalar/serial.h +332 -0
  185. package/include/numkong/scalar/v128relaxed.h +56 -0
  186. package/include/numkong/scalar.h +683 -0
  187. package/include/numkong/set/README.md +179 -0
  188. package/include/numkong/set/haswell.h +334 -0
  189. package/include/numkong/set/icelake.h +485 -0
  190. package/include/numkong/set/neon.h +364 -0
  191. package/include/numkong/set/rvv.h +226 -0
  192. package/include/numkong/set/rvvbb.h +117 -0
  193. package/include/numkong/set/serial.h +174 -0
  194. package/include/numkong/set/sve.h +185 -0
  195. package/include/numkong/set/v128relaxed.h +240 -0
  196. package/include/numkong/set.h +457 -0
  197. package/include/numkong/set.hpp +114 -0
  198. package/include/numkong/sets/README.md +149 -0
  199. package/include/numkong/sets/haswell.h +63 -0
  200. package/include/numkong/sets/icelake.h +66 -0
  201. package/include/numkong/sets/neon.h +61 -0
  202. package/include/numkong/sets/serial.h +43 -0
  203. package/include/numkong/sets/smebi32.h +1099 -0
  204. package/include/numkong/sets/v128relaxed.h +58 -0
  205. package/include/numkong/sets.h +339 -0
  206. package/include/numkong/sparse/README.md +156 -0
  207. package/include/numkong/sparse/icelake.h +463 -0
  208. package/include/numkong/sparse/neon.h +288 -0
  209. package/include/numkong/sparse/serial.h +117 -0
  210. package/include/numkong/sparse/sve2.h +507 -0
  211. package/include/numkong/sparse/turin.h +322 -0
  212. package/include/numkong/sparse.h +363 -0
  213. package/include/numkong/sparse.hpp +113 -0
  214. package/include/numkong/spatial/README.md +435 -0
  215. package/include/numkong/spatial/alder.h +607 -0
  216. package/include/numkong/spatial/genoa.h +290 -0
  217. package/include/numkong/spatial/haswell.h +960 -0
  218. package/include/numkong/spatial/icelake.h +586 -0
  219. package/include/numkong/spatial/neon.h +773 -0
  220. package/include/numkong/spatial/neonbfdot.h +165 -0
  221. package/include/numkong/spatial/neonhalf.h +118 -0
  222. package/include/numkong/spatial/neonsdot.h +261 -0
  223. package/include/numkong/spatial/rvv.h +984 -0
  224. package/include/numkong/spatial/rvvbf16.h +123 -0
  225. package/include/numkong/spatial/rvvhalf.h +117 -0
  226. package/include/numkong/spatial/sapphire.h +343 -0
  227. package/include/numkong/spatial/serial.h +346 -0
  228. package/include/numkong/spatial/sierra.h +323 -0
  229. package/include/numkong/spatial/skylake.h +606 -0
  230. package/include/numkong/spatial/sve.h +224 -0
  231. package/include/numkong/spatial/svebfdot.h +122 -0
  232. package/include/numkong/spatial/svehalf.h +109 -0
  233. package/include/numkong/spatial/v128relaxed.h +717 -0
  234. package/include/numkong/spatial.h +1425 -0
  235. package/include/numkong/spatial.hpp +183 -0
  236. package/include/numkong/spatials/README.md +580 -0
  237. package/include/numkong/spatials/alder.h +94 -0
  238. package/include/numkong/spatials/genoa.h +94 -0
  239. package/include/numkong/spatials/haswell.h +219 -0
  240. package/include/numkong/spatials/icelake.h +113 -0
  241. package/include/numkong/spatials/neon.h +109 -0
  242. package/include/numkong/spatials/neonbfdot.h +60 -0
  243. package/include/numkong/spatials/neonfhm.h +92 -0
  244. package/include/numkong/spatials/neonhalf.h +58 -0
  245. package/include/numkong/spatials/neonsdot.h +109 -0
  246. package/include/numkong/spatials/rvv.h +1960 -0
  247. package/include/numkong/spatials/sapphireamx.h +1149 -0
  248. package/include/numkong/spatials/serial.h +226 -0
  249. package/include/numkong/spatials/sierra.h +96 -0
  250. package/include/numkong/spatials/skylake.h +184 -0
  251. package/include/numkong/spatials/sme.h +1901 -0
  252. package/include/numkong/spatials/smef64.h +465 -0
  253. package/include/numkong/spatials/v128relaxed.h +240 -0
  254. package/include/numkong/spatials.h +3021 -0
  255. package/include/numkong/spatials.hpp +508 -0
  256. package/include/numkong/tensor.hpp +1592 -0
  257. package/include/numkong/trigonometry/README.md +184 -0
  258. package/include/numkong/trigonometry/haswell.h +652 -0
  259. package/include/numkong/trigonometry/neon.h +639 -0
  260. package/include/numkong/trigonometry/rvv.h +699 -0
  261. package/include/numkong/trigonometry/serial.h +703 -0
  262. package/include/numkong/trigonometry/skylake.h +721 -0
  263. package/include/numkong/trigonometry/v128relaxed.h +666 -0
  264. package/include/numkong/trigonometry.h +467 -0
  265. package/include/numkong/trigonometry.hpp +166 -0
  266. package/include/numkong/types.h +1384 -0
  267. package/include/numkong/types.hpp +5603 -0
  268. package/include/numkong/vector.hpp +698 -0
  269. package/javascript/README.md +246 -0
  270. package/javascript/dist/cjs/numkong-wasm.d.ts +166 -0
  271. package/javascript/dist/cjs/numkong-wasm.js +617 -0
  272. package/javascript/dist/cjs/numkong.d.ts +343 -0
  273. package/javascript/dist/cjs/numkong.js +523 -0
  274. package/javascript/dist/cjs/package.json +3 -0
  275. package/javascript/dist/cjs/types.d.ts +284 -0
  276. package/javascript/dist/cjs/types.js +653 -0
  277. package/javascript/dist/esm/numkong-wasm.d.ts +166 -0
  278. package/javascript/dist/esm/numkong-wasm.js +595 -0
  279. package/javascript/dist/esm/numkong.d.ts +343 -0
  280. package/javascript/dist/esm/numkong.js +452 -0
  281. package/javascript/dist/esm/package.json +3 -0
  282. package/javascript/dist/esm/types.d.ts +284 -0
  283. package/javascript/dist/esm/types.js +630 -0
  284. package/javascript/dist-package-cjs.json +3 -0
  285. package/javascript/dist-package-esm.json +3 -0
  286. package/javascript/node-gyp-build.d.ts +1 -0
  287. package/javascript/numkong-wasm.ts +756 -0
  288. package/javascript/numkong.c +689 -0
  289. package/javascript/numkong.ts +575 -0
  290. package/javascript/tsconfig-base.json +39 -0
  291. package/javascript/tsconfig-cjs.json +8 -0
  292. package/javascript/tsconfig-esm.json +8 -0
  293. package/javascript/types.ts +674 -0
  294. package/package.json +87 -0
@@ -0,0 +1,698 @@
1
+ /**
2
+ * @brief NumKong Vector types for C++23 and newer.
3
+ * @file include/numkong/vector.hpp
4
+ * @author Ash Vardanian
5
+ * @date January 7, 2026
6
+ *
7
+ * Provides owning and non-owning vector types with signed indexing,
8
+ * strided views, and sub-byte element support.
9
+ *
10
+ * - `nk::vector<T, A>`: Owning, non-resizable, SIMD-aligned
11
+ * - `nk::vector_view<T>`: Non-owning, const, strided
12
+ * - `nk::vector_span<T>`: Non-owning, mutable, strided
13
+ *
14
+ * @section vector_terminology Terminology: Dimensions vs Values
15
+ *
16
+ * The `nk::vector<value_type_>` container uses two distinct counts:
17
+ *
18
+ * - `size()`: Number of logical dimensions (what kernels see).
19
+ * For `vector<i4x2_t>` with 100 dimensions, you have 100 nibbles.
20
+ *
21
+ * - `size_values()`: Number of C++ container elements (`value_type_` instances).
22
+ * For `vector<i4x2_t>` with 100 dimensions, you have 50 values (2 dims/value).
23
+ *
24
+ * @code
25
+ * auto v = nk::vector<float>::try_zeros(5);
26
+ * v.size(); // 5
27
+ * v[-1]; // last element (signed indexing)
28
+ * v[nk::range(0,3)]; // view of first 3 elements
29
+ * @endcode
30
+ *
31
+ * See `types.hpp` for the full terminology reference.
32
+ */
33
+
34
+ #ifndef NK_VECTOR_HPP
35
+ #define NK_VECTOR_HPP
36
+
37
+ #include <concepts> // `std::integral`
38
+ #include <cstdlib> // `std::aligned_alloc`, `std::free`
39
+ #include <cstring> // `std::memset`
40
+ #include <iterator> // `std::random_access_iterator_tag`
41
+ #include <memory> // `std::allocator_traits`
42
+ #include <type_traits> // `std::conditional_t`
43
+ #include <utility> // `std::exchange`, `std::swap`
44
+
45
+ #include "types.hpp"
46
+
47
+ namespace ashvardanian::numkong {
48
+
49
+ #pragma region - Aligned Allocator
50
+
51
+ /**
52
+ * @brief Cache-aligned allocator with non-throwing allocation.
53
+ * @tparam value_type_ Value type to allocate.
54
+ * @tparam alignment_ Alignment in bytes (default: 64 for cache line).
55
+ *
56
+ * This allocator uses `std::aligned_alloc` and returns `nullptr` on failure
57
+ * instead of throwing. It is stateless and always compares equal.
58
+ */
59
+ template <typename value_type_, std::size_t alignment_ = 64>
60
+ struct aligned_allocator {
61
+ using value_type = value_type_;
62
+ using size_type = std::size_t;
63
+ using difference_type = std::ptrdiff_t;
64
+ using propagate_on_container_move_assignment = std::true_type;
65
+ using is_always_equal = std::true_type;
66
+
67
+ template <typename other_type_>
68
+ struct rebind {
69
+ using other = aligned_allocator<other_type_, alignment_>;
70
+ };
71
+
72
+ static constexpr std::size_t alignment = alignment_;
73
+
74
+ constexpr aligned_allocator() noexcept = default;
75
+
76
+ template <typename other_type_>
77
+ constexpr aligned_allocator(aligned_allocator<other_type_, alignment_> const &) noexcept {}
78
+
79
+ [[nodiscard]] value_type *allocate(std::size_t n) noexcept {
80
+ if (n == 0) return nullptr;
81
+ std::size_t bytes = n * sizeof(value_type);
82
+ // Round up to alignment boundary (required by aligned_alloc)
83
+ std::size_t aligned_bytes = ((bytes + alignment_ - 1) / alignment_) * alignment_;
84
+ #if defined(_MSC_VER)
85
+ return static_cast<value_type *>(::_aligned_malloc(aligned_bytes, alignment_));
86
+ #else
87
+ return static_cast<value_type *>(std::aligned_alloc(alignment_, aligned_bytes));
88
+ #endif
89
+ }
90
+
91
+ void deallocate(value_type *p, std::size_t) noexcept {
92
+ #if defined(_MSC_VER)
93
+ if (p) ::_aligned_free(p);
94
+ #else
95
+ if (p) std::free(p);
96
+ #endif
97
+ }
98
+
99
+ template <typename other_type_>
100
+ constexpr bool operator==(aligned_allocator<other_type_, alignment_> const &) const noexcept {
101
+ return true;
102
+ }
103
+ };
104
+
105
+ #pragma endregion - Aligned Allocator
106
+
107
+ #pragma region - Slicing Infrastructure
108
+
109
+ /** @brief Tag type for selecting all elements along a dimension. */
110
+ struct all_t {};
111
+
112
+ /** @brief Global instance of `all_t` for use in slicing expressions. */
113
+ inline constexpr all_t all {};
114
+
115
+ /** @brief Slicing descriptor: [start, stop) with optional step.
116
+ * `step` must be non-zero. Negative start/stop indices wrap from the end. */
117
+ struct range {
118
+ std::ptrdiff_t start, stop, step;
119
+ template <std::integral start_type_, std::integral stop_type_, std::integral step_type_ = int>
120
+ constexpr range(start_type_ start, stop_type_ stop, step_type_ step = 1) noexcept
121
+ : start(static_cast<std::ptrdiff_t>(start)), stop(static_cast<std::ptrdiff_t>(stop)),
122
+ step(static_cast<std::ptrdiff_t>(step)) {}
123
+ };
124
+
125
+ /** @brief Resolve an integral index to an unsigned offset. Negative wraps from end. */
126
+ template <std::integral index_type_>
127
+ constexpr std::size_t resolve_index_(index_type_ idx, std::size_t extent) noexcept {
128
+ if constexpr (std::signed_integral<index_type_>)
129
+ return static_cast<std::size_t>(idx >= 0 ? idx : static_cast<std::ptrdiff_t>(extent) + idx);
130
+ else return static_cast<std::size_t>(idx);
131
+ }
132
+
133
+ /** @brief Normalize any integral stride input to the signed internal representation. */
134
+ template <std::integral stride_type_>
135
+ constexpr std::ptrdiff_t resolve_stride_(stride_type_ stride) noexcept {
136
+ return static_cast<std::ptrdiff_t>(stride);
137
+ }
138
+
139
+ /** @brief Normalize any unsigned extent input to the internal representation. */
140
+ template <std::unsigned_integral extent_type_>
141
+ constexpr std::size_t resolve_extent_(extent_type_ extent) noexcept {
142
+ return static_cast<std::size_t>(extent);
143
+ }
144
+
145
+ /** @brief Resolve range start/stop against an extent (handles negatives). */
146
+ constexpr void resolve_range_(range const &r, std::size_t extent, //
147
+ std::size_t &out_start, std::size_t &out_stop) noexcept {
148
+ out_start = resolve_index_(r.start, extent);
149
+ out_stop = resolve_index_(r.stop, extent);
150
+ }
151
+
152
+ /** @brief Number of elements in a resolved range with the given step. */
153
+ constexpr std::size_t range_extent_(std::size_t start, std::size_t stop, std::ptrdiff_t step) noexcept {
154
+ if (step > 0)
155
+ return start < stop ? (stop - start + static_cast<std::size_t>(step) - 1) / static_cast<std::size_t>(step) : 0;
156
+ else {
157
+ auto abs_step = static_cast<std::size_t>(-step);
158
+ return start > stop ? (start - stop + abs_step - 1) / abs_step : 0;
159
+ }
160
+ }
161
+
162
+ #pragma endregion - Slicing Infrastructure
163
+
164
+ #pragma region - Forward Declarations
165
+
166
+ template <typename value_type_>
167
+ struct vector_view;
168
+ template <typename value_type_>
169
+ struct vector_span;
170
+
171
+ #pragma endregion - Forward Declarations
172
+
173
+ #pragma region - Dim Iterator
174
+
175
+ template <typename value_type_, typename allocator_type_>
176
+ struct vector;
177
+
178
+ /**
179
+ * @brief Random-access iterator over logical dimensions.
180
+ *
181
+ * For sub-byte types (i4x2_t, u1x8_t), dereference returns a proxy reference.
182
+ * For normal types, dereference returns a direct reference.
183
+ */
184
+ template <typename container_type_>
185
+ class dim_iterator {
186
+ static constexpr bool is_const_ = std::is_const<container_type_>::value;
187
+ using container_t = typename std::remove_reference<container_type_>::type;
188
+ using container_ptr_t = std::conditional_t<is_const_, container_t const *, container_t *>;
189
+
190
+ container_ptr_t container_;
191
+ std::size_t index_;
192
+
193
+ public:
194
+ using container_type = container_type_;
195
+ using iterator_category = std::random_access_iterator_tag;
196
+ using difference_type = std::ptrdiff_t;
197
+ using size_type = std::size_t;
198
+
199
+ constexpr dim_iterator() noexcept : container_(nullptr), index_(0) {}
200
+ constexpr dim_iterator(container_type &c, size_type i) noexcept : container_(&c), index_(i) {}
201
+
202
+ constexpr decltype(auto) operator*() const noexcept { return (*container_)[index_]; }
203
+
204
+ constexpr auto operator->() const noexcept { return &(*container_)[index_]; }
205
+
206
+ constexpr decltype(auto) operator[](difference_type n) const noexcept {
207
+ return (*container_)[static_cast<difference_type>(index_) + n];
208
+ }
209
+
210
+ constexpr dim_iterator &operator++() noexcept {
211
+ ++index_;
212
+ return *this;
213
+ }
214
+ constexpr dim_iterator operator++(int) noexcept {
215
+ auto tmp = *this;
216
+ ++index_;
217
+ return tmp;
218
+ }
219
+ constexpr dim_iterator &operator--() noexcept {
220
+ --index_;
221
+ return *this;
222
+ }
223
+ constexpr dim_iterator operator--(int) noexcept {
224
+ auto tmp = *this;
225
+ --index_;
226
+ return tmp;
227
+ }
228
+
229
+ constexpr dim_iterator &operator+=(difference_type n) noexcept {
230
+ index_ += n;
231
+ return *this;
232
+ }
233
+ constexpr dim_iterator &operator-=(difference_type n) noexcept {
234
+ index_ -= n;
235
+ return *this;
236
+ }
237
+ constexpr dim_iterator operator+(difference_type n) const noexcept {
238
+ return {*container_, index_ + static_cast<size_type>(n)};
239
+ }
240
+ constexpr dim_iterator operator-(difference_type n) const noexcept {
241
+ return {*container_, index_ - static_cast<size_type>(n)};
242
+ }
243
+ constexpr difference_type operator-(dim_iterator const &other) const noexcept {
244
+ return static_cast<difference_type>(index_) - static_cast<difference_type>(other.index_);
245
+ }
246
+
247
+ constexpr bool operator==(dim_iterator const &other) const noexcept { return index_ == other.index_; }
248
+ constexpr bool operator!=(dim_iterator const &other) const noexcept { return index_ != other.index_; }
249
+ constexpr bool operator<(dim_iterator const &other) const noexcept { return index_ < other.index_; }
250
+ constexpr bool operator<=(dim_iterator const &other) const noexcept { return index_ <= other.index_; }
251
+ constexpr bool operator>(dim_iterator const &other) const noexcept { return index_ > other.index_; }
252
+ constexpr bool operator>=(dim_iterator const &other) const noexcept { return index_ >= other.index_; }
253
+
254
+ friend constexpr dim_iterator operator+(difference_type n, dim_iterator const &it) noexcept { return it + n; }
255
+ };
256
+
257
+ #pragma endregion - Dim Iterator
258
+
259
+ #pragma region - Vector View
260
+
261
+ /**
262
+ * @brief Non-owning, immutable, strided view into a vector.
263
+ * @tparam value_type_ Element type.
264
+ *
265
+ * Supports signed indexing (`v[-1]` = last element) and strided access.
266
+ * For sub-byte types, only contiguous views are meaningful.
267
+ */
268
+ template <typename value_type_>
269
+ struct vector_view {
270
+ using value_type = value_type_;
271
+ using size_type = std::size_t;
272
+ using difference_type = std::ptrdiff_t;
273
+
274
+ private:
275
+ char const *data_ = nullptr;
276
+ size_type dimensions_ = 0;
277
+ difference_type stride_bytes_ = 0;
278
+
279
+ public:
280
+ constexpr vector_view() noexcept = default;
281
+
282
+ template <std::unsigned_integral dims_type_, std::integral stride_type_>
283
+ constexpr vector_view(char const *data, dims_type_ dims, stride_type_ stride_bytes) noexcept
284
+ : data_(data), dimensions_(resolve_extent_(dims)), stride_bytes_(resolve_stride_(stride_bytes)) {}
285
+
286
+ /** @brief Construct from contiguous typed pointer. */
287
+ template <std::unsigned_integral dims_type_>
288
+ constexpr vector_view(value_type const *data, dims_type_ dims) noexcept
289
+ : data_(reinterpret_cast<char const *>(data)), dimensions_(resolve_extent_(dims)),
290
+ stride_bytes_(static_cast<difference_type>(sizeof(value_type))) {}
291
+
292
+ /** @brief Number of logical dimensions. */
293
+ constexpr size_type size() const noexcept { return dimensions_; }
294
+
295
+ /** @brief Check if empty. */
296
+ constexpr bool empty() const noexcept { return dimensions_ == 0; }
297
+
298
+ /** @brief Stride in bytes between consecutive elements. */
299
+ constexpr difference_type stride_bytes() const noexcept { return stride_bytes_; }
300
+
301
+ /** @brief True if elements are stored contiguously. */
302
+ constexpr bool is_contiguous() const noexcept {
303
+ return stride_bytes_ == static_cast<difference_type>(sizeof(value_type));
304
+ }
305
+
306
+ /** @brief Raw byte pointer to the first element. */
307
+ constexpr char const *byte_data() const noexcept { return data_; }
308
+
309
+ /** @brief Typed pointer (only valid if contiguous). */
310
+ constexpr value_type const *data() const noexcept { return reinterpret_cast<value_type const *>(data_); }
311
+
312
+ /** @brief Integral indexing: signed negatives wrap from end. */
313
+ template <std::integral index_type_>
314
+ decltype(auto) operator[](index_type_ idx) const noexcept {
315
+ auto i = resolve_index_(idx, dimensions_);
316
+ if constexpr (dimensions_per_value<value_type>() > 1) {
317
+ constexpr auto dims_per_value = dimensions_per_value<value_type>();
318
+ auto value_index = i / dims_per_value;
319
+ auto sub_index = i % dims_per_value;
320
+ using raw_type = typename raw_pod_type<value_type>::type;
321
+ auto *base = const_cast<raw_type *>(
322
+ reinterpret_cast<raw_type const *>(data_ + static_cast<difference_type>(value_index) * stride_bytes_));
323
+ return sub_byte_ref<value_type>(base, sub_index).get();
324
+ }
325
+ else { return *reinterpret_cast<value_type const *>(data_ + static_cast<difference_type>(i) * stride_bytes_); }
326
+ }
327
+
328
+ /** @brief Sub-slice via range. */
329
+ vector_view operator[](range r) const noexcept {
330
+ size_type start, stop;
331
+ resolve_range_(r, dimensions_, start, stop);
332
+ auto count = range_extent_(start, stop, r.step);
333
+ return {data_ + static_cast<difference_type>(start) * stride_bytes_, count, stride_bytes_ * r.step};
334
+ }
335
+
336
+ /** @brief Select all elements (identity). */
337
+ vector_view operator[](all_t) const noexcept { return *this; }
338
+
339
+ /** @brief Create a reversed view by negating the stride and pointing to the last element.
340
+ * Iterating the returned view visits elements in reverse order. */
341
+ constexpr vector_view rev() const noexcept {
342
+ if (dimensions_ == 0) return *this;
343
+ return {data_ + static_cast<difference_type>(dimensions_ - 1) * stride_bytes_, dimensions_, -stride_bytes_};
344
+ }
345
+ };
346
+
347
+ #pragma endregion - Vector View
348
+
349
+ #pragma region - Vector Span
350
+
351
+ /**
352
+ * @brief Non-owning, mutable, strided view into a vector.
353
+ * @tparam value_type_ Element type.
354
+ *
355
+ * Same as `vector_view` but allows mutation. Implicitly converts to `vector_view`.
356
+ */
357
+ template <typename value_type_>
358
+ struct vector_span {
359
+ using value_type = value_type_;
360
+ using size_type = std::size_t;
361
+ using difference_type = std::ptrdiff_t;
362
+
363
+ private:
364
+ char *data_ = nullptr;
365
+ size_type dimensions_ = 0;
366
+ difference_type stride_bytes_ = 0;
367
+
368
+ public:
369
+ constexpr vector_span() noexcept = default;
370
+
371
+ template <std::unsigned_integral dims_type_, std::integral stride_type_>
372
+ constexpr vector_span(char *data, dims_type_ dims, stride_type_ stride_bytes) noexcept
373
+ : data_(data), dimensions_(resolve_extent_(dims)), stride_bytes_(resolve_stride_(stride_bytes)) {}
374
+
375
+ /** @brief Construct from contiguous typed pointer. */
376
+ template <std::unsigned_integral dims_type_>
377
+ constexpr vector_span(value_type *data, dims_type_ dims) noexcept
378
+ : data_(reinterpret_cast<char *>(data)), dimensions_(resolve_extent_(dims)),
379
+ stride_bytes_(static_cast<difference_type>(sizeof(value_type))) {}
380
+
381
+ /** @brief Number of logical dimensions. */
382
+ constexpr size_type size() const noexcept { return dimensions_; }
383
+
384
+ /** @brief Check if empty. */
385
+ constexpr bool empty() const noexcept { return dimensions_ == 0; }
386
+
387
+ /** @brief Stride in bytes. */
388
+ constexpr difference_type stride_bytes() const noexcept { return stride_bytes_; }
389
+
390
+ /** @brief True if contiguous. */
391
+ constexpr bool is_contiguous() const noexcept {
392
+ return stride_bytes_ == static_cast<difference_type>(sizeof(value_type));
393
+ }
394
+
395
+ /** @brief Raw byte pointer. */
396
+ constexpr char *byte_data() noexcept { return data_; }
397
+ constexpr char const *byte_data() const noexcept { return data_; }
398
+
399
+ /** @brief Typed pointer (only valid if contiguous). */
400
+ constexpr value_type *data() noexcept { return reinterpret_cast<value_type *>(data_); }
401
+ constexpr value_type const *data() const noexcept { return reinterpret_cast<value_type const *>(data_); }
402
+
403
+ /** @brief Implicit conversion to const view. */
404
+ constexpr operator vector_view<value_type>() const noexcept {
405
+ return {static_cast<char const *>(data_), dimensions_, stride_bytes_};
406
+ }
407
+
408
+ /** @brief Mutable integral indexing. Signed negatives wrap from end. */
409
+ template <std::integral index_type_>
410
+ decltype(auto) operator[](index_type_ idx) noexcept {
411
+ auto i = resolve_index_(idx, dimensions_);
412
+ if constexpr (dimensions_per_value<value_type>() > 1) {
413
+ constexpr auto dims_per_value = dimensions_per_value<value_type>();
414
+ auto value_index = i / dims_per_value;
415
+ auto sub_index = i % dims_per_value;
416
+ using raw_type = typename raw_pod_type<value_type>::type;
417
+ auto *base = reinterpret_cast<raw_type *>(data_ +
418
+ static_cast<difference_type>(value_index) * stride_bytes_);
419
+ return sub_byte_ref<value_type>(base, sub_index);
420
+ }
421
+ else { return *reinterpret_cast<value_type *>(data_ + static_cast<difference_type>(i) * stride_bytes_); }
422
+ }
423
+
424
+ /** @brief Const integral indexing. Signed negatives wrap from end. */
425
+ template <std::integral index_type_>
426
+ decltype(auto) operator[](index_type_ idx) const noexcept {
427
+ return static_cast<vector_view<value_type>>(*this)[idx];
428
+ }
429
+
430
+ /** @brief Sub-slice via range. */
431
+ vector_span operator[](range r) noexcept {
432
+ size_type start, stop;
433
+ resolve_range_(r, dimensions_, start, stop);
434
+ auto count = range_extent_(start, stop, r.step);
435
+ return {data_ + static_cast<difference_type>(start) * stride_bytes_, count, stride_bytes_ * r.step};
436
+ }
437
+
438
+ /** @brief Const sub-slice via range. */
439
+ vector_view<value_type> operator[](range r) const noexcept {
440
+ return static_cast<vector_view<value_type>>(*this)[r];
441
+ }
442
+
443
+ /** @brief Select all elements. */
444
+ vector_span operator[](all_t) noexcept { return *this; }
445
+ };
446
+
447
+ #pragma endregion - Vector Span
448
+
449
+ #pragma region - Vector
450
+
451
+ /**
452
+ * @brief Owning, non-resizable, SIMD-aligned vector.
453
+ *
454
+ * Size is fixed at construction. Use `try_zeros()` factory for
455
+ * non-throwing construction, or `from_raw()` to adopt existing memory.
456
+ *
457
+ * Supports signed indexing (`v[-1]`), sub-byte types via proxy references,
458
+ * and slicing via `operator[](range)`.
459
+ *
460
+ * @tparam value_type_ Element type.
461
+ * @tparam allocator_type_ Allocator (default: aligned_allocator).
462
+ */
463
+ template <typename value_type_, typename allocator_type_ = aligned_allocator<value_type_>>
464
+ struct vector {
465
+ using value_type = value_type_;
466
+ using raw_value_type = typename raw_pod_type<value_type>::type;
467
+
468
+ using allocator_type = allocator_type_;
469
+ using alloc_traits = std::allocator_traits<allocator_type_>;
470
+ using size_type = std::size_t;
471
+ using difference_type = std::ptrdiff_t;
472
+ using pointer = value_type_ *;
473
+ using const_pointer = value_type_ const *;
474
+
475
+ using iterator = dim_iterator<vector>;
476
+ using const_iterator = dim_iterator<vector const>;
477
+
478
+ private:
479
+ pointer data_ = nullptr;
480
+ size_type dimensions_ = 0;
481
+ [[no_unique_address]] allocator_type_ alloc_;
482
+
483
+ /** @brief Convert dimension count to value count. */
484
+ static constexpr size_type dims_to_values(size_type dims) noexcept {
485
+ return divide_round_up(dims, dimensions_per_value<value_type>());
486
+ }
487
+
488
+ public:
489
+ /** @brief Default constructor — empty vector with default allocator. */
490
+ vector() noexcept = default;
491
+
492
+ /** @brief Construct with custom allocator. */
493
+ explicit vector(allocator_type_ const &alloc) noexcept : alloc_(alloc) {}
494
+
495
+ /** @brief Destructor — deallocates memory. */
496
+ ~vector() noexcept {
497
+ if (data_) alloc_traits::deallocate(alloc_, data_, dims_to_values(dimensions_));
498
+ }
499
+
500
+ /** @brief Move constructor. */
501
+ vector(vector &&other) noexcept
502
+ : data_(std::exchange(other.data_, nullptr)), dimensions_(std::exchange(other.dimensions_, 0)),
503
+ alloc_(std::move(other.alloc_)) {}
504
+
505
+ /** @brief Move assignment with allocator propagation. */
506
+ vector &operator=(vector &&other) noexcept {
507
+ if (this != &other) {
508
+ if (data_) alloc_traits::deallocate(alloc_, data_, dims_to_values(dimensions_));
509
+ if constexpr (alloc_traits::propagate_on_container_move_assignment::value) alloc_ = std::move(other.alloc_);
510
+ data_ = std::exchange(other.data_, nullptr);
511
+ dimensions_ = std::exchange(other.dimensions_, 0);
512
+ }
513
+ return *this;
514
+ }
515
+
516
+ vector(vector const &) = delete;
517
+ vector &operator=(vector const &) = delete;
518
+
519
+ /**
520
+ * @brief Factory: allocate a zero-initialized vector with `dims` dimensions.
521
+ * @return Non-empty vector on success, empty vector on allocation failure.
522
+ */
523
+ [[nodiscard]] static vector try_zeros(size_type dims, allocator_type_ alloc = {}) noexcept {
524
+ vector v(alloc);
525
+ size_type values = dims_to_values(dims);
526
+ if (values == 0) return v;
527
+ pointer ptr = alloc_traits::allocate(v.alloc_, values);
528
+ if (!ptr) return v;
529
+ if constexpr (is_memset_zero_safe_v<value_type_>) std::memset(ptr, 0, values * sizeof(value_type_));
530
+ else
531
+ for (size_type i = 0; i < values; ++i) ptr[i] = value_type_ {};
532
+ v.data_ = ptr;
533
+ v.dimensions_ = dims;
534
+ return v;
535
+ }
536
+
537
+ /**
538
+ * @brief Factory: allocate a vector filled with ones.
539
+ * @return Non-empty vector on success, empty vector on allocation failure.
540
+ */
541
+ [[nodiscard]] static vector try_ones(size_type dims, allocator_type_ alloc = {}) noexcept {
542
+ return try_full(dims, value_type_ {1}, alloc);
543
+ }
544
+
545
+ /**
546
+ * @brief Factory: allocate a vector filled with `val`.
547
+ * @return Non-empty vector on success, empty vector on allocation failure.
548
+ */
549
+ [[nodiscard]] static vector try_full(size_type dims, value_type_ val, allocator_type_ alloc = {}) noexcept {
550
+ vector v(alloc);
551
+ size_type values = dims_to_values(dims);
552
+ if (values == 0) return v;
553
+ pointer ptr = alloc_traits::allocate(v.alloc_, values);
554
+ if (!ptr) return v;
555
+ for (size_type i = 0; i < values; ++i) ptr[i] = val;
556
+ v.data_ = ptr;
557
+ v.dimensions_ = dims;
558
+ return v;
559
+ }
560
+
561
+ /**
562
+ * @brief Factory: allocate an uninitialized vector.
563
+ * @return Non-empty vector on success, empty vector on allocation failure.
564
+ * @warning Contents are uninitialized. Caller must fill before reading.
565
+ */
566
+ [[nodiscard]] static vector try_empty(size_type dims, allocator_type_ alloc = {}) noexcept {
567
+ vector v(alloc);
568
+ size_type values = dims_to_values(dims);
569
+ if (values == 0) return v;
570
+ pointer ptr = alloc_traits::allocate(v.alloc_, values);
571
+ if (!ptr) return v;
572
+ v.data_ = ptr;
573
+ v.dimensions_ = dims;
574
+ return v;
575
+ }
576
+
577
+ /**
578
+ * @brief Factory: adopt raw memory. Caller transfers ownership.
579
+ * @param ptr Pointer to data (must have been allocated by `alloc`).
580
+ * @param dims Number of logical dimensions.
581
+ * @param alloc Allocator instance.
582
+ */
583
+ [[nodiscard]] static vector from_raw(pointer ptr, size_type dims, allocator_type_ alloc = {}) noexcept {
584
+ vector v(alloc);
585
+ v.data_ = ptr;
586
+ v.dimensions_ = dims;
587
+ return v;
588
+ }
589
+
590
+ /** @brief Swap with another vector. */
591
+ void swap(vector &other) noexcept {
592
+ using std::swap;
593
+ swap(data_, other.data_);
594
+ swap(dimensions_, other.dimensions_);
595
+ if constexpr (alloc_traits::propagate_on_container_swap::value) swap(alloc_, other.alloc_);
596
+ }
597
+
598
+ /** @brief Number of logical dimensions. */
599
+ size_type size() const noexcept { return dimensions_; }
600
+
601
+ /** @brief Check if empty. */
602
+ bool empty() const noexcept { return dimensions_ == 0; }
603
+
604
+ /** @brief Number of storage values. */
605
+ size_type size_values() const noexcept { return dims_to_values(dimensions_); }
606
+
607
+ /** @brief Size in bytes. */
608
+ size_type size_bytes() const noexcept { return dims_to_values(dimensions_) * sizeof(value_type_); }
609
+
610
+ /** @brief Pointer to underlying data. */
611
+ value_type *values_data() noexcept { return data_; }
612
+ value_type const *values_data() const noexcept { return data_; }
613
+
614
+ raw_value_type *raw_values_data() noexcept { return reinterpret_cast<raw_value_type *>(data_); }
615
+ raw_value_type const *raw_values_data() const noexcept { return reinterpret_cast<raw_value_type const *>(data_); }
616
+
617
+ /** @brief Get a copy of the allocator. */
618
+ allocator_type get_allocator() const noexcept { return alloc_; }
619
+
620
+ /**
621
+ * @brief Signed dimension access. Negative indices wrap from end.
622
+ * @retval For sub-byte types, returns proxy reference.
623
+ * @retval For normal types, returns direct reference.
624
+ */
625
+ template <std::integral index_type_>
626
+ decltype(auto) operator[](index_type_ idx) noexcept {
627
+ auto i = resolve_index_(idx, dimensions_);
628
+ if constexpr (dimensions_per_value<value_type>() > 1)
629
+ return sub_byte_ref<value_type>(reinterpret_cast<raw_value_type *>(data_), i);
630
+ else return data_[i];
631
+ }
632
+
633
+ template <std::integral index_type_>
634
+ decltype(auto) operator[](index_type_ idx) const noexcept {
635
+ auto i = resolve_index_(idx, dimensions_);
636
+ if constexpr (dimensions_per_value<value_type>() > 1)
637
+ return sub_byte_ref<value_type>(
638
+ const_cast<raw_value_type *>(reinterpret_cast<raw_value_type const *>(data_)), i)
639
+ .get();
640
+ else return data_[i];
641
+ }
642
+
643
+ /** @brief Slice via range, returns a vector_span. */
644
+ vector_span<value_type> operator[](range r) noexcept {
645
+ size_type start, stop;
646
+ resolve_range_(r, dimensions_, start, stop);
647
+ auto count = range_extent_(start, stop, r.step);
648
+ auto stride = static_cast<difference_type>(sizeof(value_type)) * r.step;
649
+ return {reinterpret_cast<char *>(data_) +
650
+ static_cast<difference_type>(start) * static_cast<difference_type>(sizeof(value_type)),
651
+ count, stride};
652
+ }
653
+
654
+ /** @brief Slice via range (const), returns a vector_view. */
655
+ vector_view<value_type> operator[](range r) const noexcept {
656
+ size_type start, stop;
657
+ resolve_range_(r, dimensions_, start, stop);
658
+ auto count = range_extent_(start, stop, r.step);
659
+ auto stride = static_cast<difference_type>(sizeof(value_type)) * r.step;
660
+ return {reinterpret_cast<char const *>(data_) +
661
+ static_cast<difference_type>(start) * static_cast<difference_type>(sizeof(value_type)),
662
+ count, stride};
663
+ }
664
+
665
+ /** @brief Select all elements as a span. */
666
+ vector_span<value_type> operator[](all_t) noexcept { return span(); }
667
+
668
+ /** @brief Select all elements as a view. */
669
+ vector_view<value_type> operator[](all_t) const noexcept { return view(); }
670
+
671
+ /** @brief Create an immutable view. */
672
+ vector_view<value_type> view() const noexcept { return {data_, dimensions_}; }
673
+
674
+ /** @brief Create a mutable span. */
675
+ vector_span<value_type> span() noexcept { return {data_, dimensions_}; }
676
+
677
+ /** @brief Dimension iterator to beginning. */
678
+ iterator begin() noexcept { return {*this, 0}; }
679
+ const_iterator begin() const noexcept { return {*this, 0}; }
680
+ const_iterator cbegin() const noexcept { return {*this, 0}; }
681
+
682
+ /** @brief Dimension iterator to end. */
683
+ iterator end() noexcept { return {*this, dimensions_}; }
684
+ const_iterator end() const noexcept { return {*this, dimensions_}; }
685
+ const_iterator cend() const noexcept { return {*this, dimensions_}; }
686
+ };
687
+
688
+ /** @brief Non-member swap. */
689
+ template <typename value_type_, typename allocator_type_>
690
+ void swap(vector<value_type_, allocator_type_> &a, vector<value_type_, allocator_type_> &b) noexcept {
691
+ a.swap(b);
692
+ }
693
+
694
+ #pragma endregion - Vector
695
+
696
+ } // namespace ashvardanian::numkong
697
+
698
+ #endif // NK_VECTOR_HPP