2 #include "Template.hpp"
24 StrideIterator(T *ptr,
long stride) : m_ptr(ptr), m_stride(stride) {}
26 T &operator*() {
return *m_ptr; }
28 const T &operator*()
const {
return *m_ptr; }
31 return m_ptr == other.m_ptr;
34 return m_ptr < other.m_ptr;
57 m_ptr += n * m_stride;
62 m_ptr -= n * m_stride;
67 auto out_iter = *
this;
72 auto out_iter = *
this;
87 const T &operator*()
const {
return *m_ptr; }
90 return m_ptr == other.m_ptr;
93 return m_ptr < other.m_ptr;
116 m_ptr += n * m_stride;
121 m_ptr -= n * m_stride;
126 auto out_iter = *
this;
127 return out_iter += n;
131 auto out_iter = *
this;
132 return out_iter -= n;
143 template <
typename T =
double>
148 std::size_t m_stride;
152 ArrayView(T *data, std::size_t size, std::size_t stride = 1)
153 : m_size(size), m_stride(stride), m_data(data) {}
155 std::size_t size()
const {
return m_size; }
157 T &operator[](std::size_t i) {
return m_data[i * m_stride]; }
159 T operator[](std::size_t i)
const {
return m_data[i * m_stride]; }
161 T &at(std::size_t i) {
163 return m_data[i * m_stride];
166 T at(std::size_t i)
const {
168 return m_data[i * m_stride];
171 T &operator()(std::size_t i) {
return at(i); }
172 T operator()(std::size_t i)
const {
return at(i); }
174 T &front() {
return at(0); }
175 T front()
const {
return at(0); }
176 T &back() {
return at(m_size - 1); }
177 T back()
const {
return at(m_size - 1); }
179 T *data() {
return m_data; }
186 return StrideIterator(m_data +
long(m_size * m_stride),
long(m_stride));
189 return ConstStrideIterator(m_data +
long(m_size * m_stride),
194 return StrideIterator(m_data +
long(m_size * m_stride) -
long(m_stride),
197 auto crbegin()
const {
198 return ConstStrideIterator(
199 m_data +
long(m_size * m_stride) -
long(m_stride), -
long(m_stride));
203 return StrideIterator(m_data -
long(m_stride), -
long(m_stride));
206 return ConstStrideIterator(m_data -
long(m_stride), -
long(m_stride));
212 for (std::size_t i = 0; i < m_size; ++i) {
213 out.push_back(m_data[i * m_stride]);
222 template <
typename T,
typename... Args>
224 if constexpr (
sizeof...(rest) == 0) {
227 return first *
product(rest...);
231 template <std::
size_t N>
232 void NDrange_impl(std::vector<std::array<std::size_t, N>> &result,
233 std::array<std::size_t, N> ¤t,
234 const std::array<std::size_t, N> &maxValues,
237 result.push_back(current);
241 for (std::size_t i = 0; i < maxValues[index]; ++i) {
243 NDrange_impl<N>(result, current, maxValues, index + 1);
255 template <
typename... Args>
256 auto NDrange(std::size_t first, Args... rest) {
257 constexpr std::size_t N =
sizeof...(rest) + 1;
259 const std::array<std::size_t, N> maxValues = {
260 first,
static_cast<std::size_t
>(rest)...};
262 std::vector<std::array<std::size_t, N>> result;
263 result.reserve(
product(first,
static_cast<std::size_t
>(rest)...));
265 std::array<std::size_t, N> current = {0};
267 NDrange_impl<N>(result, current, maxValues, 0);
272 template <
typename T =
double>
273 class Array :
public Arithmetic<Array<T>>, Arithmetic2<Array<T>, T> {
277 std::vector<std::size_t> m_sizes;
281 std::vector<std::size_t> m_cumulative_sizes;
283 std::size_t m_total_size;
285 std::vector<T> m_data;
290 template <
typename... Args>
291 Array(std::size_t first, Args... rest);
294 template <
typename... Args>
295 void resize(std::size_t first, Args... rest);
298 std::size_t size()
const {
return m_total_size; }
301 std::size_t size(std::size_t dim)
const {
return m_sizes.at(dim); }
304 std::size_t dimensions()
const {
return m_Ndim; }
307 const std::vector<std::size_t> &shape()
const {
return m_sizes; }
310 template <
typename... Args>
311 T &at(std::size_t first, Args... rest);
314 template <
typename... Args>
315 T at(std::size_t first, Args... rest)
const;
318 template <
typename... Args>
319 T &operator()(std::size_t first, Args... rest);
322 template <
typename... Args>
323 T operator()(std::size_t first, Args... rest)
const;
327 T *data() {
return m_data.data(); }
328 const T *data()
const {
return m_data.data(); }
331 const std::vector<T> &vector()
const {
return m_data; }
334 std::size_t rows()
const {
return size(0); }
336 std::size_t cols()
const {
return size(1); }
339 ArrayView<T> row(std::size_t i);
340 ArrayView<const T> row(std::size_t i)
const;
342 ArrayView<T> col(std::size_t j);
343 ArrayView<const T> col(std::size_t j)
const;
346 auto begin() {
return m_data.begin(); }
348 auto cbegin()
const {
return m_data.cbegin(); }
350 auto end() {
return m_data.end(); }
352 auto cend()
const {
return m_data.cend(); }
355 auto rbegin() {
return m_data.rbegin(); }
357 auto crbegin()
const {
return m_data.crbegin(); }
359 auto rend() {
return m_data.rend(); }
361 auto crend()
const {
return m_data.crend(); }
366 Array<T> &operator-=(
const Array<T> &other);
367 Array<T> &operator*=(
const Array<T> &other);
368 Array<T> &operator/=(
const Array<T> &other);
375 Array<T> &operator-=(
const T &t);
376 Array<T> &operator*=(
const T &t);
377 Array<T> &operator/=(
const T &t);
381 std::vector<std::size_t> calc_cumulative_size()
const;
384 template <
typename... Args>
385 std::size_t unchecked_index(std::size_t first, Args... rest)
const;
388 template <
typename... Args>
389 std::size_t unchecked_index_impl(std::size_t dim, std::size_t first,
393 template <
typename... Args>
394 std::size_t checked_index(std::size_t first, Args... rest)
const;
397 template <
typename... Args>
398 std::size_t checked_index_impl(std::size_t dim, std::size_t first,
405 template <
typename T>
406 std::vector<std::size_t> Array<T>::calc_cumulative_size()
const {
407 std::vector<std::size_t> cumulative_size;
408 cumulative_size.reserve(m_sizes.size());
409 for (std::size_t i = 0; i < m_Ndim; ++i) {
410 cumulative_size.push_back(std::accumulate(m_sizes.cbegin() +
long(i) + 1,
412 std::multiplies<std::size_t>()));
414 return cumulative_size;
417 template <
typename T>
418 template <
typename... Args>
419 Array<T>::Array(std::size_t first, Args... rest)
420 : m_sizes({first,
static_cast<std::size_t
>(rest)...}),
421 m_Ndim(m_sizes.size()),
422 m_cumulative_sizes(calc_cumulative_size()),
423 m_total_size(std::accumulate(m_sizes.cbegin(), m_sizes.cend(), 1ul,
424 std::multiplies<std::size_t>())),
425 m_data(m_total_size) {}
427 template <
typename T>
428 template <
typename... Args>
429 void Array<T>::resize(std::size_t first, Args... rest) {
430 m_sizes = std::vector{first,
static_cast<std::size_t
>(rest)...};
431 m_Ndim = m_sizes.size();
432 m_cumulative_sizes = calc_cumulative_size();
433 m_total_size = std::accumulate(m_sizes.cbegin(), m_sizes.cend(), 1ul,
434 std::multiplies<std::size_t>());
435 m_data.resize(m_total_size);
438 template <
typename T>
439 template <
typename... Args>
440 std::size_t Array<T>::unchecked_index(std::size_t first, Args... rest)
const {
441 return unchecked_index_impl(0, first, rest...);
444 template <
typename T>
445 template <
typename... Args>
446 std::size_t Array<T>::unchecked_index_impl(std::size_t dim, std::size_t first,
447 Args... rest)
const {
448 if constexpr (
sizeof...(rest) == 0) {
449 return first * m_cumulative_sizes[dim];
451 return first * m_cumulative_sizes[dim] +
452 unchecked_index_impl(dim + 1, rest...);
456 template <
typename T>
457 template <
typename... Args>
458 std::size_t Array<T>::checked_index(std::size_t first, Args... rest)
const {
459 assert(
sizeof...(rest) + 1 == m_Ndim &&
460 "Number of arguments must match number of dimensions");
461 return checked_index_impl(0, first, rest...);
464 template <
typename T>
465 template <
typename... Args>
466 std::size_t Array<T>::checked_index_impl(std::size_t dim, std::size_t first,
467 Args... rest)
const {
468 assert(first < m_sizes[dim]);
469 if constexpr (
sizeof...(rest) == 0) {
470 return first * m_cumulative_sizes[dim];
472 return first * m_cumulative_sizes[dim] +
473 checked_index_impl(dim + 1, rest...);
477 template <
typename T>
478 template <
typename... Args>
479 T &Array<T>::at(std::size_t first, Args... rest) {
480 return m_data.at(checked_index(first, rest...));
483 template <
typename T>
484 template <
typename... Args>
485 T Array<T>::at(std::size_t first, Args... rest)
const {
486 return m_data.at(checked_index(first, rest...));
489 template <
typename T>
490 template <
typename... Args>
491 T &Array<T>::operator()(std::size_t first, Args... rest) {
492 return m_data[unchecked_index(first, rest...)];
495 template <
typename T>
496 template <
typename... Args>
497 T Array<T>::operator()(std::size_t first, Args... rest)
const {
498 return m_data[unchecked_index(first, rest...)];
501 template <
typename T>
502 Array<T> &Array<T>::operator+=(
const Array<T> &other) {
503 assert(m_sizes == other.m_sizes &&
504 "Arithmetic only defined for equal-dimension arrays");
505 for (std::size_t i = 0; i < m_data.size(); ++i) {
506 this->m_data[i] += other.m_data[i];
511 template <
typename T>
512 Array<T> &Array<T>::operator-=(
const Array<T> &other) {
513 assert(m_sizes == other.m_sizes &&
514 "Arithmetic only defined for equal-dimension arrays");
515 for (std::size_t i = 0; i < m_data.size(); ++i) {
516 this->m_data[i] -= other.m_data[i];
521 template <
typename T>
522 Array<T> &Array<T>::operator*=(
const Array<T> &other) {
523 assert(m_sizes == other.m_sizes &&
524 "Arithmetic only defined for equal-dimension arrays");
525 for (std::size_t i = 0; i < m_data.size(); ++i) {
526 this->m_data[i] *= other.m_data[i];
531 template <
typename T>
532 Array<T> &Array<T>::operator/=(
const Array<T> &other) {
533 assert(m_sizes == other.m_sizes &&
534 "Arithmetic only defined for equal-dimension arrays");
535 for (std::size_t i = 0; i < m_data.size(); ++i) {
536 this->m_data[i] /= other.m_data[i];
541 template <
typename T>
542 Array<T> &Array<T>::operator+=(
const T &t) {
543 for (std::size_t i = 0; i < m_data.size(); ++i) {
544 this->m_data[i] += t;
549 template <
typename T>
550 Array<T> &Array<T>::operator-=(
const T &t) {
551 for (std::size_t i = 0; i < m_data.size(); ++i) {
552 this->m_data[i] -= t;
557 template <
typename T>
558 Array<T> &Array<T>::operator*=(
const T &t) {
559 for (std::size_t i = 0; i < m_data.size(); ++i) {
560 this->m_data[i] *= t;
565 template <
typename T>
566 Array<T> &Array<T>::operator/=(
const T &t) {
567 for (std::size_t i = 0; i < m_data.size(); ++i) {
568 this->m_data[i] /= t;
573 template <
typename T>
574 ArrayView<T> Array<T>::row(std::size_t i) {
575 assert(m_Ndim == 2 &&
"Row only defined for 2D array");
576 return ArrayView(m_data.data() + i * m_sizes[1], m_sizes[1]);
578 template <
typename T>
579 ArrayView<T> Array<T>::col(std::size_t j) {
580 assert(m_Ndim == 2 &&
"Col only defined for 2D array");
581 return ArrayView(m_data.data() + j, m_sizes[0], m_sizes[1]);
583 template <
typename T>
584 ArrayView<const T> Array<T>::row(std::size_t i)
const {
585 assert(m_Ndim == 2 &&
"Row only defined for 2D array");
586 return ArrayView(m_data.data() + i * m_sizes[1], m_sizes[1]);
588 template <
typename T>
589 ArrayView<const T> Array<T>::col(std::size_t j)
const {
590 assert(m_Ndim == 2 &&
"Col only defined for 2D array");
591 return ArrayView<const T>(m_data.data() + j, m_sizes[0], m_sizes[1]);
A view onto a 1D array; used for rows/collumns of ND array. Can have a stride.
Definition: Array.hpp:144
auto begin()
Iterator to the beginning.
Definition: Array.hpp:182
std::vector< T > vector()
Returns a copy of the array as a std::vector.
Definition: Array.hpp:210
Helper template for comparisons. Derive from this to provide !=,>,<=,>=, given == and <.
Definition: Template.hpp:32
A constant iterator accounting for a stride.
Definition: Array.hpp:79
An iterator accounting for a stride.
Definition: Array.hpp:18
std::vector< T > & operator+=(std::vector< T > &a, const std::vector< T > &b)
Provide addition of two vectors:
Definition: Vector.hpp:454
qip library: A collection of useful functions
Definition: Array.hpp:8
auto NDrange(std::size_t first, Args... rest)
Variadic array of all possible indexes.
Definition: Array.hpp:256
T product(T first, Args... rest)
Variadic product - helper function.
Definition: Array.hpp:223