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