]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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. | |
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 | |
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 | |
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> | |
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. | |
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> | |
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> | |
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 | |
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 | ||
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> | |
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> | |
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. | |
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. | |
294 | vector& operator=(vector&& other) | |
295 | { | |
296 | if(m_size){ | |
297 | m_allocator.deallocate(m_data, m_size); | |
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. | |
311 | ~vector() | |
312 | { | |
313 | if(m_size){ | |
314 | m_allocator.deallocate(m_data, m_size); | |
315 | } | |
316 | } | |
317 | ||
318 | iterator begin() | |
319 | { | |
320 | return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), 0); | |
321 | } | |
322 | ||
323 | const_iterator begin() const | |
324 | { | |
325 | return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), 0); | |
326 | } | |
327 | ||
328 | const_iterator cbegin() const | |
329 | { | |
330 | return begin(); | |
331 | } | |
332 | ||
333 | iterator end() | |
334 | { | |
335 | return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), m_size); | |
336 | } | |
337 | ||
338 | const_iterator end() const | |
339 | { | |
340 | return ::boost::compute::make_buffer_iterator<T>(m_data.get_buffer(), m_size); | |
341 | } | |
342 | ||
343 | const_iterator cend() const | |
344 | { | |
345 | return end(); | |
346 | } | |
347 | ||
348 | reverse_iterator rbegin() | |
349 | { | |
350 | return reverse_iterator(end() - 1); | |
351 | } | |
352 | ||
353 | const_reverse_iterator rbegin() const | |
354 | { | |
355 | return reverse_iterator(end() - 1); | |
356 | } | |
357 | ||
358 | const_reverse_iterator crbegin() const | |
359 | { | |
360 | return rbegin(); | |
361 | } | |
362 | ||
363 | reverse_iterator rend() | |
364 | { | |
365 | return reverse_iterator(begin() - 1); | |
366 | } | |
367 | ||
368 | const_reverse_iterator rend() const | |
369 | { | |
370 | return reverse_iterator(begin() - 1); | |
371 | } | |
372 | ||
373 | const_reverse_iterator crend() const | |
374 | { | |
375 | return rend(); | |
376 | } | |
377 | ||
378 | /// Returns the number of elements in the vector. | |
379 | size_type size() const | |
380 | { | |
381 | return m_size; | |
382 | } | |
383 | ||
384 | size_type max_size() const | |
385 | { | |
386 | return m_allocator.max_size(); | |
387 | } | |
388 | ||
389 | /// Resizes the vector to \p size. | |
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 | // copy old values to the new buffer | |
405 | ::boost::compute::copy(m_data, m_data + m_size, new_data, queue); | |
406 | ||
407 | // free old memory | |
408 | m_allocator.deallocate(m_data, m_size); | |
409 | ||
410 | // set new data and size | |
411 | m_data = new_data; | |
412 | m_size = size; | |
413 | } | |
414 | } | |
415 | ||
416 | /// \overload | |
417 | void resize(size_type size) | |
418 | { | |
419 | command_queue queue = default_queue(); | |
420 | resize(size, queue); | |
421 | queue.finish(); | |
422 | } | |
423 | ||
424 | /// Returns \c true if the vector is empty. | |
425 | bool empty() const | |
426 | { | |
427 | return m_size == 0; | |
428 | } | |
429 | ||
430 | /// Returns the capacity of the vector. | |
431 | size_type capacity() const | |
432 | { | |
433 | return m_data.get_buffer().size() / sizeof(T); | |
434 | } | |
435 | ||
436 | void reserve(size_type size, command_queue &queue) | |
437 | { | |
438 | (void) size; | |
439 | (void) queue; | |
440 | } | |
441 | ||
442 | void reserve(size_type size) | |
443 | { | |
444 | command_queue queue = default_queue(); | |
445 | reserve(size, queue); | |
446 | queue.finish(); | |
447 | } | |
448 | ||
449 | void shrink_to_fit(command_queue &queue) | |
450 | { | |
451 | (void) queue; | |
452 | } | |
453 | ||
454 | void shrink_to_fit() | |
455 | { | |
456 | command_queue queue = default_queue(); | |
457 | shrink_to_fit(queue); | |
458 | queue.finish(); | |
459 | } | |
460 | ||
461 | reference operator[](size_type index) | |
462 | { | |
463 | return *(begin() + static_cast<difference_type>(index)); | |
464 | } | |
465 | ||
466 | const_reference operator[](size_type index) const | |
467 | { | |
468 | return *(begin() + static_cast<difference_type>(index)); | |
469 | } | |
470 | ||
471 | reference at(size_type index) | |
472 | { | |
473 | if(index >= size()){ | |
474 | BOOST_THROW_EXCEPTION(std::out_of_range("index out of range")); | |
475 | } | |
476 | ||
477 | return operator[](index); | |
478 | } | |
479 | ||
480 | const_reference at(size_type index) const | |
481 | { | |
482 | if(index >= size()){ | |
483 | BOOST_THROW_EXCEPTION(std::out_of_range("index out of range")); | |
484 | } | |
485 | ||
486 | return operator[](index); | |
487 | } | |
488 | ||
489 | reference front() | |
490 | { | |
491 | return *begin(); | |
492 | } | |
493 | ||
494 | const_reference front() const | |
495 | { | |
496 | return *begin(); | |
497 | } | |
498 | ||
499 | reference back() | |
500 | { | |
501 | return *(end() - static_cast<difference_type>(1)); | |
502 | } | |
503 | ||
504 | const_reference back() const | |
505 | { | |
506 | return *(end() - static_cast<difference_type>(1)); | |
507 | } | |
508 | ||
509 | template<class InputIterator> | |
510 | void assign(InputIterator first, | |
511 | InputIterator last, | |
512 | command_queue &queue) | |
513 | { | |
514 | // resize vector for new contents | |
515 | resize(detail::iterator_range_size(first, last), queue); | |
516 | ||
517 | // copy values into the vector | |
518 | ::boost::compute::copy(first, last, begin(), queue); | |
519 | } | |
520 | ||
521 | template<class InputIterator> | |
522 | void assign(InputIterator first, InputIterator last) | |
523 | { | |
524 | command_queue queue = default_queue(); | |
525 | assign(first, last, queue); | |
526 | queue.finish(); | |
527 | } | |
528 | ||
529 | void assign(size_type n, const T &value, command_queue &queue) | |
530 | { | |
531 | // resize vector for new contents | |
532 | resize(n, queue); | |
533 | ||
534 | // fill vector with value | |
535 | ::boost::compute::fill_n(begin(), n, value, queue); | |
536 | } | |
537 | ||
538 | void assign(size_type n, const T &value) | |
539 | { | |
540 | command_queue queue = default_queue(); | |
541 | assign(n, value, queue); | |
542 | queue.finish(); | |
543 | } | |
544 | ||
545 | /// Inserts \p value at the end of the vector (resizing if neccessary). | |
546 | /// | |
547 | /// Note that calling \c push_back() to insert data values one at a time | |
548 | /// is inefficient as there is a non-trivial overhead in performing a data | |
549 | /// transfer to the device. It is usually better to store a set of values | |
550 | /// on the host (for example, in a \c std::vector) and then transfer them | |
551 | /// in bulk using the \c insert() method or the copy() algorithm. | |
552 | void push_back(const T &value, command_queue &queue) | |
553 | { | |
554 | insert(end(), value, queue); | |
555 | } | |
556 | ||
557 | /// \overload | |
558 | void push_back(const T &value) | |
559 | { | |
560 | command_queue queue = default_queue(); | |
561 | push_back(value, queue); | |
562 | queue.finish(); | |
563 | } | |
564 | ||
565 | void pop_back(command_queue &queue) | |
566 | { | |
567 | resize(size() - 1, queue); | |
568 | } | |
569 | ||
570 | void pop_back() | |
571 | { | |
572 | command_queue queue = default_queue(); | |
573 | pop_back(queue); | |
574 | queue.finish(); | |
575 | } | |
576 | ||
577 | iterator insert(iterator position, const T &value, command_queue &queue) | |
578 | { | |
579 | if(position == end()){ | |
580 | resize(m_size + 1, queue); | |
581 | position = begin() + position.get_index(); | |
582 | ::boost::compute::copy_n(&value, 1, position, queue); | |
583 | } | |
584 | else { | |
585 | ::boost::compute::vector<T, Alloc> tmp(position, end(), queue); | |
586 | resize(m_size + 1, queue); | |
587 | position = begin() + position.get_index(); | |
588 | ::boost::compute::copy_n(&value, 1, position, queue); | |
589 | ::boost::compute::copy(tmp.begin(), tmp.end(), position + 1, queue); | |
590 | } | |
591 | ||
592 | return position + 1; | |
593 | } | |
594 | ||
595 | iterator insert(iterator position, const T &value) | |
596 | { | |
597 | command_queue queue = default_queue(); | |
598 | iterator iter = insert(position, value, queue); | |
599 | queue.finish(); | |
600 | return iter; | |
601 | } | |
602 | ||
603 | void insert(iterator position, | |
604 | size_type count, | |
605 | const T &value, | |
606 | command_queue &queue) | |
607 | { | |
608 | ::boost::compute::vector<T, Alloc> tmp(position, end(), queue); | |
609 | resize(size() + count, queue); | |
610 | ||
611 | position = begin() + position.get_index(); | |
612 | ||
613 | ::boost::compute::fill_n(position, count, value, queue); | |
614 | ::boost::compute::copy( | |
615 | tmp.begin(), | |
616 | tmp.end(), | |
617 | position + static_cast<difference_type>(count), | |
618 | queue | |
619 | ); | |
620 | } | |
621 | ||
622 | void insert(iterator position, size_type count, const T &value) | |
623 | { | |
624 | command_queue queue = default_queue(); | |
625 | insert(position, count, value, queue); | |
626 | queue.finish(); | |
627 | } | |
628 | ||
629 | /// Inserts the values in the range [\p first, \p last) into the vector at | |
630 | /// \p position using \p queue. | |
631 | template<class InputIterator> | |
632 | void insert(iterator position, | |
633 | InputIterator first, | |
634 | InputIterator last, | |
635 | command_queue &queue) | |
636 | { | |
637 | ::boost::compute::vector<T, Alloc> tmp(position, end(), queue); | |
638 | ||
639 | size_type count = detail::iterator_range_size(first, last); | |
640 | resize(size() + count, queue); | |
641 | ||
642 | position = begin() + position.get_index(); | |
643 | ||
644 | ::boost::compute::copy(first, last, position, queue); | |
645 | ::boost::compute::copy( | |
646 | tmp.begin(), | |
647 | tmp.end(), | |
648 | position + static_cast<difference_type>(count), | |
649 | queue | |
650 | ); | |
651 | } | |
652 | ||
653 | /// \overload | |
654 | template<class InputIterator> | |
655 | void insert(iterator position, InputIterator first, InputIterator last) | |
656 | { | |
657 | command_queue queue = default_queue(); | |
658 | insert(position, first, last, queue); | |
659 | queue.finish(); | |
660 | } | |
661 | ||
662 | iterator erase(iterator position, command_queue &queue) | |
663 | { | |
664 | return erase(position, position + 1, queue); | |
665 | } | |
666 | ||
667 | iterator erase(iterator position) | |
668 | { | |
669 | command_queue queue = default_queue(); | |
670 | iterator iter = erase(position, queue); | |
671 | queue.finish(); | |
672 | return iter; | |
673 | } | |
674 | ||
675 | iterator erase(iterator first, iterator last, command_queue &queue) | |
676 | { | |
677 | if(last != end()){ | |
678 | ::boost::compute::vector<T, Alloc> tmp(last, end(), queue); | |
679 | ::boost::compute::copy(tmp.begin(), tmp.end(), first, queue); | |
680 | } | |
681 | ||
682 | difference_type count = std::distance(first, last); | |
683 | resize(size() - static_cast<size_type>(count), queue); | |
684 | ||
685 | return begin() + first.get_index() + count; | |
686 | } | |
687 | ||
688 | iterator erase(iterator first, iterator last) | |
689 | { | |
690 | command_queue queue = default_queue(); | |
691 | iterator iter = erase(first, last, queue); | |
692 | queue.finish(); | |
693 | return iter; | |
694 | } | |
695 | ||
696 | /// Swaps the contents of \c *this with \p other. | |
697 | void swap(vector &other) | |
698 | { | |
699 | std::swap(m_data, other.m_data); | |
700 | std::swap(m_size, other.m_size); | |
701 | std::swap(m_allocator, other.m_allocator); | |
702 | } | |
703 | ||
704 | /// Removes all elements from the vector. | |
705 | void clear() | |
706 | { | |
707 | m_size = 0; | |
708 | } | |
709 | ||
710 | allocator_type get_allocator() const | |
711 | { | |
712 | return m_allocator; | |
713 | } | |
714 | ||
715 | /// Returns the underlying buffer. | |
716 | const buffer& get_buffer() const | |
717 | { | |
718 | return m_data.get_buffer(); | |
719 | } | |
720 | ||
721 | /// \internal_ | |
722 | /// | |
723 | /// Returns a command queue usable to issue commands for the vector's | |
724 | /// memory buffer. This is used when a member function is called without | |
725 | /// specifying an existing command queue to use. | |
726 | command_queue default_queue() const | |
727 | { | |
728 | const context &context = m_allocator.get_context(); | |
729 | command_queue queue(context, context.get_device()); | |
730 | return queue; | |
731 | } | |
732 | ||
733 | private: | |
734 | /// \internal_ | |
735 | BOOST_CONSTEXPR size_type _minimum_capacity() const { return 4; } | |
736 | ||
737 | /// \internal_ | |
738 | BOOST_CONSTEXPR float _growth_factor() const { return 1.5; } | |
739 | ||
740 | private: | |
741 | pointer m_data; | |
742 | size_type m_size; | |
743 | allocator_type m_allocator; | |
744 | }; | |
745 | ||
746 | namespace detail { | |
747 | ||
748 | // set_kernel_arg specialization for vector<T> | |
749 | template<class T, class Alloc> | |
750 | struct set_kernel_arg<vector<T, Alloc> > | |
751 | { | |
752 | void operator()(kernel &kernel_, size_t index, const vector<T, Alloc> &vector) | |
753 | { | |
754 | kernel_.set_arg(index, vector.get_buffer()); | |
755 | } | |
756 | }; | |
757 | ||
758 | // for capturing vector<T> with BOOST_COMPUTE_CLOSURE() | |
759 | template<class T, class Alloc> | |
760 | struct capture_traits<vector<T, Alloc> > | |
761 | { | |
762 | static std::string type_name() | |
763 | { | |
764 | return std::string("__global ") + ::boost::compute::type_name<T>() + "*"; | |
765 | } | |
766 | }; | |
767 | ||
768 | // meta_kernel streaming operator for vector<T> | |
769 | template<class T, class Alloc> | |
770 | meta_kernel& operator<<(meta_kernel &k, const vector<T, Alloc> &vector) | |
771 | { | |
772 | return k << k.get_buffer_identifier<T>(vector.get_buffer()); | |
773 | } | |
774 | ||
775 | } // end detail namespace | |
776 | } // end compute namespace | |
777 | } // end boost namespace | |
778 | ||
779 | #endif // BOOST_COMPUTE_CONTAINER_VECTOR_HPP |