From cd3ebd3b504bbf9fc18de71b5d4ca47e7e6b6d48 Mon Sep 17 00:00:00 2001
From: Pauli Virtanen <pauli.t.virtanen@jyu.fi>
Date: Tue, 2 Aug 2022 16:47:19 +0300
Subject: [PATCH] array: more checks

---
 src/action.hpp |  4 ++--
 src/array.hpp  | 63 +++++++++++++++++++++++++++++++++++---------------
 src/main.cpp   | 29 +++++++++++++++--------
 3 files changed, 66 insertions(+), 30 deletions(-)

diff --git a/src/action.hpp b/src/action.hpp
index 1006075..d220e3a 100644
--- a/src/action.hpp
+++ b/src/action.hpp
@@ -8,8 +8,8 @@
 template <typename Scalar>
 inline Scalar S_2(Array<Scalar,2> Q)
 {
-    Q(0u,0u) = 123;
-    Q(1u,1u) = 123;
+    Q(0u,0u) = 1;
+    Q(0u,1u) = 2;
     return Scalar(0);
 }
 
diff --git a/src/array.hpp b/src/array.hpp
index bb2bd7f..bdce598 100644
--- a/src/array.hpp
+++ b/src/array.hpp
@@ -4,12 +4,13 @@
 #include <vector>
 #include <array>
 #include <type_traits>
+#include <initializer_list>
 #include <stdexcept>
 
 
-/*! Simple data-by-reference strided array class
+/*! Simple data-by-reference strided array class a la Fortran
  */
-template <typename Scalar, int NDim, typename Storage = std::vector<Scalar> >
+template <typename Scalar, size_t NDim, typename Storage = std::vector<Scalar> >
 class Array
 {
 private:
@@ -19,24 +20,36 @@ private:
     size_t offset_ = 0;
 
 public:
-    Array(Array<Scalar,NDim>&& array)
-        : data_(array.data_), shape_(array.shape_), stride_(array.stride_), offset_(array.offset_)
-        {}
-
-    Array(Storage& data, const std::array<size_t, NDim> shape, const std::array<size_t, NDim> stride, const size_t offset=0)
+    Array(Storage& data, const std::array<size_t, NDim> shape, const std::array<size_t, NDim> stride, const size_t offset)
         : data_(data), shape_(shape), stride_(stride), offset_(offset)
         {}
 
-    Array(Storage& data, const std::array<size_t, NDim> shape)
+    Array(Storage& data, const std::array<size_t, NDim> shape, const bool row_major=true)
         : data_(data), shape_(shape), offset_(0)
         {
-            // row-major strides
-            for (size_t i = NDim; i > 0; --i) {
-                if (i == NDim)
-                    stride_[i-1] = 1;
-                else
-                    stride_[i-1] = shape[i] * stride_[i];
+            if (row_major) {
+                for (size_t i = NDim; i > 0; --i) {
+                    if (i == NDim)
+                        stride_[i-1] = 1;
+                    else
+                        stride_[i-1] = shape[i] * stride_[i];
+                }
+            } else {
+                for (size_t i = 0; i < NDim; ++i) {
+                    if (i == 0)
+                        stride_[i] = 1;
+                    else
+                        stride_[i] = shape[i-1] * stride_[i-1];
+                }
             }
+
+#ifndef NO_BOUNDS_CHECK
+            size_t total = 1;
+            for (size_t i = 0; i < NDim; ++i)
+                total *= shape[i];
+            if (total > data.size())
+                throw std::out_of_range("data array too small");
+#endif
         }
 
     template <typename... Idx>
@@ -48,7 +61,7 @@ public:
     template <size_t axis>
     Array<Scalar, NDim-1> slice(size_t pos=0) const
         {
-            static_assert(axis < NDim, "invalid slice index");
+            static_assert(axis < NDim, "invalid axis");
 
             std::array<size_t, NDim-1> shape;
             std::array<size_t, NDim-1> stride;
@@ -70,7 +83,7 @@ public:
     template <size_t axis>
     Array<Scalar, NDim> slice(size_t begin, size_t end) const
         {
-            static_assert(axis < NDim, "invalid slice index");
+            static_assert(axis < NDim, "invalid axis");
 
             std::array<size_t, NDim> shape;
             std::array<size_t, NDim> stride;
@@ -90,12 +103,20 @@ public:
         }
 
     Storage& data() { return data_; }
-    
+
     template <size_t axis>
-    const size_t shape() const { return shape_[axis]; }
+    const size_t shape() const
+        {
+            static_assert(axis < NDim, "invalid axis");
+            return shape_[axis];
+        }
 
     template <size_t axis>
-    const size_t stride() const { return stride_[axis]; }
+    const size_t stride() const
+        {
+            static_assert(axis < NDim, "invalid axis");
+            return stride_[axis];
+        }
 
     size_t offset() const { return offset_; }
 
@@ -116,6 +137,10 @@ public:
 #endif
             }
 
+#ifndef NO_BOUNDS_CHECK
+            if (idx >= data_.size())
+                throw std::out_of_range("total index out of bounds");
+#endif
             return idx;
         }
 };
diff --git a/src/main.cpp b/src/main.cpp
index e6cc131..1e02e12 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,21 +1,32 @@
 #include "common.hpp"
+#include "array.hpp"
 #include "action.hpp"
 
 
+template <typename Scalar=double>
+void dump(Array<Scalar,3> Q)
+{
+    for (size_t i = 0; i < Q.template shape<0>(); ++i) {
+        for (size_t j = 0; j < Q.template shape<1>(); ++j) {
+            for (size_t k = 0; k < Q.template shape<2>(); ++k) {
+                std::cout << i << "," << j << "," << k << " = " << Q(i,j,k) << std::endl;
+            }
+        }
+    }
+
+    for (size_t i = 0; i < Q.data().size(); ++i) {
+        std::cout << Q.data()[i] << std::endl;
+    }
+}
+
 int main()
 {
-    std::vector<ADComplex> v(2*2*2);
-    Array<ADComplex,3> Q(v,{2,2,2});
+    std::vector<double> v(2*2*2);
+    Array<double,3> Q(v,{2,2,2},false);
 
     S_2(Q.slice<2>());
 
-    for (size_t i = 0; i < Q.shape<0>(); ++i) {
-        for (size_t j = 0; j < Q.shape<1>(); ++j) {
-            for (size_t k = 0; k < Q.shape<2>(); ++k) {
-                std::cout << Q(i,j,k) << std::endl;
-            }
-        }
-    }
+    dump<>(Q);
 
     return 0;
 }
-- 
GitLab