valarray.hpp 16 KB

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