//---------------------------------------------------------------------------// // Copyright (c) 2013 Kyle Lutz // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // // See http://boostorg.github.com/compute for more information. //---------------------------------------------------------------------------// #ifndef BOOST_COMPUTE_CONTAINER_VALARRAY_HPP #define BOOST_COMPUTE_CONTAINER_VALARRAY_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace compute { template class valarray { public: explicit valarray(const context &context = system::default_context()) : m_buffer(context, 0) { } explicit valarray(size_t size, const context &context = system::default_context()) : m_buffer(context, size * sizeof(T)) { } valarray(const T &value, size_t size, const context &context = system::default_context()) : m_buffer(context, size * sizeof(T)) { fill(begin(), end(), value); } valarray(const T *values, size_t size, const context &context = system::default_context()) : m_buffer(context, size * sizeof(T)) { copy(values, values + size, begin()); } valarray(const valarray &other) : m_buffer(other.m_buffer.get_context(), other.size() * sizeof(T)) { } valarray(const std::valarray &valarray, const context &context = system::default_context()) : m_buffer(context, valarray.size() * sizeof(T)) { copy(&valarray[0], &valarray[valarray.size()], begin()); } valarray& operator=(const valarray &other) { if(this != &other){ // change to other's OpenCL context m_buffer = buffer(other.m_buffer.get_context(), other.size() * sizeof(T)); copy(other.begin(), other.end(), begin()); } return *this; } valarray& operator=(const std::valarray &valarray) { m_buffer = buffer(m_buffer.get_context(), valarray.size() * sizeof(T)); copy(&valarray[0], &valarray[valarray.size()], begin()); return *this; } valarray& operator*=(const T&); valarray& operator/=(const T&); valarray& operator%=(const T& val); valarray operator+() const { // This operator can be used with any type. valarray result(size()); copy(begin(), end(), result.begin()); return result; } valarray operator-() const { BOOST_STATIC_ASSERT_MSG( is_fundamental::value, "This operator can be used with all OpenCL built-in scalar" " and vector types" ); valarray result(size()); BOOST_COMPUTE_FUNCTION(T, unary_minus, (T x), { return -x; }); transform(begin(), end(), result.begin(), unary_minus); return result; } valarray operator~() const { BOOST_STATIC_ASSERT_MSG( is_fundamental::value && !is_floating_point::type>::value, "This operator can be used with all OpenCL built-in scalar" " and vector types except the built-in scalar and vector float types" ); valarray result(size()); BOOST_COMPUTE_FUNCTION(T, bitwise_not, (T x), { return ~x; }); transform(begin(), end(), result.begin(), bitwise_not); return result; } /// In OpenCL there cannot be memory buffer with bool type, for /// this reason return type is valarray instead of valarray. /// 1 means true, 0 means false. valarray operator!() const { BOOST_STATIC_ASSERT_MSG( is_fundamental::value, "This operator can be used with all OpenCL built-in scalar" " and vector types" ); valarray result(size()); BOOST_COMPUTE_FUNCTION(char, logical_not, (T x), { return !x; }); transform(begin(), end(), &result[0], logical_not); return result; } valarray& operator+=(const T&); valarray& operator-=(const T&); valarray& operator^=(const T&); valarray& operator&=(const T&); valarray& operator|=(const T&); valarray& operator<<=(const T&); valarray& operator>>=(const T&); valarray& operator*=(const valarray&); valarray& operator/=(const valarray&); valarray& operator%=(const valarray&); valarray& operator+=(const valarray&); valarray& operator-=(const valarray&); valarray& operator^=(const valarray&); valarray& operator&=(const valarray&); valarray& operator|=(const valarray&); valarray& operator<<=(const valarray&); valarray& operator>>=(const valarray&); ~valarray() { } size_t size() const { return m_buffer.size() / sizeof(T); } void resize(size_t size, T value = T()) { m_buffer = buffer(m_buffer.get_context(), size * sizeof(T)); fill(begin(), end(), value); } detail::buffer_value operator[](size_t index) { return *(begin() + static_cast(index)); } const detail::buffer_value operator[](size_t index) const { return *(begin() + static_cast(index)); } T (min)() const { return *(boost::compute::min_element(begin(), end())); } T (max)() const { return *(boost::compute::max_element(begin(), end())); } T sum() const { return boost::compute::accumulate(begin(), end(), T(0)); } template valarray apply(UnaryFunction function) const { valarray result(size()); transform(begin(), end(), result.begin(), function); return result; } const buffer& get_buffer() const { return m_buffer; } private: buffer_iterator begin() const { return buffer_iterator(m_buffer, 0); } buffer_iterator end() const { return buffer_iterator(m_buffer, size()); } private: buffer m_buffer; }; /// \internal_ #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(op, op_name, assert) \ template \ inline valarray& \ valarray::operator op##=(const T& val) \ { \ assert \ transform(begin(), end(), begin(), \ ::boost::compute::bind(op_name(), placeholders::_1, val)); \ return *this; \ } \ \ template \ inline valarray& \ valarray::operator op##=(const valarray &rhs) \ { \ assert \ transform(begin(), end(), rhs.begin(), begin(), op_name()); \ return *this; \ } /// \internal_ #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(op, op_name) \ BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(op, op_name, \ BOOST_STATIC_ASSERT_MSG( \ is_fundamental::value, \ "This operator can be used with all OpenCL built-in scalar" \ " and vector types" \ ); \ ) /// \internal_ /// For some operators class T can't be floating point type. /// See OpenCL specification, operators chapter. #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(op, op_name) \ BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(op, op_name, \ BOOST_STATIC_ASSERT_MSG( \ is_fundamental::value && \ !is_floating_point::type>::value, \ "This operator can be used with all OpenCL built-in scalar" \ " and vector types except the built-in scalar and vector float types" \ ); \ ) // defining operators BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(+, plus) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(-, minus) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(*, multiplies) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY(/, divides) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(^, bit_xor) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(&, bit_and) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(|, bit_or) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(<<, shift_left) BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP(>>, shift_right) // The remainder (%) operates on // integer scalar and integer vector data types only. // See OpenCL specification. BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT(%, modulus, BOOST_STATIC_ASSERT_MSG( is_integral::type>::value, "This operator can be used only with OpenCL built-in integer types" ); ) #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_ANY #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT_NO_FP #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPOUND_ASSIGNMENT /// \internal_ /// Macro for defining binary operators for valarray #define BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR(op, op_name, assert) \ template \ valarray operator op (const valarray& lhs, const valarray& rhs) \ { \ assert \ valarray result(lhs.size()); \ transform(buffer_iterator(lhs.get_buffer(), 0), \ buffer_iterator(lhs.get_buffer(), lhs.size()), \ buffer_iterator(rhs.get_buffer(), 0), \ buffer_iterator(result.get_buffer(), 0), \ op_name()); \ return result; \ } \ \ template \ valarray operator op (const T& val, const valarray& rhs) \ { \ assert \ valarray result(rhs.size()); \ transform(buffer_iterator(rhs.get_buffer(), 0), \ buffer_iterator(rhs.get_buffer(), rhs.size()), \ buffer_iterator(result.get_buffer(), 0), \ ::boost::compute::bind(op_name(), val, placeholders::_1)); \ return result; \ } \ \ template \ valarray operator op (const valarray& lhs, const T& val) \ { \ assert \ valarray result(lhs.size()); \ transform(buffer_iterator(lhs.get_buffer(), 0), \ buffer_iterator(lhs.get_buffer(), lhs.size()), \ buffer_iterator(result.get_buffer(), 0), \ ::boost::compute::bind(op_name(), placeholders::_1, val)); \ return result; \ } /// \internal_ #define BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(op, op_name) \ BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR(op, op_name, \ BOOST_STATIC_ASSERT_MSG( \ is_fundamental::value, \ "This operator can be used with all OpenCL built-in scalar" \ " and vector types" \ ); \ ) /// \internal_ /// For some operators class T can't be floating point type. /// See OpenCL specification, operators chapter. #define BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(op, op_name) \ BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR(op, op_name, \ BOOST_STATIC_ASSERT_MSG( \ is_fundamental::value && \ !is_floating_point::type>::value, \ "This operator can be used with all OpenCL built-in scalar" \ " and vector types except the built-in scalar and vector float types" \ ); \ ) // defining binary operators for valarray BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(+, plus) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(-, minus) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(*, multiplies) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY(/, divides) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(^, bit_xor) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(&, bit_and) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(|, bit_or) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(<<, shift_left) BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP(>>, shift_right) #undef BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_ANY #undef BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR_NO_FP #undef BOOST_COMPUTE_DEFINE_VALARRAY_BINARY_OPERATOR /// \internal_ /// Macro for defining valarray comparison operators. /// For return type valarray is used instead of valarray because /// in OpenCL there cannot be memory buffer with bool type. /// /// Note it's also used for defining binary logical operators (==, &&) #define BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(op, op_name) \ template \ valarray operator op (const valarray& lhs, const valarray& rhs) \ { \ BOOST_STATIC_ASSERT_MSG( \ is_fundamental::value, \ "This operator can be used with all OpenCL built-in scalar" \ " and vector types" \ ); \ valarray result(lhs.size()); \ transform(buffer_iterator(lhs.get_buffer(), 0), \ buffer_iterator(lhs.get_buffer(), lhs.size()), \ buffer_iterator(rhs.get_buffer(), 0), \ buffer_iterator(result.get_buffer(), 0), \ op_name()); \ return result; \ } \ \ template \ valarray operator op (const T& val, const valarray& rhs) \ { \ BOOST_STATIC_ASSERT_MSG( \ is_fundamental::value, \ "This operator can be used with all OpenCL built-in scalar" \ " and vector types" \ ); \ valarray result(rhs.size()); \ transform(buffer_iterator(rhs.get_buffer(), 0), \ buffer_iterator(rhs.get_buffer(), rhs.size()), \ buffer_iterator(result.get_buffer(), 0), \ ::boost::compute::bind(op_name(), val, placeholders::_1)); \ return result; \ } \ \ template \ valarray operator op (const valarray& lhs, const T& val) \ { \ BOOST_STATIC_ASSERT_MSG( \ is_fundamental::value, \ "This operator can be used with all OpenCL built-in scalar" \ " and vector types" \ ); \ valarray result(lhs.size()); \ transform(buffer_iterator(lhs.get_buffer(), 0), \ buffer_iterator(lhs.get_buffer(), lhs.size()), \ buffer_iterator(result.get_buffer(), 0), \ ::boost::compute::bind(op_name(), placeholders::_1, val)); \ return result; \ } BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(==, equal_to) BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(!=, not_equal_to) BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(>, greater) BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(<, less) BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(>=, greater_equal) BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(<=, less_equal) /// \internal_ /// Macro for defining binary logical operators for valarray. /// /// For return type valarray is used instead of valarray because /// in OpenCL there cannot be memory buffer with bool type. /// 1 means true, 0 means false. #define BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR(op, op_name) \ BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR(op, op_name) BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR(&&, logical_and) BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR(||, logical_or) #undef BOOST_COMPUTE_DEFINE_VALARRAY_LOGICAL_OPERATOR #undef BOOST_COMPUTE_DEFINE_VALARRAY_COMPARISON_OPERATOR } // end compute namespace } // end boost namespace #endif // BOOST_COMPUTE_CONTAINER_VALARRAY_HPP