M/c++_api/inc/DM/Array.hpp
1 #ifndef DM_ARRAY_HPP_INCLUDED
2 #define DM_ARRAY_HPP_INCLUDED
3 
4 #pragma once
5 
6 #include "DM/config.hpp"
7 #include "DM/AutoLink.hpp" //enable autolink
8 
9 // std::ptrdiff_t and std::size_t
10 //#include <cstddef>
11 // std::reverse_iterator<Iterator>
12 //#include <iterator>
13 // std::out_of_range
14 #include <stdexcept>
15 
16 
17 DM_NAMESPACE_BEGIN
18 
19  /**
20  \class Array
21  \tparam T the element type
22  \tparam N the constant size, must be >= 1
23 
24  \brief a template class holding a C-array of constant size.
25 
26  \author wk
27  \date 03.02.2011
28 
29  Array is an aggregate, meaning that it may be initialized with a static initializer list:
30  opals::Array<double,3> arr = { 1., 2., 3. };
31  Array fulfills almost all the requirements of an STL reversible container.
32  The complete implementation is exposed, why opals users may instantiate Array<T,N> with arbitrary template arguments.
33  The class closely follows boost::array.
34  \internal
35  opals::Array extends boost::array. Like boost::array, opals::Array is an aggregate,
36  as it defines no constructors and no protected/private data members (and no base class, no virtual functions).
37  As a consequence, opals::Array may be initialized with an initializer list,
38  but no conversion constructor from boost::array can be provided.
39  For that purpose, first instantiate the opals::Array, then assign the boost::array:
40  opals::Array<double,2> arr;
41  arr = boost_array_double_2_instance;
42  As extensions to boost::array, assignment of a C-array is supported:
43  double da[] = { 1., 2. };
44  arr = da;
45  In contrast to opals::Vector and opals::List,
46  its data member is a plain-old-C-array,
47  why the whole implementation can be exposed to DLL users, together with
48  global template comparison operators - mind that the C-array
49  must not be protected/private in order to keep Array an aggregate.
50  As further extensions to the interface of boost::array,
51  opals::Array provides operator<<, operator>>,
52  and function toInternal(),
53  which returns a boost::array<U>, where U is the internal type
54  corresponding to T (see InternalType).
55  In contrast to boost::array, Array may not be instantiated for N==0.
56  */
57 
58  template<class T, std::size_t N>
59  class DM_API Array
60  {
61 
62  public:
63 
64  T elems[N]; // fixed-size C-array of elements of type T
65 
66  // type definitions
67  typedef T value_type;
68  typedef T* iterator;
69  typedef const T* const_iterator;
70  typedef T& reference;
71  typedef const T& const_reference;
72  typedef std::size_t size_type;
73  typedef std::ptrdiff_t difference_type;
74  typedef std::reverse_iterator<iterator> reverse_iterator;
75  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
76  enum { static_size = N };
77 
78 
79  /// \name assignment, swapping
80  //@{
81  /// assignment with type conversion
82  template <typename T2>
83  Array<T,N>& operator= (const Array<T2,N> &other)
84  {
85  ::std::copy(other.begin(),other.end(), begin());
86  return *this;
87  }
88  /// assign a C-array with type conversion
89  template <typename T2>
90  Array<T,N>& operator= ( const T2 (&other) [N] )
91  {
92  std::copy(other,&other[N], begin());
93  return *this;
94  }
95 
96  /// assign one value to all elements
97  void assign(const T &val)
98  { std::fill_n(begin(),size(),val); }
99 
100  /// swap (linear complexity)
101  void swap(Array<T,N> &other)
102  { std::swap_ranges(begin(),end(),other.begin()); }
103  //}@
104 
105  /// \name iterator traversal
106  /// forward/reverse, const/non-const
107  //@{
108  iterator begin() { return elems; }
109  const_iterator begin() const { return elems; }
110  iterator end() { return elems+N; }
111  const_iterator end() const { return elems+N; }
112 
113  reverse_iterator rbegin() { return reverse_iterator(end()); }
114  const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
115  reverse_iterator rend() { return reverse_iterator(begin()); }
116  const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
117  //}@
118 
119  /// \name direct element access with range check
120  /// zero-based indexing
121  //@{
122  reference operator[](size_type i) { rangecheck(i); return elems[i]; }
123  const_reference operator[](size_type i) const { rangecheck(i); return elems[i]; }
124  reference at(size_type i) { rangecheck(i); return elems[i]; }
125  const_reference at(size_type i) const { rangecheck(i); return elems[i]; }
126  //}@
127 
128 
129  /// \name first/last element
130  //@{
131  reference front() { return elems[0]; }
132  const_reference front() const { return elems[0]; }
133  reference back() { return elems[N-1]; }
134  const_reference back() const { return elems[N-1]; }
135  //}@
136 
137  /// \name direct access to C-array
138  //@{
139  const T* data() const { return elems; }
140  T* data() { return elems; }
141  T* c_array() { return elems; }
142  //}@
143 
144  /// \name size
145  //@{
146  static size_type size() { return N; }
147  static bool empty() { return false; }
148  static size_type max_size() { return N; }
149  //}@
150 
151  private:
152  static void rangecheck (size_type i)
153  {
154  if (i >= size()) {
155  throw std::out_of_range("Array<>: index out of range");
156  }
157  }
158  };
159 
160  template<class T>
161  class Array<T,0>
162  {
163  template<class U> struct Must_not_instantiate_an_empty_opals_Array;
164  typedef typename Must_not_instantiate_an_empty_opals_Array<T>::Type CompilationError;
165  };
166 
167  /// \relatesalso Array
168  template<class T, std::size_t N>
169  bool operator== (const Array<T,N>& l, const Array<T,N>& r) {
170  return std::equal(l.begin(), l.end(), r.begin());
171  }
172 
173  /// \relatesalso Array
174  template<class T, std::size_t N>
175  bool operator< (const Array<T,N>& l, const Array<T,N>& r) {
176  return std::lexicographical_compare(l.begin(),l.end(),r.begin(),r.end());
177  }
178 
179  /// \relatesalso Array
180  template<class T, std::size_t N>
181  bool operator!= (const Array<T,N>& l, const Array<T,N>& r) {
182  return !(l==r);
183  }
184 
185  /// \relatesalso Array
186  template<class T, std::size_t N>
187  bool operator> (const Array<T,N>& l, const Array<T,N>& r) {
188  return r<l;
189  }
190 
191  /// \relatesalso Array
192  template<class T, std::size_t N>
193  bool operator<= (const Array<T,N>& l, const Array<T,N>& r) {
194  return !(r<l);
195  }
196 
197  /// \relatesalso Array
198  template<class T, std::size_t N>
199  bool operator>= (const Array<T,N>& l, const Array<T,N>& r) {
200  return !(l<r);
201  }
202 
203  /// \relatesalso Array
204  template<class T, std::size_t N>
205  void swap (Array<T,N>& l, Array<T,N>& r) {
206  l.swap(r);
207  }
208 
209 DM_NAMESPACE_END
210 
211 
212 #endif //DM_ARRAY_HPP_INCLUDED