42 StrideIterator(T *ptr,
long stride) : m_ptr(ptr), m_stride(stride) {}
44 T &operator*() {
return *m_ptr; }
46 const T &operator*()
const {
return *m_ptr; }
49 return m_ptr == other.m_ptr;
52 return m_ptr < other.m_ptr;
75 m_ptr += n * m_stride;
80 m_ptr -= n * m_stride;
85 auto out_iter = *
this;
90 auto out_iter = *
this;
105 const T &operator*()
const {
return *m_ptr; }
108 return m_ptr == other.m_ptr;
111 return m_ptr < other.m_ptr;
134 m_ptr += n * m_stride;
139 m_ptr -= n * m_stride;
144 auto out_iter = *
this;
145 return out_iter += n;
149 auto out_iter = *
this;
150 return out_iter -= n;
163template <
typename T =
double>
168 std::size_t m_stride;
172 ArrayView(
T *data, std::size_t size, std::size_t stride = 1)
173 : m_size(size), m_stride(stride), m_data(data) {}
175 std::size_t size()
const {
return m_size; }
177 T &operator[](std::size_t
i) {
return m_data[
i * m_stride]; }
179 T operator[](std::size_t
i)
const {
return m_data[
i * m_stride]; }
181 T &at(std::size_t
i) {
183 return m_data[
i * m_stride];
186 T at(std::size_t
i)
const {
188 return m_data[
i * m_stride];
191 T &operator()(std::size_t
i) {
return at(
i); }
192 T operator()(std::size_t
i)
const {
return at(
i); }
194 T &front() {
return at(0); }
195 T front()
const {
return at(0); }
196 T &back() {
return at(m_size - 1); }
197 T back()
const {
return at(m_size - 1); }
199 T *data() {
return m_data; }
206 return StrideIterator(m_data +
long(m_size * m_stride),
long(m_stride));
209 return ConstStrideIterator(m_data +
long(m_size * m_stride),
214 return StrideIterator(m_data +
long(m_size * m_stride) -
long(m_stride),
217 auto crbegin()
const {
218 return ConstStrideIterator(
219 m_data +
long(m_size * m_stride) -
long(m_stride), -
long(m_stride));
223 return StrideIterator(m_data -
long(m_stride), -
long(m_stride));
226 return ConstStrideIterator(m_data -
long(m_stride), -
long(m_stride));
232 for (std::size_t
i = 0;
i < m_size; ++
i) {
233 out.push_back(m_data[
i * m_stride]);
242template <
typename T,
typename... Args>
244 if constexpr (
sizeof...(rest) == 0) {
247 return first *
product(rest...);
251template <std::
size_t N>
252void NDrange_impl(std::vector<std::array<std::size_t, N>> &result,
253 std::array<std::size_t, N> ¤t,
254 const std::array<std::size_t, N> &maxValues,
257 result.push_back(current);
261 for (std::size_t i = 0; i < maxValues[index]; ++i) {
263 NDrange_impl<N>(result, current, maxValues, index + 1);
277template <
typename... Args>
278auto NDrange(std::size_t first, Args... rest) {
279 constexpr std::size_t N =
sizeof...(rest) + 1;
281 const std::array<std::size_t, N> maxValues = {
282 first,
static_cast<std::size_t
>(rest)...};
284 std::vector<std::array<std::size_t, N>> result;
285 result.reserve(
product(first,
static_cast<std::size_t
>(rest)...));
287 std::array<std::size_t, N> current = {0};
289 NDrange_impl<N>(result, current, maxValues, 0);
303template <
typename T =
double>
308 std::vector<std::size_t> m_sizes;
312 std::vector<std::size_t> m_cumulative_sizes;
314 std::size_t m_total_size;
316 std::vector<T> m_data;
324 template <
typename...
Args>
328 template <
typename...
Args>
332 std::size_t
size()
const {
return m_total_size; }
335 std::size_t
size(std::size_t
dim)
const {
return m_sizes.at(
dim); }
341 const std::vector<std::size_t> &
shape()
const {
return m_sizes; }
344 template <
typename...
Args>
348 template <
typename...
Args>
352 template <
typename...
Args>
356 template <
typename...
Args>
361 const T *
data()
const {
return m_data.data(); }
364 const std::vector<T> &
vector()
const {
return m_data; }
379 auto begin() {
return m_data.begin(); }
381 auto cbegin()
const {
return m_data.cbegin(); }
383 auto end() {
return m_data.end(); }
385 auto cend()
const {
return m_data.cend(); }
388 auto rbegin() {
return m_data.rbegin(); }
390 auto crbegin()
const {
return m_data.crbegin(); }
392 auto rend() {
return m_data.rend(); }
394 auto crend()
const {
return m_data.crend(); }
416 std::vector<std::size_t> calc_cumulative_size()
const;
419 template <
typename...
Args>
420 std::size_t unchecked_index(std::size_t
first,
Args...
rest)
const;
423 template <
typename...
Args>
424 std::size_t unchecked_index_impl(std::size_t
dim, std::size_t
first,
428 template <
typename...
Args>
429 std::size_t checked_index(std::size_t
first,
Args...
rest)
const;
432 template <
typename...
Args>
433 std::size_t checked_index_impl(std::size_t
dim, std::size_t
first,
441std::vector<std::size_t> Array<T>::calc_cumulative_size()
const {
442 std::vector<std::size_t> cumulative_size;
443 cumulative_size.reserve(m_sizes.size());
444 for (std::size_t i = 0; i < m_Ndim; ++i) {
445 cumulative_size.push_back(std::accumulate(m_sizes.cbegin() +
long(i) + 1,
447 std::multiplies<std::size_t>()));
449 return cumulative_size;
453template <
typename... Args>
455 : m_sizes({
first,
static_cast<std::size_t
>(
rest)...}),
456 m_Ndim(m_sizes.size()),
457 m_cumulative_sizes(calc_cumulative_size()),
458 m_total_size(std::accumulate(m_sizes.cbegin(), m_sizes.cend(), 1ul,
459 std::multiplies<std::size_t>())),
460 m_data(m_total_size) {}
463template <
typename... Args>
465 m_sizes = std::vector{first,
static_cast<std::size_t
>(rest)...};
466 m_Ndim = m_sizes.size();
467 m_cumulative_sizes = calc_cumulative_size();
468 m_total_size = std::accumulate(m_sizes.cbegin(), m_sizes.cend(), 1ul,
469 std::multiplies<std::size_t>());
470 m_data.resize(m_total_size);
474template <
typename... Args>
476 return unchecked_index_impl(0, first, rest...);
480template <
typename... Args>
481std::size_t Array<T>::unchecked_index_impl(std::size_t dim, std::size_t first,
482 Args... rest)
const {
483 if constexpr (
sizeof...(rest) == 0) {
484 return first * m_cumulative_sizes[dim];
486 return first * m_cumulative_sizes[dim] +
487 unchecked_index_impl(dim + 1, rest...);
492template <
typename... Args>
493std::size_t Array<T>::checked_index(std::size_t first, Args... rest)
const {
494 assert(
sizeof...(rest) + 1 == m_Ndim &&
495 "Number of arguments must match number of dimensions");
496 return checked_index_impl(0, first, rest...);
500template <
typename... Args>
501std::size_t Array<T>::checked_index_impl(std::size_t dim, std::size_t first,
502 Args... rest)
const {
503 assert(first < m_sizes[dim]);
504 if constexpr (
sizeof...(rest) == 0) {
505 return first * m_cumulative_sizes[dim];
507 return first * m_cumulative_sizes[dim] +
508 checked_index_impl(dim + 1, rest...);
513template <
typename... Args>
515 return m_data.at(checked_index(first, rest...));
519template <
typename... Args>
521 return m_data.at(checked_index(first, rest...));
525template <
typename... Args>
527 return m_data[unchecked_index(first, rest...)];
531template <
typename... Args>
533 return m_data[unchecked_index(first, rest...)];
538 assert(m_sizes == other.m_sizes &&
539 "Arithmetic only defined for equal-dimension arrays");
540 for (std::size_t i = 0; i < m_data.size(); ++i) {
541 this->m_data[i] += other.m_data[i];
548 assert(m_sizes == other.m_sizes &&
549 "Arithmetic only defined for equal-dimension arrays");
550 for (std::size_t i = 0; i < m_data.size(); ++i) {
551 this->m_data[i] -= other.m_data[i];
557Array<T> &Array<T>::operator*=(
const Array<T> &other) {
558 assert(m_sizes == other.m_sizes &&
559 "Arithmetic only defined for equal-dimension arrays");
560 for (std::size_t i = 0; i < m_data.size(); ++i) {
561 this->m_data[i] *= other.m_data[i];
567Array<T> &Array<T>::operator/=(
const Array<T> &other) {
568 assert(m_sizes == other.m_sizes &&
569 "Arithmetic only defined for equal-dimension arrays");
570 for (std::size_t i = 0; i < m_data.size(); ++i) {
571 this->m_data[i] /= other.m_data[i];
578 for (std::size_t i = 0; i < m_data.size(); ++i) {
579 this->m_data[i] += t;
586 for (std::size_t i = 0; i < m_data.size(); ++i) {
587 this->m_data[i] -= t;
593Array<T> &Array<T>::operator*=(
const T &t) {
594 for (std::size_t i = 0; i < m_data.size(); ++i) {
595 this->m_data[i] *= t;
601Array<T> &Array<T>::operator/=(
const T &t) {
602 for (std::size_t i = 0; i < m_data.size(); ++i) {
603 this->m_data[i] /= t;
610 assert(m_Ndim == 2 &&
"Row only defined for 2D array");
611 return ArrayView(m_data.data() + i * m_sizes[1], m_sizes[1]);
615 assert(m_Ndim == 2 &&
"Col only defined for 2D array");
616 return ArrayView(m_data.data() + j, m_sizes[0], m_sizes[1]);
620 assert(m_Ndim == 2 &&
"Row only defined for 2D array");
621 return ArrayView(m_data.data() + i * m_sizes[1], m_sizes[1]);
625 assert(m_Ndim == 2 &&
"Col only defined for 2D array");
626 return ArrayView<const T>(m_data.data() + j, m_sizes[0], m_sizes[1]);
Like Arithmetic, but for two different types (T op U).
Definition Template.hpp:66
Helper template that provides +, -, *, / given +=, -=, *=, /=.
Definition Template.hpp:51
Non-owning view onto a 1D contiguous or strided array segment.
Definition Array.hpp:164
auto begin()
Iterator to the beginning.
Definition Array.hpp:202
std::vector< T > vector()
Returns a copy of the view as a std::vector.
Definition Array.hpp:230
N-dimensional array with arithmetic operators.
Definition Array.hpp:304
void resize(std::size_t first, Args... rest)
Resizes the array. Note: invalidates all underlying data.
Definition Array.hpp:464
auto cbegin() const
Constant iterator to the beginning.
Definition Array.hpp:381
std::size_t cols() const
Number of columns (equivalent to size(1)).
Definition Array.hpp:369
T & operator()(std::size_t first, Args... rest)
Access element without bounds checking.
Definition Array.hpp:526
T & at(std::size_t first, Args... rest)
Access element with bounds checking.
Definition Array.hpp:514
Array(std::size_t first, Args... rest)
Constructs an N-dimensional array with the given dimension sizes.
Definition Array.hpp:454
std::size_t dimensions() const
Returns the number of dimensions.
Definition Array.hpp:338
const std::vector< std::size_t > & shape() const
Returns the shape (sizes of all dimensions) of the array.
Definition Array.hpp:341
ArrayView< T > row(std::size_t i)
A view onto the ith row. Only defined for 2D arrays.
Definition Array.hpp:609
auto begin()
Iterator to the beginning.
Definition Array.hpp:379
std::size_t rows() const
Number of rows (equivalent to size(0)).
Definition Array.hpp:367
auto rend()
Reverse iterator to the end of the data.
Definition Array.hpp:392
const std::vector< T > & vector() const
Const reference to the underlying flat data vector.
Definition Array.hpp:364
auto cend() const
Constant iterator to the end.
Definition Array.hpp:385
ArrayView< T > col(std::size_t j)
A view onto the jth column. Only defined for 2D arrays.
Definition Array.hpp:614
T * data()
Pointer to the first element of the underlying contiguous storage.
Definition Array.hpp:360
Array< T > & operator+=(const Array< T > &other)
Element-wise arithmetic between arrays of identical shape (+, -, *, /).
Definition Array.hpp:537
auto crend() const
Constant reverse iterator to the end of the data.
Definition Array.hpp:394
auto rbegin()
Reverse iterator to the beginning of the data.
Definition Array.hpp:388
std::size_t size(std::size_t dim) const
Returns the size of a specific dimension.
Definition Array.hpp:335
auto end()
Iterator to the end.
Definition Array.hpp:383
std::size_t size() const
Returns the total number of elements.
Definition Array.hpp:332
auto crbegin() const
Constant reverse iterator to the beginning of the data.
Definition Array.hpp:390
Helper template that provides !=, >, <=, >= given == and <.
Definition Template.hpp:36
Const version of StrideIterator.
Definition Array.hpp:97
Iterator with a configurable stride.
Definition Array.hpp:36
General-purpose utility library.
Definition Array.hpp:23
auto NDrange(std::size_t first, Args... rest)
Returns all index tuples for an N-dimensional range.
Definition Array.hpp:278
T product(T first, Args... rest)
Variadic product - helper function.
Definition Array.hpp:243