From 9642ba7103eef6fe9f01386ed769ffeecb3d2b8e Mon Sep 17 00:00:00 2001
From: Glen Fernandes <glen.fernandes@gmail.com>
Date: Tue, 19 Feb 2019 00:54:36 -0500
Subject: [PATCH] Add test cases for allocators

---
 doc/test_cases.html |   7 ++
 test/Jamfile.v2     |   1 +
 test/allocators.cpp | 151 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 159 insertions(+)
 create mode 100644 test/allocators.cpp

diff --git a/doc/test_cases.html b/doc/test_cases.html
index f0ad9d3..f0a1226 100644
--- a/doc/test_cases.html
+++ b/doc/test_cases.html
@@ -179,6 +179,13 @@ by library users.
 </td>
 </tr>
 
+<tr>
+<td><a href="../test/allocators.cpp">libs/multi_array/test/allocators.cpp</a></td>
+<td>
+Test support for custom allocators.
+</td>
+</tr>
+
 <tr>
 <td><a href="../test/generative_tests.hpp">libs/multi_array/test/generative_tests.hpp</a></td>
 <td>
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 1c90413..ef1260e 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -46,5 +46,6 @@ run stl_interaction.cpp ;
 run resize.cpp ;
 run assert.cpp ;
 run reverse_view.cpp ;
+run allocators.cpp ;
 
 compile concept_checks.cpp ;
diff --git a/test/allocators.cpp b/test/allocators.cpp
new file mode 100644
index 0000000..8bb099f
--- /dev/null
+++ b/test/allocators.cpp
@@ -0,0 +1,151 @@
+// Copyright 2019 Glen Joseph Fernandes
+// (glenjofe@gmail.com)
+//
+// Distributed under the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#include <boost/core/lightweight_test.hpp>
+#include <boost/multi_array.hpp>
+#include <algorithm>
+
+template<class T>
+class creator {
+public:
+  typedef T value_type;
+  typedef T* pointer;
+  typedef std::size_t size_type;
+  typedef std::ptrdiff_t difference_type;
+
+  template<class U>
+  struct rebind {
+    typedef creator<U> other;
+  };
+
+  creator(int state)
+    : state_(state) { }
+
+  template<class U>
+  creator(const creator<U>& other)
+    : state_(other.state()) { }
+
+  T* allocate(std::size_t size) {
+    return static_cast<T*>(::operator new(sizeof(T) * size));
+  }
+
+  void deallocate(T* ptr, std::size_t) {
+    ::operator delete(ptr);
+  }
+
+  int state() const {
+    return state_;
+  }
+
+private:
+  int state_;
+};
+
+template<class T, class U>
+inline bool
+operator==(const creator<T>& a, const creator<U>& b)
+{
+  return a.state() == b.state();
+}
+
+template<class T, class U>
+inline bool
+operator!=(const creator<T>& a, const creator<U>& b)
+{
+  return !(a == b);
+}
+
+void test(const double&, std::size_t*, int*, unsigned)
+{
+}
+
+template<class Array>
+void test(const Array& array, std::size_t* sizes, int* strides,
+    unsigned elements)
+{
+  BOOST_TEST(array.num_elements() == elements);
+  BOOST_TEST(array.size() == *sizes);
+  BOOST_TEST(std::equal(sizes, sizes + array.num_dimensions(), array.shape()));
+  BOOST_TEST(std::equal(strides, strides + array.num_dimensions(),
+    array.strides()));
+  test(array[0], ++sizes, ++strides, elements / array.size());
+}
+
+bool test(const double& a, const double& b)
+{
+  return a == b;
+}
+
+template<class A1, class A2>
+bool test(const A1& a1, const A2& a2)
+{
+  typename A1::const_iterator i1 = a1.begin();
+  typename A2::const_iterator i2 = a2.begin();
+  for (; i1 != a1.end(); ++i1, ++i2) {
+    if (!test(*i1, *i2)) {
+      return false;
+    }
+  }
+  return true;
+}
+
+int main()
+{
+  typedef boost::multi_array<double, 3, creator<double> > type;
+  creator<double> state(1);
+  {
+    type array(state);
+  }
+  boost::array<type::size_type, 3> sizes = { { 3, 3, 3 } };
+  type::size_type elements = 27;
+  {
+    int strides[] = { 9, 3, 1 };
+    type array(sizes, state);
+    test(array, &sizes[0], strides, elements);
+  }
+  {
+    int strides[] = { 1, 3, 9 };
+    type array(sizes, boost::fortran_storage_order(), state);
+    test(array, &sizes[0], strides, elements);
+  }
+  {
+    int strides[] = { 9, 3, 1 };
+    type::extent_gen extents;
+    type array(extents[3][3][3], state);
+    test(array, &sizes[0], strides, elements);
+  }
+  {
+    type array1(sizes, state);
+    std::vector<double> values(elements, 4.5);
+    array1.assign(values.begin(), values.end());
+    type array2(array1);
+    int strides[] = { 9, 3, 1 };
+    test(array2, &sizes[0], strides, elements);
+    BOOST_TEST(test(array1, array2));
+  }
+  {
+    type array1(sizes, state);
+    type array2(sizes, state);
+    std::vector<double> values(elements, 4.5);
+    array1.assign(values.begin(), values.end());
+    array2 = array1;
+    int strides[] = { 9, 3, 1 };
+    test(array2, &sizes[0], strides, elements);
+    BOOST_TEST(test(array1, array2));
+  }
+  {
+    type array1(sizes, state);
+    std::vector<double> values(elements, 4.5);
+    array1.assign(values.begin(), values.end());
+    typedef type::subarray<2>::type other;
+    other array2 = array1[1];
+    other::value_type value = array2[0];
+    BOOST_TEST(test(array1[1][0], value));
+    BOOST_TEST(test(array2[0], value));
+  }
+  return boost::report_errors();
+}