//---------------------------------------------------------------------------// // 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_ARRAY_HPP #define BOOST_COMPUTE_CONTAINER_ARRAY_HPP #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace compute { /// \class array /// \brief A fixed-size container. /// /// The array container is very similar to the \ref vector container except /// its size is fixed at compile-time rather than being dynamically resizable /// at run-time. /// /// For example, to create a fixed-size array with eight values on the device: /// \code /// boost::compute::array values(context); /// \endcode /// /// The Boost.Compute \c array class provides a STL-like API and is modeled /// after the \c std::array class from the C++ standard library. /// /// \see \ref vector "vector" template class array { public: typedef T value_type; typedef std::size_t size_type; typedef ptrdiff_t difference_type; typedef detail::buffer_value reference; typedef const detail::buffer_value const_reference; typedef T* pointer; typedef const T* const_pointer; typedef buffer_iterator iterator; typedef buffer_iterator const_iterator; typedef std::reverse_iterator reverse_iterator; typedef std::reverse_iterator const_reverse_iterator; enum { static_size = N }; explicit array(const context &context = system::default_context()) : m_buffer(context, sizeof(T) * N) { } array(const array &other) : m_buffer(other.m_buffer.get_context(), sizeof(T) * N) { command_queue queue = default_queue(); boost::compute::copy(other.begin(), other.end(), begin(), queue); queue.finish(); } array(const boost::array &array, const context &context = system::default_context()) : m_buffer(context, sizeof(T) * N) { command_queue queue = default_queue(); boost::compute::copy(array.begin(), array.end(), begin(), queue); queue.finish(); } array(const array &other, const command_queue &queue) : m_buffer(other.m_buffer.get_context(), sizeof(T) * N) { boost::compute::copy(other.begin(), other.end(), begin(), queue); } array& operator=(const array &other) { if(this != &other){ command_queue queue = default_queue(); boost::compute::copy(other.begin(), other.end(), begin(), queue); queue.finish(); } return *this; } array& operator=(const boost::array &array) { command_queue queue = default_queue(); boost::compute::copy(array.begin(), array.end(), begin(), queue); queue.finish(); return *this; } ~array() { } iterator begin() { return buffer_iterator(m_buffer, 0); } const_iterator begin() const { return buffer_iterator(m_buffer, 0); } const_iterator cbegin() const { return begin(); } iterator end() { return buffer_iterator(m_buffer, N); } const_iterator end() const { return buffer_iterator(m_buffer, N); } const_iterator cend() const { return end(); } reverse_iterator rbegin() { return reverse_iterator(end() - 1); } const_reverse_iterator rbegin() const { return reverse_iterator(end() - 1); } const_reverse_iterator crbegin() const { return rbegin(); } reverse_iterator rend() { return reverse_iterator(begin() - 1); } const_reverse_iterator rend() const { return reverse_iterator(begin() - 1); } const_reverse_iterator crend() const { return rend(); } size_type size() const { return N; } bool empty() const { return N == 0; } size_type max_size() const { return N; } reference operator[](size_type index) { return *(begin() + static_cast(index)); } const_reference operator[](size_type index) const { return *(begin() + static_cast(index)); } reference at(size_type index) { if(index >= N){ BOOST_THROW_EXCEPTION(std::out_of_range("index out of range")); } return operator[](index); } const_reference at(size_type index) const { if(index >= N){ BOOST_THROW_EXCEPTION(std::out_of_range("index out of range")); } return operator[](index); } reference front() { return *begin(); } const_reference front() const { return *begin(); } reference back() { return *(end() - static_cast(1)); } const_reference back() const { return *(end() - static_cast(1)); } void fill(const value_type &value, const command_queue &queue) { ::boost::compute::fill(begin(), end(), value, queue); } void swap(array &other, const command_queue &queue) { ::boost::compute::swap_ranges(begin(), end(), other.begin(), queue); } void fill(const value_type &value) { command_queue queue = default_queue(); ::boost::compute::fill(begin(), end(), value, queue); queue.finish(); } void swap(array &other) { command_queue queue = default_queue(); ::boost::compute::swap_ranges(begin(), end(), other.begin(), queue); queue.finish(); } const buffer& get_buffer() const { return m_buffer; } private: buffer m_buffer; command_queue default_queue() const { const context &context = m_buffer.get_context(); command_queue queue(context, context.get_device()); return queue; } }; namespace detail { // set_kernel_arg specialization for array template struct set_kernel_arg > { void operator()(kernel &kernel_, size_t index, const array &array) { kernel_.set_arg(index, array.get_buffer()); } }; // for capturing array with BOOST_COMPUTE_CLOSURE() template struct capture_traits > { static std::string type_name() { return std::string("__global ") + ::boost::compute::type_name() + "*"; } }; // meta_kernel streaming operator for array template meta_kernel& operator<<(meta_kernel &k, const array &array) { return k << k.get_buffer_identifier(array.get_buffer()); } } // end detail namespace } // end compute namespace } // end boost namespace #endif // BOOST_COMPUTE_CONTAINER_ARRAY_HPP