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