From 551530658fa43c19fd4d86748dd24950380750be Mon Sep 17 00:00:00 2001
From: Stephane Del Pino <stephane.delpino44@gmail.com>
Date: Thu, 11 Oct 2018 15:14:38 +0200
Subject: [PATCH] Add conversion of Array<data_type> to an
 "Array<another_data_type>"

"Array<another_data_type>" is actually (CastArray<another_data_type>).  This is
in fact just a view which allow to access/modify original array's data
reinterpreting them to another type.

The only constrain w.r. to the type is that one must have
sizeof(data_type)*Array::size() == sizeof(other_data_type)*CastArray::size().

CastArray can be built thanks to the helper static function
cast_array_to<other_data_type>::from(given_array).

Usage: for instance, one writes:

Array<double> x(3); x[0]=1;x[1]=2;x[2]=3;
CastArray y = cast_array_to<int>::from(x);        // ok! y values can change
CastArray z = cast_array_to<const int>::from(x);  // ok! z values cannot change

Array<const double> cx = x;
CastArray cy = cast_array_to<int>::from(cx);      // invalid! cannot remove const
CastArray cz = cast_array_to<const int>::from(cx);// ok!

CastArray t = cast_array_to<TinyVector<4,int>>::from(x); // ok!

In last example, execution will fail (sizes are incompatible), but would success
if the size of x was a multiple of 2.

It is unclear if one should impose sizeof(other_data_type) <= sizeof(data_type)
---
 src/utils/CastArray.hpp | 72 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)
 create mode 100644 src/utils/CastArray.hpp

diff --git a/src/utils/CastArray.hpp b/src/utils/CastArray.hpp
new file mode 100644
index 000000000..0f9ec5145
--- /dev/null
+++ b/src/utils/CastArray.hpp
@@ -0,0 +1,72 @@
+#ifndef CAST_ARRAY_HPP
+#define CAST_ARRAY_HPP
+
+#include <Array.hpp>
+
+template <typename DataType,
+          typename CastDataType>
+class CastArray
+{
+ private:
+  const Array<DataType> m_array;
+  const size_t m_size;
+  CastDataType* const m_values;
+
+ public:
+  PASTIS_INLINE
+  const size_t& size() const
+  {
+    return m_size;
+  }
+
+  PASTIS_INLINE
+  CastDataType& operator[](const size_t& i) const
+  {
+    Assert(i<m_size);
+    return m_values[i];
+  }
+
+  PASTIS_INLINE
+  CastArray(const Array<DataType>& array)
+      : m_array (array),
+        m_size  (sizeof(DataType)*array.size()/sizeof(CastDataType)),
+        m_values((array.size() == 0) ? nullptr : reinterpret_cast<CastDataType*>(&(array[0])))
+  {
+    static_assert((std::is_const_v<CastDataType> and std::is_const_v<DataType>) or
+                  (not std::is_const_v<DataType>), "CastArray cannot remove const attribute");
+
+    if (sizeof(DataType)*array.size() % sizeof(CastDataType)) {
+      std::cerr << "cannot cast array to the chosen data type\n";
+      std::exit(1);
+    }
+  }
+
+  PASTIS_INLINE
+  CastArray(const CastArray&) = default;
+
+  PASTIS_INLINE
+  CastArray(CastArray&&) = default;
+
+  PASTIS_INLINE
+  CastArray& operator=(const CastArray&) = default;
+
+  PASTIS_INLINE
+  CastArray& operator=(CastArray&&) = default;
+
+  PASTIS_INLINE
+  ~CastArray() = default;
+};
+
+template <typename CastDataType>
+struct cast_array_to
+{
+  template <typename DataType>
+  PASTIS_INLINE
+  static CastArray<DataType, CastDataType>
+  from(const Array<DataType>& array)
+  {
+    return CastArray<DataType, CastDataType>(array);
+  }
+};
+
+#endif // CAST_ARRAY_HPP
-- 
GitLab