• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //---------------------------------------------------------------------------//
2 // Copyright (c) 2013 Kyle Lutz <kyle.r.lutz@gmail.com>
3 //
4 // Distributed under the Boost Software License, Version 1.0
5 // See accompanying file LICENSE_1_0.txt or copy at
6 // http://www.boost.org/LICENSE_1_0.txt
7 //
8 // See http://boostorg.github.com/compute for more information.
9 //---------------------------------------------------------------------------//
10 
11 #ifndef BOOST_COMPUTE_CONTAINER_VALARRAY_HPP
12 #define BOOST_COMPUTE_CONTAINER_VALARRAY_HPP
13 
14 #include <cstddef>
15 #include <valarray>
16 
17 #include <boost/static_assert.hpp>
18 #include <boost/type_traits.hpp>
19 
20 #include <boost/compute/buffer.hpp>
21 #include <boost/compute/algorithm/copy.hpp>
22 #include <boost/compute/algorithm/fill.hpp>
23 #include <boost/compute/algorithm/max_element.hpp>
24 #include <boost/compute/algorithm/min_element.hpp>
25 #include <boost/compute/algorithm/transform.hpp>
26 #include <boost/compute/algorithm/accumulate.hpp>
27 #include <boost/compute/detail/buffer_value.hpp>
28 #include <boost/compute/functional.hpp>
29 #include <boost/compute/functional/bind.hpp>
30 #include <boost/compute/iterator/buffer_iterator.hpp>
31 #include <boost/compute/type_traits.hpp>
32 
33 namespace boost {
34 namespace compute {
35 
36 template<class T>
37 class valarray
38 {
39 public:
valarray(const context & context=system::default_context ())40     explicit valarray(const context &context = system::default_context())
41         : m_buffer(context, 0)
42     {
43     }
44 
valarray(size_t size,const context & context=system::default_context ())45     explicit valarray(size_t size,
46                       const context &context = system::default_context())
47         : m_buffer(context, size * sizeof(T))
48     {
49     }
50 
valarray(const T & value,size_t size,const context & context=system::default_context ())51     valarray(const T &value,
52              size_t size,
53              const context &context = system::default_context())
54         : m_buffer(context, size * sizeof(T))
55     {
56         fill(begin(), end(), value);
57     }
58 
valarray(const T * values,size_t size,const context & context=system::default_context ())59     valarray(const T *values,
60              size_t size,
61              const context &context = system::default_context())
62         : m_buffer(context, size * sizeof(T))
63     {
64         copy(values, values + size, begin());
65     }
66 
valarray(const valarray<T> & other)67     valarray(const valarray<T> &other)
68         : m_buffer(other.m_buffer.get_context(), other.size() * sizeof(T))
69     {
70         copy(other.begin(), other.end(), begin());
71     }
72 
valarray(const std::valarray<T> & valarray,const context & context=system::default_context ())73     valarray(const std::valarray<T> &valarray,
74              const context &context = system::default_context())
75         : m_buffer(context, valarray.size() * sizeof(T))
76     {
77         copy(&valarray[0], &valarray[valarray.size()], begin());
78     }
79 
operator =(const valarray<T> & other)80     valarray<T>& operator=(const valarray<T> &other)
81     {
82         if(this != &other){
83             // change to other's OpenCL context
84             m_buffer = buffer(other.m_buffer.get_context(), other.size() * sizeof(T));
85             copy(other.begin(), other.end(), begin());
86         }
87 
88         return *this;
89     }
90 
operator =(const std::valarray<T> & valarray)91     valarray<T>& operator=(const std::valarray<T> &valarray)
92     {
93         m_buffer = buffer(m_buffer.get_context(), valarray.size() * sizeof(T));
94         copy(&valarray[0], &valarray[valarray.size()], begin());
95 
96         return *this;
97     }
98 
99     valarray<T>& operator*=(const T&);
100 
101     valarray<T>& operator/=(const T&);
102 
103     valarray<T>& operator%=(const T& val);
104 
operator +() const105     valarray<T> operator+() const
106     {
107         //  This operator can be used with any type.
108         valarray<T> result(size());
109         copy(begin(), end(), result.begin());
110         return result;
111     }
112 
operator -() const113     valarray<T> operator-() const
114     {
115         BOOST_STATIC_ASSERT_MSG(
116             is_fundamental<T>::value,
117             "This operator can be used with all OpenCL built-in scalar"
118             " and vector types"
119         );
120         valarray<T> result(size());
121         BOOST_COMPUTE_FUNCTION(T, unary_minus, (T x),
122         {
123             return -x;
124         });
125         transform(begin(), end(), result.begin(), unary_minus);
126         return result;
127     }
128 
operator ~() const129     valarray<T> operator~() const
130     {
131         BOOST_STATIC_ASSERT_MSG(
132             is_fundamental<T>::value &&
133                 !is_floating_point<typename scalar_type<T>::type>::value,
134             "This operator can be used with all OpenCL built-in scalar"
135             " and vector types except the built-in scalar and vector float types"
136         );
137         valarray<T> result(size());
138         BOOST_COMPUTE_FUNCTION(T, bitwise_not, (T x),
139         {
140             return ~x;
141         });
142         transform(begin(), end(), result.begin(), bitwise_not);
143         return result;
144     }
145 
146     /// In OpenCL there cannot be memory buffer with bool type, for
147     /// this reason return type is valarray<char> instead of valarray<bool>.
148     /// 1 means true, 0 means false.
operator !() const149     valarray<char> operator!() const
150     {
151         BOOST_STATIC_ASSERT_MSG(
152             is_fundamental<T>::value,
153             "This operator can be used with all OpenCL built-in scalar"
154             " and vector types"
155         );
156         valarray<char> result(size());
157         BOOST_COMPUTE_FUNCTION(char, logical_not, (T x),
158         {
159             return !x;
160         });
161         transform(begin(), end(), &result[0], logical_not);
162         return result;
163     }
164 
165     valarray<T>& operator+=(const T&);
166 
167     valarray<T>& operator-=(const T&);
168 
169     valarray<T>& operator^=(const T&);
170 
171     valarray<T>& operator&=(const T&);
172 
173     valarray<T>& operator|=(const T&);
174 
175     valarray<T>& operator<<=(const T&);
176 
177     valarray<T>& operator>>=(const T&);
178 
179     valarray<T>& operator*=(const valarray<T>&);
180 
181     valarray<T>& operator/=(const valarray<T>&);
182 
183     valarray<T>& operator%=(const valarray<T>&);
184 
185     valarray<T>& operator+=(const valarray<T>&);
186 
187     valarray<T>& operator-=(const valarray<T>&);
188 
189     valarray<T>& operator^=(const valarray<T>&);
190 
191     valarray<T>& operator&=(const valarray<T>&);
192 
193     valarray<T>& operator|=(const valarray<T>&);
194 
195     valarray<T>& operator<<=(const valarray<T>&);
196 
197     valarray<T>& operator>>=(const valarray<T>&);
198 
~valarray()199     ~valarray()
200     {
201 
202     }
203 
size() const204     size_t size() const
205     {
206         return m_buffer.size() / sizeof(T);
207     }
208 
resize(size_t size,T value=T ())209     void resize(size_t size, T value = T())
210     {
211         m_buffer = buffer(m_buffer.get_context(), size * sizeof(T));
212         fill(begin(), end(), value);
213     }
214 
operator [](size_t index)215     detail::buffer_value<T> operator[](size_t index)
216     {
217         return *(begin() + static_cast<ptrdiff_t>(index));
218     }
219 
operator [](size_t index) const220     const detail::buffer_value<T> operator[](size_t index) const
221     {
222         return *(begin() + static_cast<ptrdiff_t>(index));
223     }
224 
T(min)225     T (min)() const
226     {
227         return *(boost::compute::min_element(begin(), end()));
228     }
229 
T(max)230     T (max)() const
231     {
232         return *(boost::compute::max_element(begin(), end()));
233     }
234 
sum() const235     T sum() const
236     {
237         return boost::compute::accumulate(begin(), end(), T(0));
238     }
239 
240     template<class UnaryFunction>
apply(UnaryFunction function) const241     valarray<T> apply(UnaryFunction function) const
242     {
243         valarray<T> result(size());
244         transform(begin(), end(), result.begin(), function);
245         return result;
246     }
247 
get_buffer() const248     const buffer& get_buffer() const
249     {
250         return m_buffer;
251     }
252 
253 
254 private:
begin() const255     buffer_iterator<T> begin() const
256     {
257         return buffer_iterator<T>(m_buffer, 0);
258     }
259 
end() const260     buffer_iterator<T> end() const
261     {
262         return buffer_iterator<T>(m_buffer, size());
263     }
264 
265 private:
266     buffer m_buffer;
267 };
268 
269 /// \internal_
270 #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(op, op_name, assert) \
271     template<class T> \
272     inline valarray<T>& \
273     valarray<T>::operator op##=(const T& val) \
274     { \
275         assert \
276         transform(begin(), end(), begin(), \
277             ::boost::compute::bind(op_name<T>(), placeholders::_1, val)); \
278         return *this; \
279     } \
280     \
281     template<class T> \
282     inline valarray<T>& \
283     valarray<T>::operator op##=(const valarray<T> &rhs) \
284     { \
285         assert \
286         transform(begin(), end(), rhs.begin(), begin(), op_name<T>()); \
287         return *this; \
288     }
289 
290 /// \internal_
291 #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(op, op_name) \
292     BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(op, op_name, \
293         BOOST_STATIC_ASSERT_MSG( \
294             is_fundamental<T>::value, \
295             "This operator can be used with all OpenCL built-in scalar" \
296             " and vector types" \
297         ); \
298     )
299 
300 /// \internal_
301 /// For some operators class T can't be floating point type.
302 /// See OpenCL specification, operators chapter.
303 #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(op, op_name) \
304     BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(op, op_name, \
305         BOOST_STATIC_ASSERT_MSG( \
306             is_fundamental<T>::value && \
307                 !is_floating_point<typename scalar_type<T>::type>::value, \
308             "This operator can be used with all OpenCL built-in scalar" \
309             " and vector types except the built-in scalar and vector float types" \
310         ); \
311     )
312 
313 // defining operators
314 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(+, plus)
315 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(-, minus)
316 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(*, multiplies)
317 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(/, divides)
318 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(^, bit_xor)
319 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(&, bit_and)
320 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(|, bit_or)
321 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(<<, shift_left)
322 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(>>, shift_right)
323 
324 // The remainder (%) operates on
325 // integer scalar and integer vector data types only.
326 // See OpenCL specification.
327 BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(%, modulus,
328     BOOST_STATIC_ASSERT_MSG(
329         is_integral<typename scalar_type<T>::type>::value,
330         "This operator can be used only with OpenCL built-in integer types"
331     );
332 )
333 
334 #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY
335 #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP
336 
337 #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT
338 
339 /// \internal_
340 /// Macro for defining binary operators for valarray
341 #define BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR(op, op_name, assert) \
342     template<class T> \
343     valarray<T> operator op (const valarray<T>& lhs, const valarray<T>& rhs) \
344     { \
345         assert \
346         valarray<T> result(lhs.size()); \
347         transform(buffer_iterator<T>(lhs.get_buffer(), 0), \
348                   buffer_iterator<T>(lhs.get_buffer(), lhs.size()), \
349                   buffer_iterator<T>(rhs.get_buffer(), 0), \
350                   buffer_iterator<T>(result.get_buffer(), 0), \
351                   op_name<T>()); \
352         return result; \
353     } \
354     \
355     template<class T> \
356     valarray<T> operator op (const T& val, const valarray<T>& rhs) \
357     { \
358         assert \
359         valarray<T> result(rhs.size()); \
360         transform(buffer_iterator<T>(rhs.get_buffer(), 0), \
361                   buffer_iterator<T>(rhs.get_buffer(), rhs.size()), \
362                   buffer_iterator<T>(result.get_buffer(), 0), \
363                   ::boost::compute::bind(op_name<T>(), val, placeholders::_1)); \
364         return result; \
365     } \
366     \
367     template<class T> \
368     valarray<T> operator op (const valarray<T>& lhs, const T& val) \
369     { \
370         assert \
371         valarray<T> result(lhs.size()); \
372         transform(buffer_iterator<T>(lhs.get_buffer(), 0), \
373                   buffer_iterator<T>(lhs.get_buffer(), lhs.size()), \
374                   buffer_iterator<T>(result.get_buffer(), 0), \
375                   ::boost::compute::bind(op_name<T>(), placeholders::_1, val)); \
376         return result; \
377     }
378 
379 /// \internal_
380 #define BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(op, op_name) \
381     BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR(op, op_name, \
382         BOOST_STATIC_ASSERT_MSG( \
383             is_fundamental<T>::value, \
384             "This operator can be used with all OpenCL built-in scalar" \
385             " and vector types" \
386         ); \
387     )
388 
389 /// \internal_
390 /// For some operators class T can't be floating point type.
391 /// See OpenCL specification, operators chapter.
392 #define BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(op, op_name) \
393     BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR(op, op_name, \
394         BOOST_STATIC_ASSERT_MSG( \
395             is_fundamental<T>::value && \
396                 !is_floating_point<typename scalar_type<T>::type>::value, \
397             "This operator can be used with all OpenCL built-in scalar" \
398             " and vector types except the built-in scalar and vector float types" \
399         ); \
400     )
401 
402 // defining binary operators for valarray
403 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(+, plus)
404 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(-, minus)
405 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(*, multiplies)
406 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(/, divides)
407 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(^, bit_xor)
408 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(&, bit_and)
409 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(|, bit_or)
410 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(<<, shift_left)
411 BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(>>, shift_right)
412 
413 #undef BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY
414 #undef BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP
415 
416 #undef BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR
417 
418 /// \internal_
419 /// Macro for defining valarray comparison operators.
420 /// For return type valarray<char> is used instead of valarray<bool> because
421 /// in OpenCL there cannot be memory buffer with bool type.
422 ///
423 /// Note it's also used for defining binary logical operators (==, &&)
424 #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(op, op_name) \
425     template<class T> \
426     valarray<char> operator op (const valarray<T>& lhs, const valarray<T>& rhs) \
427     { \
428         BOOST_STATIC_ASSERT_MSG( \
429             is_fundamental<T>::value, \
430             "This operator can be used with all OpenCL built-in scalar" \
431             " and vector types" \
432         ); \
433         valarray<char> result(lhs.size()); \
434         transform(buffer_iterator<T>(lhs.get_buffer(), 0), \
435                   buffer_iterator<T>(lhs.get_buffer(), lhs.size()), \
436                   buffer_iterator<T>(rhs.get_buffer(), 0), \
437                   buffer_iterator<char>(result.get_buffer(), 0), \
438                   op_name<T>()); \
439         return result; \
440     } \
441     \
442     template<class T> \
443     valarray<char> operator op (const T& val, const valarray<T>& rhs) \
444     { \
445         BOOST_STATIC_ASSERT_MSG( \
446             is_fundamental<T>::value, \
447             "This operator can be used with all OpenCL built-in scalar" \
448             " and vector types" \
449         ); \
450         valarray<char> result(rhs.size()); \
451         transform(buffer_iterator<T>(rhs.get_buffer(), 0), \
452                   buffer_iterator<T>(rhs.get_buffer(), rhs.size()), \
453                   buffer_iterator<char>(result.get_buffer(), 0), \
454                   ::boost::compute::bind(op_name<T>(), val, placeholders::_1)); \
455         return result; \
456     } \
457     \
458     template<class T> \
459     valarray<char> operator op (const valarray<T>& lhs, const T& val) \
460     { \
461         BOOST_STATIC_ASSERT_MSG( \
462             is_fundamental<T>::value, \
463             "This operator can be used with all OpenCL built-in scalar" \
464             " and vector types" \
465         ); \
466         valarray<char> result(lhs.size()); \
467         transform(buffer_iterator<T>(lhs.get_buffer(), 0), \
468                   buffer_iterator<T>(lhs.get_buffer(), lhs.size()), \
469                   buffer_iterator<char>(result.get_buffer(), 0), \
470                   ::boost::compute::bind(op_name<T>(), placeholders::_1, val)); \
471         return result; \
472     }
473 
474 BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(==, equal_to)
475 BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(!=, not_equal_to)
476 BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(>, greater)
477 BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(<, less)
478 BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(>=, greater_equal)
479 BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(<=, less_equal)
480 
481 /// \internal_
482 /// Macro for defining binary logical operators for valarray.
483 ///
484 /// For return type valarray<char> is used instead of valarray<bool> because
485 /// in OpenCL there cannot be memory buffer with bool type.
486 /// 1 means true, 0 means false.
487 #define BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR(op, op_name) \
488     BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(op, op_name)
489 
490 BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR(&&, logical_and)
491 BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR(||, logical_or)
492 
493 #undef BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR
494 
495 #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR
496 
497 } // end compute namespace
498 } // end boost namespace
499 
500 #endif // BOOST_COMPUTE_CONTAINER_VALARRAY_HPP
501