aimstil  5.0.5
numeric_array_operators.h
Go to the documentation of this file.
1 #ifndef TIL_NUMERIC_ARRAY_OPERATORS_H
2 #define TIL_NUMERIC_ARRAY_OPERATORS_H
3 
6 
7 // includes from TIL
8 #include "til/functors.h"
9 #include "til/sandbox.h"
10 
11 namespace til
12 {
13 
14  //-----------------------------------------------------------------------------------------------
15 
16  //-----------------------//
17  // Arithmetic functors //
18  //-----------------------//
19 
20  namespace functor
21  {
22  // NB: I don't know if there is a case when we might have a better choice of iterator
23  // for res than the random access through operator[] ??
24 #define TIL_DEFINE_TEMPLATE_OP(name, op) \
25  template < typename T1, typename T2, typename TRes, std::size_t D > \
26  struct name <numeric_array<T1,D>, numeric_array<T2,D>, TRes > \
27  : public std::binary_function<const numeric_array<T1,D> &, const numeric_array<T2,D> &, TRes > \
28  { \
29  typedef std::binary_function<const numeric_array<T1,D> &, const numeric_array<T2,D> &, TRes > Base; \
30  typedef typename Base::first_argument_type first_argument_type; \
31  typedef typename Base::second_argument_type second_argument_type; \
32  typedef typename Base::result_type result_type; \
33  TRes operator()(first_argument_type x, second_argument_type y) \
34  { \
35  typedef typename value_type_of<TRes>::type value_type; \
36  TRes res; \
37  for (std::size_t i = 0; i < D; ++i) \
38  res[i] = static_cast<value_type>(x[i]) op static_cast<value_type>(y[i]); \
39  return res; \
40  } \
41  }; \
42  template < typename T, typename TRes, std::size_t D > \
43  struct name <T, numeric_array<T,D>, TRes > \
44  : public std::binary_function<T, const numeric_array<T,D> &, TRes > \
45  { \
46  typedef std::binary_function<T, const numeric_array<T,D> &, TRes > Base; \
47  typedef typename Base::first_argument_type first_argument_type; \
48  typedef typename Base::second_argument_type second_argument_type; \
49  typedef typename Base::result_type result_type; \
50  TRes operator()(first_argument_type x, second_argument_type y) \
51  { \
52  TRes res; \
53  for (std::size_t i = 0; i < D; ++i) res[i] = x op y[i]; \
54  return res; \
55  } \
56  }; \
57  template < typename T, typename TRes, std::size_t D > \
58  struct name <numeric_array<T,D>, T, TRes > \
59  : public std::binary_function<const numeric_array<T,D> &, T, TRes > \
60  { \
61  typedef std::binary_function<const numeric_array<T,D> &, T, TRes > Base; \
62  typedef typename Base::first_argument_type first_argument_type; \
63  typedef typename Base::second_argument_type second_argument_type; \
64  typedef typename Base::result_type result_type; \
65  TRes operator()(first_argument_type x, second_argument_type y) \
66  { \
67  TRes res; \
68  for (std::size_t i = 0; i < D; ++i) res[i] = x[i] op y; \
69  return res; \
70  } \
71  }; \
72 
76  // TODO: don't we want some safeguard here for division? Say using til::fraction?
78 
79 #undef TIL_DEFINE_TEMPLATE_OP
80 
81 
82  //-----------------------------------------------------------------------------------------------
83 
84  //----------//
85  // CastTo //
86  //----------//
87 
88  template < typename T1, typename T2, std::size_t D >
89  struct CastTo<numeric_array<T1,D>, numeric_array<T2,D> >
90  : public std::binary_function<numeric_array<T1,D> &, const numeric_array<T2,D> &, void>
91  {
92  typedef std::binary_function<numeric_array<T1,D> &, const numeric_array<T2,D> &, void> Base;
93  typedef typename Base::first_argument_type first_argument_type;
94  typedef typename Base::second_argument_type second_argument_type;
95  void operator()(first_argument_type x, second_argument_type y)
96  {
97  for (std::size_t i = 0; i < D; ++i) x[i] = y[i];
98  }
99  };
100 
101  } // namespace functor
102 
103 
104  //-----------------------------------------------------------------------------------------------
105 
106  //-------------------------//
107  // artithmetic operators //
108  //-------------------------//
109 
110 
111  // Definition of array-on-array operations
112  // NB: I am not sure whether we should allow different value types here, because
113  // then the problem occurs of the return type. I think a functor should probably
114  // take care of these cases.
115 
116 /*
117 #define TIL_OPERATOR(op)
118  template < typename T1, typename T2, std::size_t D > \
119  numeric_array<T,D> \
120  operator op (const numeric_array<T1,D> & x, const numeric_array<T2,D> & y) \
121  { \
122  numeric_array<T,D> res; \
123  for (std::size_t i = 0; i < D; ++i) res[i] = x[i] op y[i]; \
124  } \
125 */
126 #define TIL_OPERATOR(op, func) \
127  template < typename T, std::size_t D > \
128  inline \
129  numeric_array<T,D> \
130  operator op (const numeric_array<T,D> & x, const numeric_array<T,D> & y) \
131  { \
132  return func <numeric_array<T,D>,numeric_array<T,D>,numeric_array<T,D> >() (x,y); \
133  } \
134 
139 
140 #undef TIL_OPERATOR
141 
142 
143  // Operations with constants.
144  // NB: I did not used boost::call_traits::param_type here. This is not because it
145  // is always better to pass by values: the numerical type might actually not be numerical
146  // at all, say std::complex, or even bigger. But I think the compiler can do more
147  // intelligent stuff when a value is passed and this value is known at compile time.
148  // So there's definitely a trade off here.
149  // TODO: check how call_traits::param_type really works, and use it at least if it passes by
150  // value all numerical types.
151 
152  // NB: for the second operator, we dont call x op y, because the operator (esp.
153  // multiplication) might not be commutative.
154 #define TIL_OPERATOR(op, func) \
155  template < typename T , std::size_t D > \
156  inline \
157  numeric_array<T,D> \
158  operator op (const numeric_array<T,D> & x, T y) \
159  { \
160  return func <numeric_array<T,D>,T,numeric_array<T,D> >()(x,y); \
161  } \
162  template < typename T, std::size_t D > \
163  inline \
164  numeric_array<T,D> \
165  operator op (T y, const numeric_array<T,D> & x) \
166  { \
167  return func <T,numeric_array<T,D>,numeric_array<T,D> >()(y,x); \
168  } \
169 
170  TIL_OPERATOR(+, functor::Add);
171  TIL_OPERATOR(-, functor::Sub);
172  TIL_OPERATOR(*, functor::Mul);
173  // Purposedly not implemented
174  TIL_OPERATOR(/, functor::Div)
175 #undef TIL_OPERATOR
176 
177 
178 
179  //-----------------------------------------------------------------------------------------------
180 
181 
182  //------------------------//
183  // Comparison operators //
184  //------------------------//
185 
186 
187 #define TIL_BOOL_VALUE_OPERATOR(opname, op) \
188  template < typename T1, typename T2, std::size_t D > \
189  inline bool opname (const numeric_array<T1,D> & x, \
190  const numeric_array<T2,D> & y) \
191  { \
192  for (std::size_t i = 0; i < D; ++i) \
193  { \
194  if (!(x[i] op y[i])) return false; \
195  } \
196  return true; \
197  } \
198  template < typename T, std::size_t D > \
199  inline bool opname (const numeric_array<T,D> & x, \
200  typename boost::call_traits<T>::param_type y) \
201  { \
202  for (std::size_t i = 0; i < D; ++i) \
203  { \
204  if (!(x[i] op y)) return false; \
205  } \
206  return true; \
207  } \
208 
209  TIL_BOOL_VALUE_OPERATOR(operator==, ==);
210  TIL_BOOL_VALUE_OPERATOR(operator!=, !=);
211 
212  // The problem redefining operator< to do a all< is that there is no more
213  // ordering on our objects. The problem is that these operators are taken
214  // by default for maps and so on. So it's better to point out the potential
215  // problem and give an explicit name to these.
216 
217  TIL_BOOL_VALUE_OPERATOR(all_less, <);
218  TIL_BOOL_VALUE_OPERATOR(all_less_equal, <=);
219  TIL_BOOL_VALUE_OPERATOR(all_greater, >);
220  TIL_BOOL_VALUE_OPERATOR(all_greater_equal, >=);
221 
222 #undef TIL_BOOL_VALUE_OPERATOR
223 
224 
225  //-----------------------------------------------------------------------------------------------
226 
227  //----------------------------//
228  // Bad comparison operators //
229  //----------------------------//
230 
231 
232 #define BAD(op) \
233  template < typename T, std::size_t D > \
234  bool operator op (const numeric_array<T,D> & x, const numeric_array<T,D> & y) \
235  { \
236  return x.do_not_use_these_operators(); \
237  } \
238 
239  BAD(<)
242  BAD(<=)
244  BAD(>)
246  BAD(>=)
247 
248 #undef BAD
249 
250 } // namespace til
251 
252 #endif
253 
254 
#define TIL_DEFINE_TEMPLATE_OP(name, op)
Belongs to package Box Do not include directly, include til/Box.h instead.
Definition: Accumulator.h:10
TIL_OPERATOR(+, functor::Add)
std::binary_function< numeric_array< T1, D > &, const numeric_array< T2, D > &, void > Base
TIL_BOOL_VALUE_OPERATOR(operator==,==)
Static cast functor.
Definition: functors.h:136
#define BAD(op)
Multiplication functor.
Definition: functors.h:293
Subtraction functor.
Definition: functors.h:278
Addition functor.
Definition: functors.h:263
void operator()(first_argument_type x, second_argument_type y)
Division functor.
Definition: functors.h:308