Bolt  1.3
C++ template library with support for OpenCL
device_vector.h
Go to the documentation of this file.
1 /***************************************************************************
2 * © 2012,2014 Advanced Micro Devices, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 
16 ***************************************************************************/
17 
23 #pragma once
24 #if !defined( BOLT_AMP_DEVICE_VECTOR_H )
25 #define BOLT_AMP_DEVICE_VECTOR_H
26 
27 #include <iterator>
28 #include <type_traits>
29 #include <numeric>
30 #include <amp.h>
31 #include <bolt/amp/control.h>
32 #include <exception> // For exception class
33 #include <boost/iterator/iterator_facade.hpp>
34 #include <boost/iterator/reverse_iterator.hpp>
35 #include <boost/shared_array.hpp>
36 
37 
40 namespace bolt
41 {
44 namespace amp
45 {
57  : public std::random_access_iterator_tag
58  { // identifying tag for random-access iterators
59  };
60 
61 
62 
63  template <typename T>
65  {
66  public:
67  // Create an AV on the CPU
68  static concurrency::array<T> getav() restrict(cpu)
69  {
70  static T type_default;
71  return concurrency::array<T>(1);
72  }
73  };
84 template< typename T, template < typename, int RANK = 1 > class CONT= concurrency::array_view >
86 {
87  typedef T* naked_pointer;
88  typedef const T* const_naked_pointer;
89 
90 public:
91  // Useful typedefs specific to this container
92  typedef T value_type;
93  typedef ptrdiff_t difference_type;
94  typedef difference_type distance_type;
95  typedef int size_type;
96 
97  // These typedefs help define the template template parameter that represents our AMP container
98  typedef concurrency::array_view< T > arrayview_type;
99  typedef concurrency::array< T > array_type;
100 
101  typedef CONT< T > container_type;
102 
103  typedef naked_pointer pointer;
104  typedef const_naked_pointer const_pointer;
105 
114  template< typename Container >
116  {
117  public:
118  reference_base( Container& rhs, size_type index ): m_Container( rhs, false ), m_Index( index )
119  {}
120 
121  // Automatic type conversion operator to turn the reference object into a value_type
122  operator value_type( ) const
123  {
124  arrayview_type av( m_Container.m_devMemory );
125  value_type &result = av[static_cast< int >( m_Index )];
126 
127  return result;
128  }
129 
130  reference_base< Container >& operator=( const value_type& rhs )
131  {
132  arrayview_type av( m_Container.m_devMemory );
133  av[static_cast< int >( m_Index )] = rhs;
134 
135  return *this;
136  }
137 
140  Container& getContainer( ) const
141  {
142  return m_Container;
143  }
144 
147  size_type getIndex() const
148  {
149  return m_Index;
150  }
151 
152  private:
153  Container m_Container;
154  size_type m_Index;
155  };
156 
161 
162  template< typename Container >
164  {
165  public:
166  const_reference_base( const Container& rhs, size_type index ): m_Container( rhs, false ), m_Index( index )
167  {}
168 
169  // Automatic type conversion operator to turn the reference object into a value_type
170  operator value_type( ) const
171  {
172  arrayview_type av( m_Container.m_devMemory );
173  value_type &result = av[static_cast< int >( m_Index )];
174 
175  return result;
176  }
177 
178  const_reference_base< const Container >& operator=( const value_type& rhs )
179  {
180  arrayview_type av( m_Container.m_devMemory );
181  av[static_cast< int >( m_Index )] = rhs;
182 
183  return *this;
184  }
185 
188  const Container& getContainer( ) const
189  {
190  return m_Container;
191  }
192 
195  size_type getIndex() const
196  {
197  return m_Index;
198  }
199 
200  private:
201  const Container m_Container;
202  size_type m_Index;
203  };
204 
211 
212  // Handy for the reference class to get at the wrapped ::cl objects
213  friend class reference;
214 
223  template< typename Container >
224  class iterator_base: public boost::iterator_facade< iterator_base< Container >,
225  value_type, device_vector_tag, typename device_vector::reference >
226  {
227  public:
228 
229  iterator_base( ): m_Container( create_empty_array< value_type >::getav( ) ), m_Index( 0 )
230  {}
231 
232  // Basic constructor requires a reference to the container and a positional element
233  iterator_base( Container& rhs, size_type index ): m_Container( rhs, false ), m_Index( static_cast<int>(index) )
234  {}
235 
236  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
237  template< typename OtherContainer >
239  m_Container( rhs.m_Container, false ), m_Index( rhs.m_Index )
240  {}
241  iterator_base( const iterator_base& rhs ):
242  m_Container( rhs.m_Container, false ), m_Index( rhs.m_Index )
243  {}
244  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
246  {
247  m_Container = rhs.m_Container;
248  m_Index = rhs.m_Index;
249  return *this;
250  }
251 
252  iterator_base< Container >& operator+= ( const difference_type & n )
253  {
254  advance( n );
255  return *this;
256  }
257 
258  const iterator_base< Container > operator+ ( const difference_type & n ) const
259  {
260  iterator_base< Container > result(*this);
261  result.advance(n);
262  return result;
263  }
264 
265  Container getContainer( ) const
266  {
267  return m_Container;
268  }
269 
270  size_type getIndex() const
271  {
272  return m_Index;
273  }
274 
275 
276  difference_type distance_to( const iterator_base< Container >& rhs ) const
277  {
278  return ( rhs.m_Index - m_Index );
279  }
280  int m_Index;
281 
282  // Implementation detail of boost.iterator
283  friend class boost::iterator_core_access;
284 
285  // Handy for the device_vector erase methods
286  friend class device_vector< value_type >;
287 
288  // Used for templatized copy constructor and the templatized equal operator
289  template < typename > friend class iterator_base;
290 
291  void advance( difference_type n )
292  {
293  m_Index += static_cast<int>(n);
294  }
295 
296  void increment( )
297  {
298  advance( 1 );
299  }
300 
301  void decrement( )
302  {
303  advance( -1 );
304  }
305 
306 
307  template< typename OtherContainer >
308  bool equal( const iterator_base< OtherContainer >& rhs ) const
309  {
310  bool sameIndex = rhs.m_Index == m_Index;
311  bool sameContainer = &m_Container.m_devMemory[m_Index] == &rhs.m_Container.m_devMemory[rhs.m_Index];
312  return ( sameIndex && sameContainer );
313  }
314 
315  value_type& operator[](int x) const restrict(cpu,amp)
316  {
317  return m_Container[m_Index + x];
318  }
319 
320  value_type& operator*() const restrict(cpu,amp)
321  {
322  return m_Container[m_Index];
323  }
324 
325 private:
326  Container m_Container;
327 
328  };
329 
330 
336  template< typename Container >
337  class reverse_iterator_base: public boost::iterator_facade< reverse_iterator_base< Container >,
338  value_type, std::random_access_iterator_tag, typename device_vector::reference >
339  {
340  public:
341 
342  reverse_iterator_base( ): m_Container( create_empty_array< value_type >::getav( ) ), m_Index( 0 )
343  {}
344 
345  // Basic constructor requires a reference to the container and a positional element
346  reverse_iterator_base( Container& lhs, int index ): m_Container( lhs, false ), m_Index( static_cast<int>(index-1) )
347  {}
348 
349  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
350  template< typename OtherContainer >
352  m_Container( lhs.m_Container, false ), m_Index( lhs.m_Index )
353  {}
354 
356  m_Container( lhs.m_Container, false ), m_Index( lhs.m_Index )
357  {}
358  // This copy constructor allows an iterator to convert into a const_iterator, but not vica versa
360  {
361  m_Container = lhs.m_Container;
362  m_Index = lhs.m_Index;
363  return *this;
364  }
365 
366  reverse_iterator_base< Container >& operator+= ( const difference_type & n )
367  {
368  advance( -n );
369  return *this;
370  }
371 
372  const reverse_iterator_base< Container > operator+ ( const difference_type & n ) const
373  {
375  result.advance(-n);
376  return result;
377  }
378 
379  int getIndex() const
380  {
381  return m_Index;
382  }
383 
384  Container& getContainer( ) const
385  {
386  return m_Container;
387  }
388 
389 
390  difference_type distance_to( const reverse_iterator_base< Container >& lhs ) const
391  {
392  return static_cast< difference_type >( m_Index - lhs.m_Index );
393  }
394 
395  int m_Index;
396 
397  // Implementation detail of boost.iterator
398  friend class boost::iterator_core_access;
399 
400  // Handy for the device_vector erase methods
401  friend class device_vector< value_type >;
402 
403  // Used for templatized copy constructor and the templatized equal operator
404  template < typename > friend class reverse_iterator_base;
405 
406  void advance( difference_type n )
407  {
408  m_Index += static_cast<int>(n);
409  }
410 
411  void increment( )
412  {
413  advance( -1 );
414  }
415 
416  void decrement( )
417  {
418  advance( 1 );
419  }
420 
421  template< typename OtherContainer >
422  bool equal( const reverse_iterator_base< OtherContainer >& lhs ) const
423  {
424  bool sameIndex = lhs.m_Index == m_Index;
425  bool sameContainer = &m_Container.m_devMemory[m_Index] == &lhs.m_Container.m_devMemory[lhs.m_Index];
426  return ( sameIndex && sameContainer );
427  }
428 
429  value_type& operator[](int x) const restrict(cpu,amp)
430  {
431  return m_Container[m_Index - x];
432  }
433 
434  value_type& operator*() const restrict(cpu,amp)
435  {
436  return m_Container[m_Index];
437  }
438 
439  private:
440  Container m_Container;
441 
442  };
443 
444 
448 
452 
456 
460 
461 
468  : m_Size( static_cast<int>(0) ), m_devMemory( create_empty_array<value_type>::getav() )
469  {
470 
471  }
472 
481  device_vector( size_type newSize, const value_type& initValue = value_type( ), bool init = true,
482  control& ctl = control::getDefault( ) )
483  : m_Size( static_cast<int>(newSize) ), m_devMemory( create_empty_array<value_type>::getav() )
484  {
485  if( m_Size > 0 )
486  {
487  concurrency::array<value_type> tmp = array_type( static_cast< int >( m_Size ), ctl.getAccelerator().default_view );
488  m_devMemory = tmp.view_as(tmp.get_extent());
489  if( init )
490  {
491  arrayview_type m_devMemoryAV( m_devMemory );
492  Concurrency::parallel_for_each( m_devMemoryAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
493  {
494  m_devMemoryAV[idx] = initValue;
495  }
496  );
497  }
498  }
499  }
500 
508  template< typename InputIterator >
509  device_vector( const InputIterator begin, size_type newSize, bool discard = false, control& ctl = control::getDefault( ),
510  typename std::enable_if< !std::is_integral< InputIterator >::value &&
511  std::is_same< arrayview_type, container_type >::value>::type* = 0 )
512  : m_Size( static_cast<int>(newSize) ), m_devMemory( create_empty_array<value_type>::getav() )
513  {
514  if( m_Size > 0 )
515  {
516  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
517  concurrency::array_view<value_type> tmp = arrayview_type( ext, reinterpret_cast< value_type* >(&begin[ 0 ]) );
518  m_devMemory = tmp;
519  }
520  if(discard)
521  m_devMemory.discard_data();
522  };
523 
524 
532  template< typename InputIterator >
533  device_vector( const InputIterator begin, size_type newSize, bool discard = false, control& ctl = control::getDefault( ),
534  typename std::enable_if< !std::is_integral< InputIterator >::value &&
535  std::is_same< array_type, container_type >::value>::type* = 0 )
536  : m_Size( static_cast<int>(newSize) ), m_devMemory( create_empty_array<value_type>::getav() )
537  {
538  if( m_Size > 0 )
539  {
540  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
541  concurrency::array<value_type> tmp = array_type( ext, reinterpret_cast< value_type* >(&begin[ 0 ]) );
542  m_devMemory = tmp.view_as(tmp.get_extent());
543  }
544  };
545 
546 
552  template< typename T >
553  device_vector( const device_vector<T, CONT> &cont, bool copy = true,control& ctl = control::getDefault( ) ): m_Size( cont.size( ) ),
554  m_devMemory( cont.m_devMemory.view_as(cont.m_devMemory.get_extent()))
555  {
556  if(!copy)
557  return;
558  if( m_Size > 0 )
559  {
560  concurrency::array<value_type> tmp = array_type( m_devMemory );
561  m_devMemory = tmp.view_as(tmp.get_extent());
562  }
563  };
564 
568  device_vector( arrayview_type &cont): m_Size(cont.get_extent().size()), m_devMemory(cont)
569  {
570  };
571 
572 
576  device_vector( array_type &cont): m_Size(cont.get_extent().size()), m_devMemory( cont.view_as(cont.get_extent()))
577  {
578  };
579 
587  template< typename InputIterator >
588  device_vector( const InputIterator begin, const InputIterator end, bool discard = false, control& ctl = control::getDefault( ),
589  typename std::enable_if< std::is_same< arrayview_type, container_type >::value &&
590  !std::is_integral< InputIterator >::value>::type* = 0 )
591  : m_devMemory( create_empty_array<value_type>::getav() )
592  {
593  m_Size = static_cast<int>(std::distance( begin, end ));
594 
595  if( m_Size > 0 )
596  {
597  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
598  concurrency::array_view<value_type> tmp = arrayview_type( ext, reinterpret_cast< value_type* >(&begin[ 0 ]) );
599  m_devMemory = tmp;
600  }
601  if(discard)
602  m_devMemory.discard_data();
603 
604  };
605 
606 
614  template< typename InputIterator >
615  device_vector( const InputIterator begin, const InputIterator end, bool discard = false, control& ctl = control::getDefault( ),
616  typename std::enable_if< std::is_same< array_type, container_type >::value &&
617  !std::is_integral< InputIterator >::value>::type* = 0 )
618  : m_devMemory( create_empty_array<value_type>::getav() )
619  {
620  m_Size = static_cast<int>(std::distance( begin, end ));
621 
622  if( m_Size > 0 )
623  {
624  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
625  concurrency::array<value_type> tmp = array_type( ext, reinterpret_cast< value_type* >(&begin[ 0 ]) );
626  m_devMemory = tmp.view_as(tmp.get_extent());
627  }
628  };
629 
630 
631  //destructor for device_vector
632  ~device_vector()
633  {
634  }
635 
636  // Member functions
637 
645  arrayview_type getBuffer( ) const
646  {
647  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
648  return m_devMemory.view_as( ext );
649  }
650 
660  arrayview_type getBuffer( const_iterator itr, unsigned int size ) const
661  {
662  if(size == static_cast<unsigned int>(m_Size))
663  {
664  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
665  return m_devMemory.view_as( ext );
666  }
667  else
668  {
669  size_type offset = itr.getIndex();
670  concurrency::extent<1> ext( static_cast< int >( size ) );
671  return m_devMemory.section( Concurrency::index<1>(offset), ext );
672  }
673  }
674 
675 
676  arrayview_type getBuffer( const_reverse_iterator itr, unsigned int size ) const
677  {
678  if(size == static_cast<unsigned int>(m_Size))
679  {
680  concurrency::extent<1> ext( static_cast< int >( m_Size ) );
681  return m_devMemory.view_as( ext );
682  }
683  else
684  {
685  size_type offset = itr.getIndex();
686  concurrency::extent<1> ext( static_cast< int >( size ) );
687  return m_devMemory.section( Concurrency::index<1>(offset), ext );
688  }
689  }
690 
703  void resize( size_type reqSize, const value_type& val = value_type( ) )
704  {
705  size_type cap = capacity( );
706 
707  if( reqSize == cap )
708  return;
709 
710  //TODO - Add if statement for max size allowed in array class
711  array_type l_tmpArray = array_type(reqSize);
712  arrayview_type l_tmpBuffer = arrayview_type(l_tmpArray);
713  if( m_Size > 0 )
714  {
715  //1622 Arrays are logically considered to be value types in that when an array is copied to another array,
716  //a deep copy is performed. Two arrays never point to the same data.
717  //m_Size data elements are copied
718 
719  if( reqSize > m_Size )
720  {
721  m_devMemory.copy_to(l_tmpBuffer.section( 0, m_devMemory.get_extent().size() ) );
722  arrayview_type l_tmpBufferSectionAV =
723  l_tmpBuffer.section(m_Size, (reqSize - m_Size));
724  concurrency::parallel_for_each(l_tmpBufferSectionAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
725  {
726  l_tmpBufferSectionAV[idx] = val;
727  });
728  }
729  else
730  {
731  arrayview_type l_devMemoryAV = m_devMemory.section(0, reqSize);
732  l_devMemoryAV.copy_to(l_tmpBuffer);
733  }
734  }
735  else
736  {
737  arrayview_type l_tmpBufferAV(l_tmpBuffer);
738  Concurrency::parallel_for_each(l_tmpBufferAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
739  {
740  l_tmpBufferAV[idx] = val;
741  });
742  }
743  // Remember the new size
744  m_Size = reqSize;
745  m_devMemory = l_tmpBuffer;
746  }
747 
752  size_type size( void ) const
753  {
754  return m_Size;
755  }
756 
757 
758 
771  void reserve( size_type reqSize )
772  {
773  if( reqSize <= capacity( ) )
774  return;
775 
776  concurrency::array<value_type> tmp = array_type( static_cast< int >( reqSize ) );
777  arrayview_type l_tmpBuffer = arrayview_type( tmp );
778  if( m_Size > 0 )
779  {
780  if( capacity() != 0 )
781  {
782  arrayview_type l_tmpBuffer = arrayview_type( tmp );
783  m_devMemory.copy_to(l_tmpBuffer.section(0, m_devMemory.get_extent().size()));
784  }
785  }
786  m_devMemory = l_tmpBuffer;
787 
788  }
789 
795  size_type capacity( void ) const
796  {
797  Concurrency::extent<1> ext = m_devMemory.get_extent();
798  return ext.size();
799  }
800 
807  {
808  if( m_Size == capacity( ) )
809  return;
810 
811  array_type l_tmpArray = array_type( static_cast< int >( size( ) ) );
812  arrayview_type l_tmpBuffer = arrayview_type(l_tmpArray);
813  arrayview_type l_devMemoryAV = m_devMemory.section( 0,(int)size() );
814  arrayview_type l_tmpBufferAV = l_tmpBuffer.section( 0,(int)size() );
815 
816  l_devMemoryAV.copy_to( l_tmpBufferAV );
817  m_devMemory = l_tmpBuffer;
818  }
819 
823  value_type& operator[]( size_type n ) restrict(cpu,amp)
824  {
825  return m_devMemory[n];
826  }
827 
831  value_type& operator[]( size_type ix ) const restrict(cpu,amp)
832  {
833  return m_devMemory[ix];
834  }
835 
839  iterator begin( void )
840  {
841  return iterator( *this, 0 );
842  }
843 
848  const_iterator begin( void ) const
849  {
850  return const_iterator( *this, 0 );
851  }
852 
858  const_iterator cbegin( void ) const
859  {
860  return const_iterator( *this, 0 );
861  }
862 
868  {
869  return reverse_iterator(*this,m_Size);
870  }
871 
878  {
879  return const_reverse_iterator(*this,m_Size);
880  }
881 
889  {
890  return const_reverse_iterator(*this,m_Size);
891  }
892 
896  iterator end( void )
897  {
898  return iterator( *this, m_Size );
899  }
900 
905  const_iterator end( void ) const
906  {
907  return const_iterator( *this, m_Size );
908  }
909 
915  const_iterator cend( void ) const
916  {
917  return const_iterator( *this, m_Size );
918  }
919 
925  {
926  return reverse_iterator( *this, 0 );
927  }
928 
935  {
936  return const_reverse_iterator( *this, 0 );
937  }
938 
946  {
947  return const_reverse_iterator( *this, 0 );
948  }
949 
953  value_type& front( void )
954  {
955  return (*begin());
956  }
957 
961  const value_type& front( void ) const
962  {
963  return (*begin());
964  }
965 
969  value_type& back( void )
970  {
971  return (*(end() - 1));
972  }
973 
977  const value_type& back( void ) const
978  {
979  return ( *(end() - 1) );
980  }
981 
982  //Yes you need the shared_array object.
983  //Ask kent for a better solution.
984  pointer data( void )
985  {
987  // below av.data(). It should anyway be freed in the UnMapBufferFunctor Functor
988  if(0 == size())
989  {
990 
991  return NULL;
992  }
993  synchronize( *this );
994  arrayview_type av( m_devMemory );
995  return av.data( );
996  }
997 
998  const_pointer data( void ) const
999  {
1000  if(0 == size())
1001  {
1002  return NULL;
1003  }
1004  synchronize( *this );
1005  arrayview_type av( m_devMemory );
1006  return av.data( );
1007  }
1008 
1012  void clear( void )
1013  {
1014  m_devMemory = create_empty_array<value_type>::getav();
1015  m_Size = 0;
1016  }
1017 
1021  bool empty( void ) const
1022  {
1023  return m_Size ? false: true;
1024  }
1025 
1029  void push_back( const value_type& value )
1030  {
1031  if( m_Size > capacity( ) )
1032  throw std::exception( "device_vector size can not be greater than capacity( )" );
1033 
1034  // Need to grow the vector to push new value.
1035  // Vectors double their capacity on push_back if the array is not big enough.
1036  if( m_Size == capacity( ) )
1037  {
1038  m_Size ? reserve( m_Size * 2 ) : reserve( 1 );
1039  }
1040 
1041  arrayview_type av( m_devMemory );
1042  //insert(end(),value);
1043  av[static_cast<int>( m_Size )] = value;
1044  ++m_Size;
1045  }
1046 
1049  void pop_back( void )
1050  {
1051  if( m_Size > 0 )
1052  {
1053  --m_Size;
1054  }
1055  }
1056 
1060  void swap( device_vector& vec )
1061  {
1062  if( this == &vec )
1063  return;
1064 
1065  arrayview_type swapBuffer( m_devMemory );
1066  m_devMemory = vec.m_devMemory;
1067  vec.m_devMemory = swapBuffer;
1068 
1069  size_type sizeTmp = m_Size;
1070  m_Size = vec.m_Size;
1071  vec.m_Size = static_cast<int>(sizeTmp);
1072  }
1073 
1079  {
1080  iterator l_End = end( );
1081  if( index.m_Index >= l_End.m_Index )
1082  throw std::exception( "Iterator is pointing past the end of this container" );
1083 
1084  size_type sizeRegion = l_End.m_Index - index.m_Index;
1085 
1086  arrayview_type av( m_devMemory );
1087  naked_pointer ptrBuff = av.data();
1088  naked_pointer ptrBuffTemp = ptrBuff + index.m_Index;
1089  ::memmove( ptrBuffTemp, ptrBuffTemp + 1, (sizeRegion - 1)*sizeof( value_type ) );
1090 
1091  --m_Size;
1092 
1093  size_type newIndex = (m_Size < index.m_Index) ? m_Size : index.m_Index;
1094  return iterator( *this, newIndex );
1095  }
1096 
1103  {
1104  if( last.m_Index > m_Size )
1105  throw std::exception( "Iterator is pointing past the end of this container" );
1106 
1107  if( (first == begin( )) && (last == end( )) )
1108  {
1109  clear( );
1110  return iterator( *this, m_Size );
1111  }
1112 
1113  iterator l_End = end( );
1114  size_type sizeMap = l_End.m_Index - first.m_Index;
1115 
1116  arrayview_type av( m_devMemory );
1117  naked_pointer ptrBuff = av.data();
1118  ptrBuff = ptrBuff + first.m_Index;
1119  size_type sizeErase = last.m_Index - first.m_Index;
1120  ::memmove( ptrBuff, ptrBuff + sizeErase, (sizeMap - sizeErase)*sizeof( value_type ) );
1121 
1122  m_Size -= static_cast<int>(sizeErase);
1123 
1124  size_type newIndex = (m_Size < last.m_Index) ? m_Size : last.m_Index;
1125  return iterator( *this, newIndex );
1126  }
1127 
1135  iterator insert( const_iterator index, const value_type& value )
1136  {
1137  if( index.m_Index > m_Size )
1138  throw std::exception( "Iterator is pointing past the end of this container" );
1139 
1140  if( index.m_Index == m_Size )
1141  {
1142  push_back( value );
1143  return iterator( *this, index.m_Index );
1144  }
1145 
1146  // Need to grow the vector to insert a new value.
1147  // TODO: What is an appropriate growth strategy for GPU memory allocation? Exponential growth does not seem
1148  // right at first blush.
1149  if( m_Size == capacity( ) )
1150  {
1151  m_Size ? reserve( m_Size * 2 ) : reserve( 1 );
1152  }
1153 
1154  size_type sizeMap = (m_Size - index.m_Index) + 1;
1155 
1156  arrayview_type av( m_devMemory );
1157  naked_pointer ptrBuff = av.data();
1158  ptrBuff = ptrBuff + index.m_Index;
1159 
1160  // Shuffle the old values 1 element down
1161  ::memmove( ptrBuff + 1, ptrBuff, (sizeMap - 1)*sizeof( value_type ) );
1162 
1163  // Write the new value in its place
1164  *ptrBuff = value;
1165 
1166  ++m_Size;
1167 
1168  return iterator( *this, index.m_Index );
1169  }
1170 
1178  void insert( const_iterator index, size_type n, const value_type& value )
1179  {
1180  if( index.m_Index > m_Size )
1181  throw std::exception( "Iterator is pointing past the end of this container" );
1182 
1183  // Need to grow the vector to insert n new values
1184  if( ( m_Size + n ) > capacity( ) )
1185  {
1186  reserve( m_Size + n );
1187  }
1188 
1189  size_type sizeMap = (m_Size - index.m_Index) + n;
1190 
1191  arrayview_type av( m_devMemory );
1192  naked_pointer ptrBuff = av.data( );
1193  ptrBuff = ptrBuff + index.m_Index;
1194 
1195  // Shuffle the old values n element down.
1196  ::memmove( ptrBuff + n, ptrBuff, (sizeMap - n)*sizeof( value_type ) );
1197 
1198  // Copy the new value n times in the buffer.
1199  for( size_type i = 0; i < n; ++i )
1200  {
1201  ptrBuff[ i ] = value;
1202  }
1203 
1204  m_Size += n;
1205  }
1206 
1207  template< typename InputIterator >
1208  void insert( const_iterator index, InputIterator begin, InputIterator end )
1209  {
1210  if( index.m_Index > m_Size )
1211  throw std::exception( "Iterator is pointing past the end of this container" );
1212 
1213  // Need to grow the vector to insert the range of new values
1214  size_type n = static_cast<int>(std::distance( begin, end ));
1215  if( ( m_Size + n ) > capacity( ) )
1216  {
1217  reserve( m_Size + n );
1218  }
1219  size_type sizeMap = (m_Size - index.m_Index) + n;
1220 
1221  arrayview_type av( m_devMemory );
1222  naked_pointer ptrBuff = av.data() + index.m_Index;
1223 
1224  // Shuffle the old values n element down.
1225  ::memmove( ptrBuff + n, ptrBuff, (sizeMap - n)*sizeof( value_type ) );
1226 
1227 #if( _WIN32 )
1228  std::copy( begin, end, stdext::checked_array_iterator< naked_pointer >( ptrBuff, n ) );
1229 #else
1230  std::copy( begin, end, ptrBuff );
1231 #endif
1232 
1233  m_Size += static_cast<int>(n);
1234  }
1235 
1241  void assign( size_type newSize, const value_type& value )
1242  {
1243  if( newSize > m_Size )
1244  {
1245  reserve( newSize );
1246  }
1247  m_Size = newSize;
1248 
1249  arrayview_type m_devMemoryAV( m_devMemory );
1250  Concurrency::parallel_for_each( m_devMemoryAV.extent, [=](Concurrency::index<1> idx) restrict(amp)
1251  {
1252  m_devMemoryAV[idx] = value;
1253  }
1254  );
1255  }
1256 #if 1
1257 
1262  template<typename InputIterator>
1263  typename std::enable_if< std::_Is_iterator<InputIterator>::value, void>::type
1264  assign( InputIterator begin, InputIterator end )
1265  {
1266  size_type l_Count = static_cast<int>(std::distance( begin, end ));
1267 
1268  if( l_Count > m_Size )
1269  {
1270  reserve( l_Count );
1271  }
1272  m_Size = static_cast<int>(l_Count);
1273 
1274  arrayview_type m_devMemoryAV( m_devMemory );
1275  naked_pointer ptrBuff = m_devMemoryAV.data();
1276 #if( _WIN32 )
1277  std::copy( begin, end, stdext::checked_array_iterator< naked_pointer >( ptrBuff, m_Size ) );
1278 #else
1279  std::copy( begin, end, ptrBuff );
1280 #endif
1281  }
1282 #endif
1283 private:
1284 
1285  // These private routines make sure that the data that resides in the concurrency::array* object are
1286  // reflected back in the host memory. However, the complication is that the concurrency::array object
1287  // does not expose a synchronize method, whereas the concurrency::array_view does. These routines
1288  // differentiate between the two different containers
1289  void synchronize( device_vector< T, concurrency::array >& rhs )
1290  {
1291  };
1292  void synchronize( device_vector< T, concurrency::array_view >& rhs )
1293  {
1294  rhs.m_devMemory.synchronize( );
1295  };
1296 
1297  int m_Size;
1298  concurrency::array_view<T, 1> m_devMemory;
1299 };
1300 
1301 }
1302 }
1303 
1304 #endif