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_VECTOR_HPP
12 #define BOOST_COMPUTE_CONTAINER_VECTOR_HPP
13 
14 #include <vector>
15 #include <cstddef>
16 #include <iterator>
17 #include <exception>
18 
19 #include <boost/throw_exception.hpp>
20 
21 #include <boost/compute/config.hpp>
22 
23 #ifndef BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST
24 #include <initializer_list>
25 #endif
26 
27 #include <boost/compute/buffer.hpp>
28 #include <boost/compute/device.hpp>
29 #include <boost/compute/system.hpp>
30 #include <boost/compute/context.hpp>
31 #include <boost/compute/command_queue.hpp>
32 #include <boost/compute/algorithm/copy.hpp>
33 #include <boost/compute/algorithm/copy_n.hpp>
34 #include <boost/compute/algorithm/fill_n.hpp>
35 #include <boost/compute/allocator/buffer_allocator.hpp>
36 #include <boost/compute/iterator/buffer_iterator.hpp>
37 #include <boost/compute/type_traits/detail/capture_traits.hpp>
38 #include <boost/compute/detail/buffer_value.hpp>
39 #include <boost/compute/detail/iterator_range_size.hpp>
40 
41 namespace boost {
42 namespace compute {
43 
44 /// \class vector
45 /// \brief A resizable array of values.
46 ///
47 /// The vector<T> class stores a dynamic array of values. Internally, the data
48 /// is stored in an OpenCL buffer object.
49 ///
50 /// The vector class is the prefered container for storing and accessing data
51 /// on a compute device. In most cases it should be used instead of directly
52 /// dealing with buffer objects. If the undelying buffer is needed, it can be
53 /// accessed with the get_buffer() method.
54 ///
55 /// The internal storage is allocated in a specific OpenCL context which is
56 /// passed as an argument to the constructor when the vector is created.
57 ///
58 /// For example, to create a vector on the device containing space for ten
59 /// \c int values:
60 /// \code
61 /// boost::compute::vector<int> vec(10, context);
62 /// \endcode
63 ///
64 /// Allocation and data transfer can also be performed in a single step:
65 /// \code
66 /// // values on the host
67 /// int data[] = { 1, 2, 3, 4 };
68 ///
69 /// // create a vector of size four and copy the values from data
70 /// boost::compute::vector<int> vec(data, data + 4, queue);
71 /// \endcode
72 ///
73 /// The Boost.Compute \c vector class provides a STL-like API and is modeled
74 /// after the \c std::vector class from the C++ standard library. It can be
75 /// used with any of the STL-like algorithms provided by Boost.Compute
76 /// including \c copy(), \c transform(), and \c sort() (among many others).
77 ///
78 /// For example:
79 /// \code
80 /// // a vector on a compute device
81 /// boost::compute::vector<float> vec = ...
82 ///
83 /// // copy data to the vector from a host std:vector
84 /// boost::compute::copy(host_vec.begin(), host_vec.end(), vec.begin(), queue);
85 ///
86 /// // copy data from the vector to a host std::vector
87 /// boost::compute::copy(vec.begin(), vec.end(), host_vec.begin(), queue);
88 ///
89 /// // sort the values in the vector
90 /// boost::compute::sort(vec.begin(), vec.end(), queue);
91 ///
92 /// // calculate the sum of the values in the vector (also see reduce())
93 /// float sum = boost::compute::accumulate(vec.begin(), vec.end(), 0, queue);
94 ///
95 /// // reverse the values in the vector
96 /// boost::compute::reverse(vec.begin(), vec.end(), queue);
97 ///
98 /// // fill the vector with ones
99 /// boost::compute::fill(vec.begin(), vec.end(), 1, queue);
100 /// \endcode
101 ///
102 /// \see \ref array "array<T, N>", buffer
103 template<class T, class Alloc = buffer_allocator<T> >
104 class vector
105 {
106 public:
107     typedef T value_type;
108     typedef Alloc allocator_type;
109     typedef typename allocator_type::size_type size_type;
110     typedef typename allocator_type::difference_type difference_type;
111     typedef detail::buffer_value<T> reference;
112     typedef const detail::buffer_value<T> const_reference;
113     typedef typename allocator_type::pointer pointer;
114     typedef typename allocator_type::const_pointer const_pointer;
115     typedef buffer_iterator<T> iterator;
116     typedef buffer_iterator<T> const_iterator;
117     typedef std::reverse_iterator<iterator> reverse_iterator;
118     typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
119 
120     /// Creates an empty vector in \p context.
vector(const context & context=system::default_context ())121     explicit vector(const context &context = system::default_context())
122         : m_size(0),
123           m_allocator(context)
124     {
125         m_data = m_allocator.allocate(_minimum_capacity());
126     }
127 
128     /// Creates a vector with space for \p count elements in \p context.
129     ///
130     /// Note that unlike \c std::vector's constructor, this will not initialize
131     /// the values in the container. Either call the vector constructor which
132     /// takes a value to initialize with or use the fill() algorithm to set
133     /// the initial values.
134     ///
135     /// For example:
136     /// \code
137     /// // create a vector on the device with space for ten ints
138     /// boost::compute::vector<int> vec(10, context);
139     /// \endcode
vector(size_type count,const context & context=system::default_context ())140     explicit vector(size_type count,
141                     const context &context = system::default_context())
142         : m_size(count),
143           m_allocator(context)
144     {
145         m_data = m_allocator.allocate((std::max)(count, _minimum_capacity()));
146     }
147 
148     /// Creates a vector with space for \p count elements and sets each equal
149     /// to \p value.
150     ///
151     /// For example:
152     /// \code
153     /// // creates a vector with four values set to nine (e.g. [9, 9, 9, 9]).
154     /// boost::compute::vector<int> vec(4, 9, queue);
155     /// \endcode
vector(size_type count,const T & value,command_queue & queue=system::default_queue ())156     vector(size_type count,
157            const T &value,
158            command_queue &queue = system::default_queue())
159         : m_size(count),
160           m_allocator(queue.get_context())
161     {
162         m_data = m_allocator.allocate((std::max)(count, _minimum_capacity()));
163 
164         ::boost::compute::fill_n(begin(), count, value, queue);
165     }
166 
167     /// Creates a vector with space for the values in the range [\p first,
168     /// \p last) and copies them into the vector with \p queue.
169     ///
170     /// For example:
171     /// \code
172     /// // values on the host
173     /// int data[] = { 1, 2, 3, 4 };
174     ///
175     /// // create a vector of size four and copy the values from data
176     /// boost::compute::vector<int> vec(data, data + 4, queue);
177     /// \endcode
178     template<class InputIterator>
vector(InputIterator first,InputIterator last,command_queue & queue=system::default_queue ())179     vector(InputIterator first,
180            InputIterator last,
181            command_queue &queue = system::default_queue())
182         : m_size(detail::iterator_range_size(first, last)),
183           m_allocator(queue.get_context())
184     {
185         m_data = m_allocator.allocate((std::max)(m_size, _minimum_capacity()));
186 
187         ::boost::compute::copy(first, last, begin(), queue);
188     }
189 
190     /// Creates a new vector and copies the values from \p other.
vector(const vector & other,command_queue & queue=system::default_queue ())191     vector(const vector &other,
192            command_queue &queue = system::default_queue())
193         : m_size(other.m_size),
194           m_allocator(other.m_allocator)
195     {
196         m_data = m_allocator.allocate((std::max)(m_size, _minimum_capacity()));
197 
198         if(!other.empty()){
199             if(other.get_buffer().get_context() != queue.get_context()){
200                 command_queue other_queue = other.default_queue();
201                 ::boost::compute::copy(other.begin(), other.end(), begin(), other_queue);
202                 other_queue.finish();
203             }
204             else {
205                 ::boost::compute::copy(other.begin(), other.end(), begin(), queue);
206                 queue.finish();
207             }
208         }
209     }
210 
211     /// Creates a new vector and copies the values from \p other.
212     template<class OtherAlloc>
vector(const vector<T,OtherAlloc> & other,command_queue & queue=system::default_queue ())213     vector(const vector<T, OtherAlloc> &other,
214            command_queue &queue = system::default_queue())
215         : m_size(other.size()),
216           m_allocator(queue.get_context())
217     {
218         m_data = m_allocator.allocate((std::max)(m_size, _minimum_capacity()));
219 
220         if(!other.empty()){
221             ::boost::compute::copy(other.begin(), other.end(), begin(), queue);
222             queue.finish();
223         }
224     }
225 
226     /// Creates a new vector and copies the values from \p vector.
227     template<class OtherAlloc>
vector(const std::vector<T,OtherAlloc> & vector,command_queue & queue=system::default_queue ())228     vector(const std::vector<T, OtherAlloc> &vector,
229            command_queue &queue = system::default_queue())
230         : m_size(vector.size()),
231           m_allocator(queue.get_context())
232     {
233         m_data = m_allocator.allocate((std::max)(m_size, _minimum_capacity()));
234 
235         ::boost::compute::copy(vector.begin(), vector.end(), begin(), queue);
236     }
237 
238     #ifndef BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST
vector(std::initializer_list<T> list,command_queue & queue=system::default_queue ())239     vector(std::initializer_list<T> list,
240            command_queue &queue = system::default_queue())
241         : m_size(list.size()),
242           m_allocator(queue.get_context())
243     {
244         m_data = m_allocator.allocate((std::max)(m_size, _minimum_capacity()));
245 
246         ::boost::compute::copy(list.begin(), list.end(), begin(), queue);
247     }
248     #endif // BOOST_COMPUTE_NO_HDR_INITIALIZER_LIST
249 
operator =(const vector & other)250     vector& operator=(const vector &other)
251     {
252         if(this != &other){
253             command_queue queue = default_queue();
254             resize(other.size(), queue);
255             ::boost::compute::copy(other.begin(), other.end(), begin(), queue);
256             queue.finish();
257         }
258 
259         return *this;
260     }
261 
262     template<class OtherAlloc>
operator =(const vector<T,OtherAlloc> & other)263     vector& operator=(const vector<T, OtherAlloc> &other)
264     {
265         command_queue queue = default_queue();
266         resize(other.size(), queue);
267         ::boost::compute::copy(other.begin(), other.end(), begin(), queue);
268         queue.finish();
269 
270         return *this;
271     }
272 
273     template<class OtherAlloc>
operator =(const std::vector<T,OtherAlloc> & vector)274     vector& operator=(const std::vector<T, OtherAlloc> &vector)
275     {
276         command_queue queue = default_queue();
277         resize(vector.size(), queue);
278         ::boost::compute::copy(vector.begin(), vector.end(), begin(), queue);
279         queue.finish();
280         return *this;
281     }
282 
283     #ifndef BOOST_COMPUTE_NO_RVALUE_REFERENCES
284     /// Move-constructs a new vector from \p other.
vector(vector && other)285     vector(vector&& other)
286         : m_data(std::move(other.m_data)),
287           m_size(other.m_size),
288           m_allocator(std::move(other.m_allocator))
289     {
290         other.m_size = 0;
291     }
292 
293     /// Move-assigns the data from \p other to \c *this.
operator =(vector && other)294     vector& operator=(vector&& other)
295     {
296         if(capacity() > 0){
297             m_allocator.deallocate(m_data, capacity());
298         }
299 
300         m_data = std::move(other.m_data);
301         m_size = other.m_size;
302         m_allocator = std::move(other.m_allocator);
303 
304         other.m_size = 0;
305 
306         return *this;
307     }
308     #endif // BOOST_COMPUTE_NO_RVALUE_REFERENCES
309 
310     /// Destroys the vector object.
~vector()311     ~vector()
312     {
313         if(capacity() > 0){
314             m_allocator.deallocate(m_data, capacity());
315         }
316     }
317 
begin()318     iterator begin()
319     {
320         return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), 0);
321     }
322 
begin() const323     const_iterator begin() const
324     {
325         return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), 0);
326     }
327 
cbegin() const328     const_iterator cbegin() const
329     {
330         return begin();
331     }
332 
end()333     iterator end()
334     {
335         return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), m_size);
336     }
337 
end() const338     const_iterator end() const
339     {
340         return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), m_size);
341     }
342 
cend() const343     const_iterator cend() const
344     {
345         return end();
346     }
347 
rbegin()348     reverse_iterator rbegin()
349     {
350         return reverse_iterator(end() - 1);
351     }
352 
rbegin() const353     const_reverse_iterator rbegin() const
354     {
355         return reverse_iterator(end() - 1);
356     }
357 
crbegin() const358     const_reverse_iterator crbegin() const
359     {
360         return rbegin();
361     }
362 
rend()363     reverse_iterator rend()
364     {
365         return reverse_iterator(begin() - 1);
366     }
367 
rend() const368     const_reverse_iterator rend() const
369     {
370         return reverse_iterator(begin() - 1);
371     }
372 
crend() const373     const_reverse_iterator crend() const
374     {
375         return rend();
376     }
377 
378     /// Returns the number of elements in the vector.
size() const379     size_type size() const
380     {
381         return m_size;
382     }
383 
max_size() const384     size_type max_size() const
385     {
386         return m_allocator.max_size();
387     }
388 
389     /// Resizes the vector to \p size.
resize(size_type size,command_queue & queue)390     void resize(size_type size, command_queue &queue)
391     {
392         if(size <= capacity()){
393             m_size = size;
394         }
395         else {
396             // allocate new buffer
397             pointer new_data =
398                 m_allocator.allocate(
399                     static_cast<size_type>(
400                         static_cast<float>(size) * _growth_factor()
401                     )
402                 );
403 
404             if(capacity() > 0)
405             {
406                 // copy old values to the new buffer
407                 ::boost::compute::copy(m_data, m_data + m_size, new_data, queue);
408 
409                 // free old memory
410                 m_allocator.deallocate(m_data, capacity());
411             }
412 
413             // set new data and size
414             m_data = new_data;
415             m_size = size;
416         }
417     }
418 
419     /// \overload
resize(size_type size)420     void resize(size_type size)
421     {
422         command_queue queue = default_queue();
423         resize(size, queue);
424         queue.finish();
425     }
426 
427     /// Returns \c true if the vector is empty.
empty() const428     bool empty() const
429     {
430         return m_size == 0;
431     }
432 
433     /// Returns the capacity of the vector.
capacity() const434     size_type capacity() const
435     {
436         if(m_data == pointer()) // null pointer check
437         {
438             return 0;
439         }
440         return m_data.get_buffer().size() / sizeof(T);
441     }
442 
reserve(size_type size,command_queue & queue)443     void reserve(size_type size, command_queue &queue)
444     {
445         if(size > max_size()){
446             throw std::length_error("vector::reserve");
447         }
448         if(capacity() < size){
449             // allocate new buffer
450             pointer new_data =
451                 m_allocator.allocate(
452                     static_cast<size_type>(
453                         static_cast<float>(size) * _growth_factor()
454                     )
455                 );
456 
457             if(capacity() > 0)
458             {
459                 // copy old values to the new buffer
460                 ::boost::compute::copy(m_data, m_data + m_size, new_data, queue);
461 
462                 // free old memory
463                 m_allocator.deallocate(m_data, capacity());
464             }
465 
466             // set new data
467             m_data = new_data;
468         }
469     }
470 
reserve(size_type size)471     void reserve(size_type size)
472     {
473         command_queue queue = default_queue();
474         reserve(size, queue);
475         queue.finish();
476     }
477 
shrink_to_fit(command_queue & queue)478     void shrink_to_fit(command_queue &queue)
479     {
480         pointer old_data = m_data;
481         m_data = pointer(); // null pointer
482         if(m_size > 0)
483         {
484             // allocate new buffer
485             m_data = m_allocator.allocate(m_size);
486 
487             // copy old values to the new buffer
488             ::boost::compute::copy(old_data, old_data + m_size, m_data, queue);
489         }
490 
491         if(capacity() > 0)
492         {
493             // free old memory
494             m_allocator.deallocate(old_data, capacity());
495         }
496     }
497 
shrink_to_fit()498     void shrink_to_fit()
499     {
500         command_queue queue = default_queue();
501         shrink_to_fit(queue);
502         queue.finish();
503     }
504 
operator [](size_type index)505     reference operator[](size_type index)
506     {
507         return *(begin() + static_cast<difference_type>(index));
508     }
509 
operator [](size_type index) const510     const_reference operator[](size_type index) const
511     {
512         return *(begin() + static_cast<difference_type>(index));
513     }
514 
at(size_type index)515     reference at(size_type index)
516     {
517         if(index >= size()){
518             BOOST_THROW_EXCEPTION(std::out_of_range("index out of range"));
519         }
520 
521         return operator[](index);
522     }
523 
at(size_type index) const524     const_reference at(size_type index) const
525     {
526         if(index >= size()){
527             BOOST_THROW_EXCEPTION(std::out_of_range("index out of range"));
528         }
529 
530         return operator[](index);
531     }
532 
front()533     reference front()
534     {
535         return *begin();
536     }
537 
front() const538     const_reference front() const
539     {
540         return *begin();
541     }
542 
back()543     reference back()
544     {
545         return *(end() - static_cast<difference_type>(1));
546     }
547 
back() const548     const_reference back() const
549     {
550         return *(end() - static_cast<difference_type>(1));
551     }
552 
553     template<class InputIterator>
assign(InputIterator first,InputIterator last,command_queue & queue)554     void assign(InputIterator first,
555                 InputIterator last,
556                 command_queue &queue)
557     {
558         // resize vector for new contents
559         resize(detail::iterator_range_size(first, last), queue);
560 
561         // copy values into the vector
562         ::boost::compute::copy(first, last, begin(), queue);
563     }
564 
565     template<class InputIterator>
assign(InputIterator first,InputIterator last)566     void assign(InputIterator first, InputIterator last)
567     {
568         command_queue queue = default_queue();
569         assign(first, last, queue);
570         queue.finish();
571     }
572 
assign(size_type n,const T & value,command_queue & queue)573     void assign(size_type n, const T &value, command_queue &queue)
574     {
575         // resize vector for new contents
576         resize(n, queue);
577 
578         // fill vector with value
579         ::boost::compute::fill_n(begin(), n, value, queue);
580     }
581 
assign(size_type n,const T & value)582     void assign(size_type n, const T &value)
583     {
584         command_queue queue = default_queue();
585         assign(n, value, queue);
586         queue.finish();
587     }
588 
589     /// Inserts \p value at the end of the vector (resizing if neccessary).
590     ///
591     /// Note that calling \c push_back() to insert data values one at a time
592     /// is inefficient as there is a non-trivial overhead in performing a data
593     /// transfer to the device. It is usually better to store a set of values
594     /// on the host (for example, in a \c std::vector) and then transfer them
595     /// in bulk using the \c insert() method or the copy() algorithm.
push_back(const T & value,command_queue & queue)596     void push_back(const T &value, command_queue &queue)
597     {
598         insert(end(), value, queue);
599     }
600 
601     /// \overload
push_back(const T & value)602     void push_back(const T &value)
603     {
604         command_queue queue = default_queue();
605         push_back(value, queue);
606         queue.finish();
607     }
608 
pop_back(command_queue & queue)609     void pop_back(command_queue &queue)
610     {
611         resize(size() - 1, queue);
612     }
613 
pop_back()614     void pop_back()
615     {
616         command_queue queue = default_queue();
617         pop_back(queue);
618         queue.finish();
619     }
620 
insert(iterator position,const T & value,command_queue & queue)621     iterator insert(iterator position, const T &value, command_queue &queue)
622     {
623         if(position == end()){
624             resize(m_size + 1, queue);
625             position = begin() + position.get_index();
626             ::boost::compute::copy_n(&value, 1, position, queue);
627         }
628         else {
629             ::boost::compute::vector<T, Alloc> tmp(position, end(), queue);
630             resize(m_size + 1, queue);
631             position = begin() + position.get_index();
632             ::boost::compute::copy_n(&value, 1, position, queue);
633             ::boost::compute::copy(tmp.begin(), tmp.end(), position + 1, queue);
634         }
635 
636         return position + 1;
637     }
638 
insert(iterator position,const T & value)639     iterator insert(iterator position, const T &value)
640     {
641         command_queue queue = default_queue();
642         iterator iter = insert(position, value, queue);
643         queue.finish();
644         return iter;
645     }
646 
insert(iterator position,size_type count,const T & value,command_queue & queue)647     void insert(iterator position,
648                 size_type count,
649                 const T &value,
650                 command_queue &queue)
651     {
652         ::boost::compute::vector<T, Alloc> tmp(position, end(), queue);
653         resize(size() + count, queue);
654 
655         position = begin() + position.get_index();
656 
657         ::boost::compute::fill_n(position, count, value, queue);
658         ::boost::compute::copy(
659             tmp.begin(),
660             tmp.end(),
661             position + static_cast<difference_type>(count),
662             queue
663         );
664     }
665 
insert(iterator position,size_type count,const T & value)666     void insert(iterator position, size_type count, const T &value)
667     {
668         command_queue queue = default_queue();
669         insert(position, count, value, queue);
670         queue.finish();
671     }
672 
673     /// Inserts the values in the range [\p first, \p last) into the vector at
674     /// \p position using \p queue.
675     template<class InputIterator>
insert(iterator position,InputIterator first,InputIterator last,command_queue & queue)676     void insert(iterator position,
677                 InputIterator first,
678                 InputIterator last,
679                 command_queue &queue)
680     {
681         ::boost::compute::vector<T, Alloc> tmp(position, end(), queue);
682 
683         size_type count = detail::iterator_range_size(first, last);
684         resize(size() + count, queue);
685 
686         position = begin() + position.get_index();
687 
688         ::boost::compute::copy(first, last, position, queue);
689         ::boost::compute::copy(
690             tmp.begin(),
691             tmp.end(),
692             position + static_cast<difference_type>(count),
693             queue
694         );
695     }
696 
697     /// \overload
698     template<class InputIterator>
insert(iterator position,InputIterator first,InputIterator last)699     void insert(iterator position, InputIterator first, InputIterator last)
700     {
701         command_queue queue = default_queue();
702         insert(position, first, last, queue);
703         queue.finish();
704     }
705 
erase(iterator position,command_queue & queue)706     iterator erase(iterator position, command_queue &queue)
707     {
708         return erase(position, position + 1, queue);
709     }
710 
erase(iterator position)711     iterator erase(iterator position)
712     {
713         command_queue queue = default_queue();
714         iterator iter = erase(position, queue);
715         queue.finish();
716         return iter;
717     }
718 
erase(iterator first,iterator last,command_queue & queue)719     iterator erase(iterator first, iterator last, command_queue &queue)
720     {
721         if(last != end()){
722             ::boost::compute::vector<T, Alloc> tmp(last, end(), queue);
723             ::boost::compute::copy(tmp.begin(), tmp.end(), first, queue);
724         }
725 
726         difference_type count = std::distance(first, last);
727         resize(size() - static_cast<size_type>(count), queue);
728 
729         return begin() + first.get_index() + count;
730     }
731 
erase(iterator first,iterator last)732     iterator erase(iterator first, iterator last)
733     {
734         command_queue queue = default_queue();
735         iterator iter = erase(first, last, queue);
736         queue.finish();
737         return iter;
738     }
739 
740     /// Swaps the contents of \c *this with \p other.
swap(vector & other)741     void swap(vector &other)
742     {
743         std::swap(m_data, other.m_data);
744         std::swap(m_size, other.m_size);
745         std::swap(m_allocator, other.m_allocator);
746     }
747 
748     /// Removes all elements from the vector.
clear()749     void clear()
750     {
751         m_size = 0;
752     }
753 
get_allocator() const754     allocator_type get_allocator() const
755     {
756         return m_allocator;
757     }
758 
759     /// Returns the underlying buffer.
get_buffer() const760     const buffer& get_buffer() const
761     {
762         return m_data.get_buffer();
763     }
764 
765     /// \internal_
766     ///
767     /// Returns a command queue usable to issue commands for the vector's
768     /// memory buffer. This is used when a member function is called without
769     /// specifying an existing command queue to use.
default_queue() const770     command_queue default_queue() const
771     {
772         const context &context = m_allocator.get_context();
773         command_queue queue(context, context.get_device());
774         return queue;
775     }
776 
777 private:
778     /// \internal_
_minimum_capacity() const779     BOOST_CONSTEXPR size_type _minimum_capacity() const { return 4; }
780 
781     /// \internal_
_growth_factor() const782     BOOST_CONSTEXPR float _growth_factor() const { return 1.5; }
783 
784 private:
785     pointer m_data;
786     size_type m_size;
787     allocator_type m_allocator;
788 };
789 
790 namespace detail {
791 
792 // set_kernel_arg specialization for vector<T>
793 template<class T, class Alloc>
794 struct set_kernel_arg<vector<T, Alloc> >
795 {
operator ()boost::compute::detail::set_kernel_arg796     void operator()(kernel &kernel_, size_t index, const vector<T, Alloc> &vector)
797     {
798         kernel_.set_arg(index, vector.get_buffer());
799     }
800 };
801 
802 // for capturing vector<T> with BOOST_COMPUTE_CLOSURE()
803 template<class T, class Alloc>
804 struct capture_traits<vector<T, Alloc> >
805 {
type_nameboost::compute::detail::capture_traits806     static std::string type_name()
807     {
808         return std::string("__global ") + ::boost::compute::type_name<T>() + "*";
809     }
810 };
811 
812 // meta_kernel streaming operator for vector<T>
813 template<class T, class Alloc>
operator <<(meta_kernel & k,const vector<T,Alloc> & vector)814 meta_kernel& operator<<(meta_kernel &k, const vector<T, Alloc> &vector)
815 {
816   return k << k.get_buffer_identifier<T>(vector.get_buffer());
817 }
818 
819 } // end detail namespace
820 } // end compute namespace
821 } // end boost namespace
822 
823 #endif // BOOST_COMPUTE_CONTAINER_VECTOR_HPP
824